no message

This commit is contained in:
gem
2025-02-18 15:21:31 +08:00
commit 2d133e56d7
1980 changed files with 465595 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
/******************************************************************************
* 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-creator-support/AttachmentVertices.h"
using namespace cc; // NOLINT(google-build-using-namespace)
namespace spine {
AttachmentVertices::AttachmentVertices(middleware::Texture2D *texture, int verticesCount, uint16_t *triangles, int trianglesCount) {
_texture = texture;
if (_texture) _texture->addRef();
_triangles = new middleware::Triangles();
_triangles->verts = new middleware::V3F_T2F_C4B[verticesCount];
_triangles->vertCount = verticesCount;
_triangles->indices = triangles;
_triangles->indexCount = trianglesCount;
}
AttachmentVertices::~AttachmentVertices() {
delete[] _triangles->verts;
delete _triangles;
if (_texture) _texture->release();
}
AttachmentVertices *AttachmentVertices::copy() {
AttachmentVertices *atv = new AttachmentVertices(nullptr, _triangles->vertCount, _triangles->indices, _triangles->indexCount);
return atv;
}
} // namespace spine

View File

@@ -0,0 +1,48 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma once
#include "base/Macros.h"
#include "middleware-adapter.h"
namespace spine {
/**
* Store attachment vertex and indice list
*/
class AttachmentVertices {
public:
AttachmentVertices(cc::middleware::Texture2D *texture, int verticesCount, uint16_t *triangles, int trianglesCount);
virtual ~AttachmentVertices();
AttachmentVertices *copy();
cc::middleware::Texture2D *_texture = nullptr;
cc::middleware::Triangles *_triangles = nullptr;
};
} // namespace spine

View File

@@ -0,0 +1,323 @@
/******************************************************************************
* 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-creator-support/SkeletonAnimation.h"
#include <algorithm>
#include "base/DeferredReleasePool.h"
#include "base/Log.h"
#include "spine-creator-support/spine-cocos2dx.h"
#include "spine/Extension.h"
namespace spine {
struct TrackEntryListeners {
StartListener startListener;
InterruptListener interruptListener;
EndListener endListener;
DisposeListener disposeListener;
CompleteListener completeListener;
EventListener eventListener;
};
void animationCallback(AnimationState *state, EventType type, TrackEntry *entry, Event *event) {
(static_cast<SkeletonAnimation *>(state->getRendererObject()))->onAnimationStateEvent(entry, type, event);
}
void trackEntryCallback(AnimationState *state, EventType type, TrackEntry *entry, Event *event) {
(static_cast<SkeletonAnimation *>(state->getRendererObject()))->onTrackEntryEvent(entry, type, event);
if (type == EventType_Dispose) {
if (entry->getRendererObject()) {
delete static_cast<spine::TrackEntryListeners *>(entry->getRendererObject());
entry->setRendererObject(nullptr);
}
}
}
static TrackEntryListeners *getListeners(TrackEntry *entry) {
if (!entry->getRendererObject()) {
entry->setRendererObject(new spine::TrackEntryListeners());
entry->setListener(trackEntryCallback);
}
return static_cast<TrackEntryListeners *>(entry->getRendererObject());
}
float SkeletonAnimation::GlobalTimeScale = 1.0F;
void SkeletonAnimation::setGlobalTimeScale(float timeScale) {
GlobalTimeScale = timeScale;
}
SkeletonAnimation *SkeletonAnimation::create() {
auto *skeleton = new SkeletonAnimation();
return skeleton;
}
SkeletonAnimation *SkeletonAnimation::createWithData(SkeletonData *skeletonData, bool ownsSkeletonData) {
auto *node = new SkeletonAnimation();
node->initWithData(skeletonData, ownsSkeletonData);
return node;
}
SkeletonAnimation *SkeletonAnimation::createWithJsonFile(const std::string &skeletonJsonFile, const std::string &atlasFile, float scale) {
auto *node = new SkeletonAnimation();
node->initWithJsonFile(skeletonJsonFile, atlasFile, scale);
return node;
}
SkeletonAnimation *SkeletonAnimation::createWithBinaryFile(const std::string &skeletonBinaryFile, const std::string &atlasFile, float scale) {
auto *node = new SkeletonAnimation();
node->initWithBinaryFile(skeletonBinaryFile, atlasFile, scale);
return node;
}
void SkeletonAnimation::initialize() {
super::initialize();
_ownsAnimationStateData = true;
_state = new (__FILE__, __LINE__) AnimationState(new (__FILE__, __LINE__) AnimationStateData(_skeleton->getData()));
_state->setRendererObject(this);
_state->setListener(animationCallback);
}
SkeletonAnimation::SkeletonAnimation() = default;
SkeletonAnimation::~SkeletonAnimation() {
_startListener = nullptr;
_interruptListener = nullptr;
_endListener = nullptr;
_disposeListener = nullptr;
_completeListener = nullptr;
_eventListener = nullptr;
if (_state) {
if (_ownsAnimationStateData) delete _state->getData();
delete _state;
}
}
void SkeletonAnimation::update(float deltaTime) {
if (!_skeleton) return;
if (!_paused) {
deltaTime *= _timeScale * GlobalTimeScale;
if (_ownsSkeleton) _skeleton->update(deltaTime);
_state->update(deltaTime);
_state->apply(*_skeleton);
_skeleton->updateWorldTransform();
}
}
void SkeletonAnimation::setAnimationStateData(AnimationStateData *stateData) {
CC_ASSERT(stateData);
if (_state) {
if (_ownsAnimationStateData) delete _state->getData();
delete _state;
}
_ownsAnimationStateData = false;
_state = new (__FILE__, __LINE__) AnimationState(stateData);
_state->setRendererObject(this);
_state->setListener(animationCallback);
}
void SkeletonAnimation::setMix(const std::string &fromAnimation, const std::string &toAnimation, float duration) {
if (_state) {
_state->getData()->setMix(fromAnimation.c_str(), toAnimation.c_str(), duration);
}
}
TrackEntry *SkeletonAnimation::setAnimation(int trackIndex, const std::string &name, bool loop) {
if (!_skeleton) return nullptr;
Animation *animation = _skeleton->getData()->findAnimation(name.c_str());
if (!animation) {
CC_LOG_WARNING("Spine: Animation not found: %s", name.c_str());
return nullptr;
}
auto *trackEntry = _state->setAnimation(trackIndex, animation, loop);
_state->apply(*_skeleton);
return trackEntry;
}
TrackEntry *SkeletonAnimation::addAnimation(int trackIndex, const std::string &name, bool loop, float delay) {
if (!_skeleton) return nullptr;
Animation *animation = _skeleton->getData()->findAnimation(name.c_str());
if (!animation) {
CC_LOG_WARNING("Spine: Animation not found: %s", name.c_str());
return nullptr;
}
return _state->addAnimation(trackIndex, animation, loop, delay);
}
TrackEntry *SkeletonAnimation::setEmptyAnimation(int trackIndex, float mixDuration) {
if (_state) {
return _state->setEmptyAnimation(trackIndex, mixDuration);
}
return nullptr;
}
void SkeletonAnimation::setEmptyAnimations(float mixDuration) {
if (_state) {
_state->setEmptyAnimations(mixDuration);
}
}
TrackEntry *SkeletonAnimation::addEmptyAnimation(int trackIndex, float mixDuration, float delay) {
if (_state) {
return _state->addEmptyAnimation(trackIndex, mixDuration, delay);
}
return nullptr;
}
Animation *SkeletonAnimation::findAnimation(const std::string &name) const {
if (_skeleton) {
return _skeleton->getData()->findAnimation(name.c_str());
}
return nullptr;
}
TrackEntry *SkeletonAnimation::getCurrent(int trackIndex) {
if (_state) {
return _state->getCurrent(trackIndex);
}
return nullptr;
}
void SkeletonAnimation::clearTracks() {
if (_state) {
_state->clearTracks();
super::setToSetupPose();
}
}
void SkeletonAnimation::clearTrack(int trackIndex) {
if (_state) {
_state->clearTrack(trackIndex);
}
}
void SkeletonAnimation::onAnimationStateEvent(TrackEntry *entry, EventType type, Event *event) {
switch (type) {
case EventType_Start:
if (_startListener) _startListener(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_Complete:
if (_completeListener) _completeListener(entry);
break;
case EventType_Event:
if (_eventListener) _eventListener(entry, event);
break;
}
}
void SkeletonAnimation::onTrackEntryEvent(TrackEntry *entry, EventType type, Event *event) {
if (!entry->getRendererObject()) return;
auto *listeners = static_cast<TrackEntryListeners *>(entry->getRendererObject());
switch (type) {
case EventType_Start:
if (listeners->startListener) listeners->startListener(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_Complete:
if (listeners->completeListener) listeners->completeListener(entry);
break;
case EventType_Event:
if (listeners->eventListener) listeners->eventListener(entry, event);
break;
}
}
void SkeletonAnimation::setStartListener(const StartListener &listener) {
_startListener = listener;
}
void SkeletonAnimation::setInterruptListener(const InterruptListener &listener) {
_interruptListener = listener;
}
void SkeletonAnimation::setEndListener(const EndListener &listener) {
_endListener = listener;
}
void SkeletonAnimation::setDisposeListener(const DisposeListener &listener) {
_disposeListener = listener;
}
void SkeletonAnimation::setCompleteListener(const CompleteListener &listener) {
_completeListener = listener;
}
void SkeletonAnimation::setEventListener(const EventListener &listener) {
_eventListener = listener;
}
void SkeletonAnimation::setTrackStartListener(TrackEntry *entry, const StartListener &listener) { // NOLINT(readability-convert-member-functions-to-static)
getListeners(entry)->startListener = listener;
}
void SkeletonAnimation::setTrackInterruptListener(TrackEntry *entry, const InterruptListener &listener) { // NOLINT(readability-convert-member-functions-to-static)
getListeners(entry)->interruptListener = listener;
}
void SkeletonAnimation::setTrackEndListener(TrackEntry *entry, const EndListener &listener) { // NOLINT(readability-convert-member-functions-to-static)
getListeners(entry)->endListener = listener;
}
void SkeletonAnimation::setTrackDisposeListener(TrackEntry *entry, const DisposeListener &listener) { // NOLINT(readability-convert-member-functions-to-static)
getListeners(entry)->disposeListener = listener;
}
void SkeletonAnimation::setTrackCompleteListener(TrackEntry *entry, const CompleteListener &listener) { // NOLINT(readability-convert-member-functions-to-static)
getListeners(entry)->completeListener = listener;
}
void SkeletonAnimation::setTrackEventListener(TrackEntry *entry, const EventListener &listener) { // NOLINT(readability-convert-member-functions-to-static)
getListeners(entry)->eventListener = listener;
}
AnimationState *SkeletonAnimation::getState() const {
return _state;
}
} // namespace spine

View File

@@ -0,0 +1,108 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2019, 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.
*
* 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.
*****************************************************************************/
#pragma once
#include "spine-creator-support/SkeletonRenderer.h"
#include "spine/spine.h"
namespace spine {
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;
/** Draws an animated skeleton, providing an AnimationState for applying one or more animations and queuing animations to be
* played later. */
class SkeletonAnimation : public SkeletonRenderer {
public:
static SkeletonAnimation *create();
static SkeletonAnimation *createWithData(SkeletonData *skeletonData, bool ownsSkeletonData = false);
static SkeletonAnimation *createWithJsonFile(const std::string &skeletonJsonFile, const std::string &atlasFile, float scale = 1);
static SkeletonAnimation *createWithBinaryFile(const std::string &skeletonBinaryFile, const std::string &atlasFile, float scale = 1);
static void setGlobalTimeScale(float timeScale);
virtual void update(float deltaTime) override;
void setAnimationStateData(AnimationStateData *stateData);
void setMix(const std::string &fromAnimation, const std::string &toAnimation, float duration);
TrackEntry *setAnimation(int trackIndex, const std::string &name, bool loop);
TrackEntry *addAnimation(int trackIndex, const std::string &name, bool loop, float delay = 0);
TrackEntry *setEmptyAnimation(int trackIndex, float mixDuration);
void setEmptyAnimations(float mixDuration);
TrackEntry *addEmptyAnimation(int trackIndex, float mixDuration, float delay = 0);
Animation *findAnimation(const std::string &name) const;
TrackEntry *getCurrent(int trackIndex = 0);
void clearTracks();
void clearTrack(int trackIndex = 0);
void setStartListener(const StartListener &listener);
void setInterruptListener(const InterruptListener &listener);
void setEndListener(const EndListener &listener);
void setDisposeListener(const DisposeListener &listener);
void setCompleteListener(const CompleteListener &listener);
void setEventListener(const EventListener &listener);
void setTrackStartListener(TrackEntry *entry, const StartListener &listener);
void setTrackInterruptListener(TrackEntry *entry, const InterruptListener &listener);
void setTrackEndListener(TrackEntry *entry, const EndListener &listener);
void setTrackDisposeListener(TrackEntry *entry, const DisposeListener &listener);
void setTrackCompleteListener(TrackEntry *entry, const CompleteListener &listener);
void setTrackEventListener(TrackEntry *entry, const EventListener &listener);
virtual void onAnimationStateEvent(TrackEntry *entry, EventType type, Event *event);
virtual void onTrackEntryEvent(TrackEntry *entry, EventType type, Event *event);
AnimationState *getState() const;
SkeletonAnimation();
virtual ~SkeletonAnimation();
virtual void initialize() override;
public:
static float GlobalTimeScale;
protected:
AnimationState *_state = nullptr;
bool _ownsAnimationStateData = false;
StartListener _startListener = nullptr;
InterruptListener _interruptListener = nullptr;
EndListener _endListener = nullptr;
DisposeListener _disposeListener = nullptr;
CompleteListener _completeListener = nullptr;
EventListener _eventListener = nullptr;
private:
typedef SkeletonRenderer super;
};
} // namespace spine

View File

@@ -0,0 +1,546 @@
/******************************************************************************
* 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 "SkeletonCache.h"
#include "base/memory/Memory.h"
#include "spine-creator-support/AttachmentVertices.h"
USING_NS_MW; // NOLINT(google-build-using-namespace)
using namespace cc; // NOLINT(google-build-using-namespace)
namespace spine {
float SkeletonCache::FrameTime = 1.0F / 60.0F;
float SkeletonCache::MaxCacheTime = 120.0F;
SkeletonCache::SegmentData::SegmentData() = default;
SkeletonCache::SegmentData::~SegmentData() {
CC_SAFE_RELEASE_NULL(_texture);
}
void SkeletonCache::SegmentData::setTexture(cc::middleware::Texture2D *value) {
CC_SAFE_ADD_REF(value);
CC_SAFE_RELEASE(_texture);
_texture = value;
}
cc::middleware::Texture2D *SkeletonCache::SegmentData::getTexture() const {
return _texture;
}
SkeletonCache::FrameData::FrameData() = default;
SkeletonCache::FrameData::~FrameData() {
for (auto &bone : _bones) {
delete bone;
}
_bones.clear();
for (auto &color : _colors) {
delete color;
}
_colors.clear();
for (auto &segment : _segments) {
delete segment;
}
_segments.clear();
}
SkeletonCache::BoneData *SkeletonCache::FrameData::buildBoneData(std::size_t index) {
if (index > _bones.size()) return nullptr;
if (index == _bones.size()) {
auto *boneData = new BoneData;
_bones.push_back(boneData);
}
return _bones[index];
}
std::size_t SkeletonCache::FrameData::getBoneCount() const {
return _bones.size();
}
SkeletonCache::ColorData *SkeletonCache::FrameData::buildColorData(std::size_t index) {
if (index > _colors.size()) return nullptr;
if (index == _colors.size()) {
auto *colorData = new ColorData;
_colors.push_back(colorData);
}
return _colors[index];
}
std::size_t SkeletonCache::FrameData::getColorCount() const {
return _colors.size();
}
SkeletonCache::SegmentData *SkeletonCache::FrameData::buildSegmentData(std::size_t index) {
if (index > _segments.size()) return nullptr;
if (index == _segments.size()) {
auto *segmentData = new SegmentData;
_segments.push_back(segmentData);
}
return _segments[index];
}
std::size_t SkeletonCache::FrameData::getSegmentCount() const {
return _segments.size();
}
SkeletonCache::AnimationData::AnimationData() = default;
SkeletonCache::AnimationData::~AnimationData() {
reset();
}
void SkeletonCache::AnimationData::reset() {
for (auto &frame : _frames) {
delete frame;
}
_frames.clear();
_isComplete = false;
_totalTime = 0.0F;
}
bool SkeletonCache::AnimationData::needUpdate(int toFrameIdx) const {
return !_isComplete && _totalTime <= MaxCacheTime && (toFrameIdx == -1 || _frames.size() < toFrameIdx + 1);
}
SkeletonCache::FrameData *SkeletonCache::AnimationData::buildFrameData(std::size_t frameIdx) {
if (frameIdx > _frames.size()) {
return nullptr;
}
if (frameIdx == _frames.size()) {
auto *frameData = new FrameData();
_frames.push_back(frameData);
}
return _frames[frameIdx];
}
SkeletonCache::FrameData *SkeletonCache::AnimationData::getFrameData(std::size_t frameIdx) const {
if (frameIdx >= _frames.size()) {
return nullptr;
}
return _frames[frameIdx];
}
std::size_t SkeletonCache::AnimationData::getFrameCount() const {
return _frames.size();
}
SkeletonCache::SkeletonCache() = default;
SkeletonCache::~SkeletonCache() {
for (auto &animationCache : _animationCaches) {
delete animationCache.second;
}
_animationCaches.clear();
}
SkeletonCache::AnimationData *SkeletonCache::buildAnimationData(const std::string &animationName) {
AnimationData *aniData = nullptr;
auto it = _animationCaches.find(animationName);
if (it == _animationCaches.end()) {
auto *animation = findAnimation(animationName);
if (animation == nullptr) return nullptr;
aniData = new AnimationData();
aniData->_animationName = animationName;
_animationCaches[animationName] = aniData;
} else {
aniData = it->second;
}
return aniData;
}
SkeletonCache::AnimationData *SkeletonCache::getAnimationData(const std::string &animationName) {
auto it = _animationCaches.find(animationName);
if (it == _animationCaches.end()) {
return nullptr;
}
return it->second;
}
void SkeletonCache::update(float deltaTime) {
if (!_skeleton) return;
if (_ownsSkeleton) _skeleton->update(deltaTime);
_state->update(deltaTime);
_state->apply(*_skeleton);
_skeleton->updateWorldTransform();
}
void SkeletonCache::updateToFrame(const std::string &animationName, int toFrameIdx /*= -1*/) {
auto it = _animationCaches.find(animationName);
if (it == _animationCaches.end()) {
return;
}
AnimationData *animationData = it->second;
if (!animationData || !animationData->needUpdate(toFrameIdx)) {
return;
}
if (_curAnimationName != animationName) {
updateToFrame(_curAnimationName);
_curAnimationName = animationName;
}
// init animation
if (animationData->getFrameCount() == 0) {
setAnimation(0, animationName, false);
}
do {
update(FrameTime);
renderAnimationFrame(animationData);
animationData->_totalTime += FrameTime;
} while (animationData->needUpdate(toFrameIdx));
}
void SkeletonCache::renderAnimationFrame(AnimationData *animationData) {
std::size_t frameIndex = animationData->getFrameCount();
FrameData *frameData = animationData->buildFrameData(frameIndex);
if (!_skeleton) return;
// If opacity is 0,then return.
if (_skeleton->getColor().a == 0) {
return;
}
Color4F preColor(-1.0F, -1.0F, -1.0F, -1.0F);
Color4F preDarkColor(-1.0F, -1.0F, -1.0F, -1.0F);
// range [0.0, 1.0]
Color4F color;
Color4F darkColor;
Color4B finalColor;
Color4B finalDardk;
AttachmentVertices *attachmentVertices = nullptr;
middleware::IOBuffer &vb = frameData->vb;
middleware::IOBuffer &ib = frameData->ib;
// vertex size int bytes with two color
int vbs2 = sizeof(V3F_T2F_C4B_C4B);
// vertex size in floats with two color
int vs2 = static_cast<int32_t>(vbs2 / sizeof(float));
int vbSize = 0;
int ibSize = 0;
int preBlendMode = -1;
int preTextureIndex = -1;
int curTextureIndex = -1;
int preISegWritePos = -1;
int curISegLen = 0;
int curVSegLen = 0;
int materialLen = 0;
Slot *slot = nullptr;
middleware::Texture2D *texture = nullptr;
auto flush = [&]() {
// fill pre segment count field
if (preISegWritePos != -1) {
SegmentData *preSegmentData = frameData->buildSegmentData(materialLen - 1);
preSegmentData->indexCount = curISegLen;
preSegmentData->vertexFloatCount = curVSegLen;
}
SegmentData *segmentData = frameData->buildSegmentData(materialLen);
segmentData->setTexture(texture);
segmentData->blendMode = slot->getData().getBlendMode();
// save new segment count pos field
preISegWritePos = static_cast<int>(ib.getCurPos() / sizeof(uint16_t));
// reset pre blend mode to current
preBlendMode = static_cast<int>(slot->getData().getBlendMode());
// reset pre texture index to current
preTextureIndex = curTextureIndex;
// reset index segmentation count
curISegLen = 0;
// reset vertex segmentation count
curVSegLen = 0;
// material length increased
materialLen++;
};
auto &bones = _skeleton->getBones();
for (std::size_t i = 0, n = bones.size(); i < n; i++) {
auto &bone = bones[i];
auto boneCount = frameData->getBoneCount();
BoneData *boneData = frameData->buildBoneData(boneCount);
auto &matm = boneData->globalTransformMatrix.m;
matm[0] = bone->getA();
matm[1] = bone->getC();
matm[4] = bone->getB();
matm[5] = bone->getD();
matm[12] = bone->getWorldX();
matm[13] = bone->getWorldY();
}
auto &drawOrder = _skeleton->getDrawOrder();
for (size_t i = 0, n = drawOrder.size(); i < n; ++i) {
slot = drawOrder[i];
if (slot->getBone().isActive() == false) {
continue;
}
if (!slot->getAttachment()) {
_clipper->clipEnd(*slot);
continue;
}
const spine::Color &slotColor = slot->getColor();
TwoColorTriangles trianglesTwoColor;
spine::Color attachmentColor;
if (slot->getAttachment()->getRTTI().isExactly(RegionAttachment::rtti)) {
auto *attachment = dynamic_cast<RegionAttachment *>(slot->getAttachment());
attachmentVertices = static_cast<AttachmentVertices *>(attachment->getRendererObject());
// Early exit if attachment is invisible
if (attachment->getColor().a == 0) {
_clipper->clipEnd(*slot);
continue;
}
trianglesTwoColor.vertCount = attachmentVertices->_triangles->vertCount;
vbSize = static_cast<int32_t>(trianglesTwoColor.vertCount * sizeof(V3F_T2F_C4B_C4B));
vb.checkSpace(vbSize, true);
trianglesTwoColor.verts = reinterpret_cast<V3F_T2F_C4B_C4B *>(vb.getCurBuffer());
for (int ii = 0; ii < trianglesTwoColor.vertCount; ii++) {
trianglesTwoColor.verts[ii].texCoord = attachmentVertices->_triangles->verts[ii].texCoord;
}
attachment->computeWorldVertices(slot->getBone(), reinterpret_cast<float *>(trianglesTwoColor.verts), 0, vs2);
trianglesTwoColor.indexCount = attachmentVertices->_triangles->indexCount;
ibSize = static_cast<int32_t>(trianglesTwoColor.indexCount * sizeof(uint16_t));
ib.checkSpace(ibSize, true);
trianglesTwoColor.indices = reinterpret_cast<uint16_t *>(ib.getCurBuffer());
memcpy(trianglesTwoColor.indices, attachmentVertices->_triangles->indices, ibSize);
attachmentColor = attachment->getColor();
} else if (slot->getAttachment()->getRTTI().isExactly(MeshAttachment::rtti)) {
auto *attachment = dynamic_cast<MeshAttachment *>(slot->getAttachment());
attachmentVertices = static_cast<AttachmentVertices *>(attachment->getRendererObject());
// Early exit if attachment is invisible
if (attachment->getColor().a == 0) {
_clipper->clipEnd(*slot);
continue;
}
trianglesTwoColor.vertCount = attachmentVertices->_triangles->vertCount;
vbSize = static_cast<int32_t>(trianglesTwoColor.vertCount * sizeof(V3F_T2F_C4B_C4B));
vb.checkSpace(vbSize, true);
trianglesTwoColor.verts = reinterpret_cast<V3F_T2F_C4B_C4B *>(vb.getCurBuffer());
for (int ii = 0; ii < trianglesTwoColor.vertCount; ii++) {
trianglesTwoColor.verts[ii].texCoord = attachmentVertices->_triangles->verts[ii].texCoord;
}
attachment->computeWorldVertices(*slot, 0, attachment->getWorldVerticesLength(), reinterpret_cast<float *>(trianglesTwoColor.verts), 0, vs2);
trianglesTwoColor.indexCount = attachmentVertices->_triangles->indexCount;
ibSize = static_cast<int32_t>(trianglesTwoColor.indexCount * sizeof(uint16_t));
ib.checkSpace(ibSize, true);
trianglesTwoColor.indices = reinterpret_cast<uint16_t *>(ib.getCurBuffer());
memcpy(trianglesTwoColor.indices, attachmentVertices->_triangles->indices, ibSize);
attachmentColor = attachment->getColor();
} else if (slot->getAttachment()->getRTTI().isExactly(ClippingAttachment::rtti)) {
auto *clip = dynamic_cast<ClippingAttachment *>(slot->getAttachment());
_clipper->clipStart(*slot, clip);
continue;
} else {
_clipper->clipEnd(*slot);
continue;
}
color.a = _skeleton->getColor().a * slotColor.a * attachmentColor.a * 255;
// skip rendering if the color of this attachment is 0
if (color.a == 0) {
_clipper->clipEnd(*slot);
continue;
}
float red = _skeleton->getColor().r * attachmentColor.r * 255;
float green = _skeleton->getColor().g * attachmentColor.g * 255;
float blue = _skeleton->getColor().b * attachmentColor.b * 255;
color.r = red * slotColor.r;
color.g = green * slotColor.g;
color.b = blue * slotColor.b;
if (slot->hasDarkColor()) {
darkColor.r = red * slot->getDarkColor().r;
darkColor.g = green * slot->getDarkColor().g;
darkColor.b = blue * slot->getDarkColor().b;
darkColor.a = 0;
} else {
darkColor.r = 0;
darkColor.g = 0;
darkColor.b = 0;
darkColor.a = 0;
}
finalColor.r = static_cast<uint8_t>(std::round(color.r));
finalColor.g = static_cast<uint8_t>(std::round(color.g));
finalColor.b = static_cast<uint8_t>(std::round(color.b));
finalColor.a = static_cast<uint8_t>(std::round(color.a));
finalDardk.r = static_cast<uint8_t>(std::round(darkColor.r));
finalDardk.g = static_cast<uint8_t>(std::round(darkColor.g));
finalDardk.b = static_cast<uint8_t>(std::round(darkColor.b));
finalDardk.a = static_cast<uint8_t>(std::round(darkColor.a));
if (preColor != color || preDarkColor != darkColor) {
preColor = color;
preDarkColor = darkColor;
auto colorCount = frameData->getColorCount();
if (colorCount > 0) {
ColorData *preColorData = frameData->buildColorData(colorCount - 1);
preColorData->vertexFloatOffset = static_cast<int>(vb.getCurPos() / sizeof(float));
}
ColorData *colorData = frameData->buildColorData(colorCount);
colorData->finalColor = finalColor;
colorData->darkColor = finalDardk;
}
// Two color tint logic
if (_clipper->isClipping()) {
_clipper->clipTriangles(reinterpret_cast<float *>(&trianglesTwoColor.verts[0].vertex), trianglesTwoColor.indices, trianglesTwoColor.indexCount, reinterpret_cast<float *>(&trianglesTwoColor.verts[0].texCoord), vs2);
if (_clipper->getClippedTriangles().size() == 0) {
_clipper->clipEnd(*slot);
continue;
}
trianglesTwoColor.vertCount = static_cast<int>(_clipper->getClippedVertices().size()) >> 1;
vbSize = static_cast<int32_t>(trianglesTwoColor.vertCount * sizeof(V3F_T2F_C4B_C4B));
vb.checkSpace(vbSize, true);
trianglesTwoColor.verts = reinterpret_cast<V3F_T2F_C4B_C4B *>(vb.getCurBuffer());
trianglesTwoColor.indexCount = static_cast<int>(_clipper->getClippedTriangles().size());
ibSize = static_cast<int32_t>(trianglesTwoColor.indexCount * sizeof(uint16_t));
ib.checkSpace(ibSize, true);
trianglesTwoColor.indices = reinterpret_cast<uint16_t *>(ib.getCurBuffer());
memcpy(trianglesTwoColor.indices, _clipper->getClippedTriangles().buffer(), sizeof(uint16_t) * _clipper->getClippedTriangles().size());
float *verts = _clipper->getClippedVertices().buffer();
float *uvs = _clipper->getClippedUVs().buffer();
for (int v = 0, vn = trianglesTwoColor.vertCount, vv = 0; v < vn; ++v, vv += 2) {
V3F_T2F_C4B_C4B *vertex = trianglesTwoColor.verts + v;
vertex->vertex.x = verts[vv];
vertex->vertex.y = verts[vv + 1];
vertex->texCoord.u = uvs[vv];
vertex->texCoord.v = uvs[vv + 1];
vertex->color = finalColor;
vertex->color2 = finalDardk;
}
} else {
for (int v = 0, vn = trianglesTwoColor.vertCount; v < vn; ++v) {
V3F_T2F_C4B_C4B *vertex = trianglesTwoColor.verts + v;
vertex->color = finalColor;
vertex->color2 = finalDardk;
}
}
texture = attachmentVertices->_texture;
curTextureIndex = attachmentVertices->_texture->getRealTextureIndex();
// If texture or blendMode change,will change material.
if (preTextureIndex != curTextureIndex || preBlendMode != slot->getData().getBlendMode()) {
flush();
}
if (vbSize > 0 && ibSize > 0) {
auto vertexOffset = curVSegLen / vs2;
if (vertexOffset > 0) {
auto *ibBuffer = reinterpret_cast<uint16_t *>(ib.getCurBuffer());
for (uint32_t ii = 0, nn = ibSize / sizeof(uint16_t); ii < nn; ii++) {
ibBuffer[ii] += vertexOffset;
}
}
vb.move(vbSize);
ib.move(ibSize);
// Record this turn index segmentation count,it will store in material buffer in the end.
curISegLen += static_cast<int32_t>(ibSize / sizeof(uint16_t));
curVSegLen += static_cast<int32_t>(vbSize / sizeof(float));
}
_clipper->clipEnd(*slot);
} // End slot traverse
_clipper->clipEnd();
if (preISegWritePos != -1) {
SegmentData *preSegmentData = frameData->buildSegmentData(materialLen - 1);
preSegmentData->indexCount = curISegLen;
preSegmentData->vertexFloatCount = curVSegLen;
}
auto colorCount = frameData->getColorCount();
if (colorCount > 0) {
ColorData *preColorData = frameData->buildColorData(colorCount - 1);
preColorData->vertexFloatOffset = static_cast<int>(vb.getCurPos() / sizeof(float));
}
}
void SkeletonCache::onAnimationStateEvent(TrackEntry *entry, EventType type, Event *event) {
SkeletonAnimation::onAnimationStateEvent(entry, type, event);
if (type == EventType_Complete && entry) {
Animation *ani = entry->getAnimation();
if (!ani) return;
std::string aniName = ani->getName().buffer();
if (aniName == _curAnimationName) {
AnimationData *aniData = getAnimationData(_curAnimationName);
if (!aniData) return;
aniData->_isComplete = true;
}
}
}
void SkeletonCache::resetAllAnimationData() {
for (auto &animationCache : _animationCaches) {
animationCache.second->reset();
}
}
void SkeletonCache::resetAnimationData(const std::string &animationName) {
for (auto &animationCache : _animationCaches) {
if (animationCache.second->_animationName == animationName) {
animationCache.second->reset();
break;
}
}
}
} // namespace spine

View File

@@ -0,0 +1,157 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma once
#include <vector>
#include "IOBuffer.h"
#include "SkeletonAnimation.h"
#include "middleware-adapter.h"
namespace spine {
class SkeletonCache : public SkeletonAnimation {
public:
struct SegmentData {
friend class SkeletonCache;
SegmentData();
~SegmentData();
void setTexture(cc::middleware::Texture2D *value);
cc::middleware::Texture2D *getTexture() const;
public:
int indexCount = 0;
int vertexFloatCount = 0;
int blendMode = 0;
private:
cc::middleware::Texture2D *_texture = nullptr;
};
struct BoneData {
cc::Mat4 globalTransformMatrix;
};
struct ColorData {
cc::middleware::Color4B finalColor;
cc::middleware::Color4B darkColor;
int vertexFloatOffset = 0;
};
struct FrameData {
friend class SkeletonCache;
FrameData();
~FrameData();
const std::vector<BoneData *> &getBones() const {
return _bones;
}
std::size_t getBoneCount() const;
const std::vector<ColorData *> &getColors() const {
return _colors;
}
std::size_t getColorCount() const;
const std::vector<SegmentData *> &getSegments() const {
return _segments;
}
std::size_t getSegmentCount() const;
private:
// if segment data is empty, it will build new one.
SegmentData *buildSegmentData(std::size_t index);
// if color data is empty, it will build new one.
ColorData *buildColorData(std::size_t index);
// if bone data is empty, it will build new one.
BoneData *buildBoneData(std::size_t index);
std::vector<BoneData *> _bones;
std::vector<ColorData *> _colors;
std::vector<SegmentData *> _segments;
public:
cc::middleware::IOBuffer ib;
cc::middleware::IOBuffer vb;
};
struct AnimationData {
friend class SkeletonCache;
AnimationData();
~AnimationData();
void reset();
FrameData *getFrameData(std::size_t frameIdx) const;
std::size_t getFrameCount() const;
bool isComplete() const { return _isComplete; }
bool needUpdate(int toFrameIdx) const;
private:
// if frame is empty, it will build new one.
FrameData *buildFrameData(std::size_t frameIdx);
private:
std::string _animationName = "";
bool _isComplete = false;
float _totalTime = 0.0f;
std::vector<FrameData *> _frames;
};
SkeletonCache();
virtual ~SkeletonCache();
virtual void beginSchedule() override {}
virtual void stopSchedule() override {}
virtual void update(float deltaTime) override;
virtual void render(float deltaTime) override {}
virtual void onAnimationStateEvent(TrackEntry *entry, EventType type, Event *event) override;
void updateToFrame(const std::string &animationName, int toFrameIdx = -1);
// if animation data is empty, it will build new one.
AnimationData *buildAnimationData(const std::string &animationName);
AnimationData *getAnimationData(const std::string &animationName);
void resetAllAnimationData();
void resetAnimationData(const std::string &animationName);
private:
void renderAnimationFrame(AnimationData *animationData);
public:
static float FrameTime;
static float MaxCacheTime;
private:
std::string _curAnimationName = "";
std::map<std::string, AnimationData *> _animationCaches;
};
} // namespace spine

View File

@@ -0,0 +1,604 @@
/******************************************************************************
* 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 "SkeletonCacheAnimation.h"
#include "2d/renderer/RenderDrawInfo.h"
#include "2d/renderer/RenderEntity.h"
#include "MiddlewareMacro.h"
#include "SharedBufferManager.h"
#include "SkeletonCacheMgr.h"
#include "base/TypeDef.h"
#include "base/memory/Memory.h"
#include "gfx-base/GFXDef.h"
#include "math/Math.h"
#include "renderer/core/MaterialInstance.h"
USING_NS_MW; // NOLINT(google-build-using-namespace)
using namespace cc; // NOLINT(google-build-using-namespace)
using namespace cc::gfx; // NOLINT(google-build-using-namespace)
static const std::string TECH_STAGE = "opaque";
static const std::string TEXTURE_KEY = "texture";
namespace spine {
SkeletonCacheAnimation::SkeletonCacheAnimation(const std::string &uuid, bool isShare) {
if (isShare) {
_skeletonCache = SkeletonCacheMgr::getInstance()->buildSkeletonCache(uuid);
_skeletonCache->addRef();
} else {
_skeletonCache = new SkeletonCache();
_skeletonCache->addRef();
_skeletonCache->initWithUUID(uuid);
}
// store global TypedArray begin and end offset
_sharedBufferOffset = new IOTypedArray(se::Object::TypedArrayType::UINT32, sizeof(uint32_t) * 2);
}
SkeletonCacheAnimation::~SkeletonCacheAnimation() {
if (_sharedBufferOffset) {
delete _sharedBufferOffset;
_sharedBufferOffset = nullptr;
}
if (_skeletonCache) {
_skeletonCache->release();
_skeletonCache = nullptr;
}
while (!_animationQueue.empty()) {
auto *ani = _animationQueue.front();
_animationQueue.pop();
delete ani;
}
for (auto *draw : _drawInfoArray) {
CC_SAFE_DELETE(draw);
}
for (auto &item : _materialCaches) {
CC_SAFE_DELETE(item.second);
}
stopSchedule();
}
void SkeletonCacheAnimation::update(float dt) {
if (_paused) return;
auto gTimeScale = SkeletonAnimation::GlobalTimeScale;
dt *= _timeScale * gTimeScale;
if (_isAniComplete) {
if (_animationQueue.empty() && !_headAnimation) {
if (_animationData && !_animationData->isComplete()) {
_skeletonCache->updateToFrame(_animationName);
}
return;
}
if (!_headAnimation) {
_headAnimation = _animationQueue.front();
_animationQueue.pop();
}
if (!_headAnimation) {
return;
}
_accTime += dt;
if (_accTime > _headAnimation->delay) {
std::string name = _headAnimation->animationName;
bool loop = _headAnimation->loop;
delete _headAnimation;
_headAnimation = nullptr;
setAnimation(name, loop);
return;
}
}
if (!_animationData) return;
if (_accTime <= 0.00001 && _playCount == 0) {
if (_startListener) {
_startListener(_animationName);
}
}
_accTime += dt;
int frameIdx = floor(_accTime / SkeletonCache::FrameTime);
if (!_animationData->isComplete()) {
_skeletonCache->updateToFrame(_animationName, frameIdx);
}
int finalFrameIndex = static_cast<int>(_animationData->getFrameCount()) - 1;
if (_animationData->isComplete() && frameIdx >= finalFrameIndex) {
_playCount++;
_accTime = 0.0F;
if (_playTimes > 0 && _playCount >= _playTimes) {
frameIdx = finalFrameIndex;
_playCount = 0;
_isAniComplete = true;
} else {
frameIdx = 0;
}
if (_endListener) {
_endListener(_animationName);
}
if (_completeListener) {
_completeListener(_animationName);
}
}
_curFrameIndex = frameIdx;
}
void SkeletonCacheAnimation::render(float /*dt*/) {
if (!_animationData) return;
SkeletonCache::FrameData *frameData = _animationData->getFrameData(_curFrameIndex);
if (!frameData) return;
auto *entity = _entity;
entity->clearDynamicRenderDrawInfos();
const auto &segments = frameData->getSegments();
const auto &colors = frameData->getColors();
if (segments.empty() || colors.empty()) return;
auto *mgr = MiddlewareManager::getInstance();
if (!mgr->isRendering) return;
_sharedBufferOffset->reset();
_sharedBufferOffset->clear();
auto *attachMgr = mgr->getAttachInfoMgr();
auto *attachInfo = attachMgr->getBuffer();
if (!attachInfo) return;
// store attach info offset
_sharedBufferOffset->writeUint32(static_cast<uint32_t>(attachInfo->getCurPos()) / sizeof(uint32_t));
auto vertexFormat = _useTint ? VF_XYZUVCC : VF_XYZUVC;
middleware::MeshBuffer *mb = mgr->getMeshBuffer(vertexFormat);
middleware::IOBuffer &vb = mb->getVB();
middleware::IOBuffer &ib = mb->getIB();
const auto &srcVB = frameData->vb;
const auto &srcIB = frameData->ib;
// vertex size int bytes with one color
int vbs1 = sizeof(V3F_T2F_C4B);
// vertex size in floats with one color
int vs1 = static_cast<int32_t>(vbs1 / sizeof(float));
// vertex size int bytes with two color
int vbs2 = sizeof(V3F_T2F_C4B_C4B);
// vertex size in floats with two color
int vs2 = static_cast<int32_t>(vbs2 / sizeof(float));
int vs = _useTint ? vs2 : vs1;
int vbs = _useTint ? vbs2 : vbs1;
auto &nodeWorldMat = entity->getNode()->getWorldMatrix();
int colorOffset = 0;
SkeletonCache::ColorData *nowColor = colors[colorOffset++];
auto maxVFOffset = nowColor->vertexFloatOffset;
Color4B finalColor;
Color4B darkColor;
float tempR = 0.0F;
float tempG = 0.0F;
float tempB = 0.0F;
float tempA = 0.0F;
float multiplier = 1.0F;
int srcVertexBytesOffset = 0;
int srcVertexBytes = 0;
int vertexBytes = 0;
int vertexFloats = 0;
int tintBytes = 0;
int srcIndexBytesOffset = 0;
int indexBytes = 0;
double effectHash = 0;
int blendMode = 0;
int dstVertexOffset = 0;
int dstIndexOffset = 0;
float *dstVertexBuffer = nullptr;
unsigned int *dstColorBuffer = nullptr;
uint16_t *dstIndexBuffer = nullptr;
bool needColor = false;
int curBlendSrc = -1;
int curBlendDst = -1;
cc::Texture2D *curTexture = nullptr;
RenderDrawInfo *curDrawInfo = nullptr;
if (abs(_nodeColor.r - 1.0F) > 0.0001F ||
abs(_nodeColor.g - 1.0F) > 0.0001F ||
abs(_nodeColor.b - 1.0F) > 0.0001F ||
abs(_nodeColor.a - 1.0F) > 0.0001F ||
_premultipliedAlpha) {
needColor = true;
}
auto handleColor = [&](SkeletonCache::ColorData *colorData) {
tempA = colorData->finalColor.a * _nodeColor.a;
multiplier = _premultipliedAlpha ? tempA / 255 : 1;
tempR = _nodeColor.r * multiplier;
tempG = _nodeColor.g * multiplier;
tempB = _nodeColor.b * multiplier;
finalColor.r = static_cast<uint8_t>(std::round(colorData->finalColor.r * tempR));
finalColor.g = static_cast<uint8_t>(std::round(colorData->finalColor.g * tempG));
finalColor.b = static_cast<uint8_t>(std::round(colorData->finalColor.b * tempB));
finalColor.a = static_cast<uint8_t>(std::round(tempA));
darkColor.r = static_cast<uint8_t>(std::round(colorData->darkColor.r * tempR));
darkColor.g = static_cast<uint8_t>(std::round(colorData->darkColor.g * tempG));
darkColor.b = static_cast<uint8_t>(std::round(colorData->darkColor.b * tempB));
darkColor.a = _premultipliedAlpha ? 255 : 0;
};
handleColor(nowColor);
int segmentCount = 0;
for (auto *segment : segments) {
srcVertexBytes = static_cast<int32_t>(segment->vertexFloatCount * sizeof(float));
if (!_useTint) {
tintBytes = static_cast<int32_t>(segment->vertexFloatCount / vs2 * sizeof(float));
vertexBytes = srcVertexBytes - tintBytes;
vertexFloats = static_cast<int32_t>(vertexBytes / sizeof(float));
} else {
vertexBytes = srcVertexBytes;
vertexFloats = segment->vertexFloatCount;
}
curDrawInfo = requestDrawInfo(segmentCount++);
entity->addDynamicRenderDrawInfo(curDrawInfo);
// fill new texture index
curTexture = static_cast<cc::Texture2D *>(segment->getTexture()->getRealTexture());
gfx::Texture *texture = curTexture->getGFXTexture();
gfx::Sampler *sampler = curTexture->getGFXSampler();
curDrawInfo->setTexture(texture);
curDrawInfo->setSampler(sampler);
blendMode = segment->blendMode;
switch (blendMode) {
case BlendMode_Additive:
curBlendSrc = static_cast<int>(_premultipliedAlpha ? BlendFactor::ONE : BlendFactor::SRC_ALPHA);
curBlendDst = static_cast<int>(BlendFactor::ONE);
break;
case BlendMode_Multiply:
curBlendSrc = static_cast<int>(BlendFactor::DST_COLOR);
curBlendDst = static_cast<int>(BlendFactor::ONE_MINUS_SRC_ALPHA);
break;
case BlendMode_Screen:
curBlendSrc = static_cast<int>(BlendFactor::ONE);
curBlendDst = static_cast<int>(BlendFactor::ONE_MINUS_SRC_COLOR);
break;
default:
curBlendSrc = static_cast<int>(_premultipliedAlpha ? BlendFactor::ONE : BlendFactor::SRC_ALPHA);
curBlendDst = static_cast<int>(BlendFactor::ONE_MINUS_SRC_ALPHA);
}
// fill new blend src and dst
auto *material = requestMaterial(curBlendSrc, curBlendDst);
curDrawInfo->setMaterial(material);
// fill vertex buffer
vb.checkSpace(vertexBytes, true);
dstVertexOffset = static_cast<int>(vb.getCurPos()) / vbs;
dstVertexBuffer = reinterpret_cast<float *>(vb.getCurBuffer());
dstColorBuffer = reinterpret_cast<unsigned int *>(vb.getCurBuffer());
if (!_useTint) {
char *srcBuffer = reinterpret_cast<char *>(srcVB.getBuffer()) + srcVertexBytesOffset;
for (std::size_t srcBufferIdx = 0; srcBufferIdx < srcVertexBytes; srcBufferIdx += vbs2) {
vb.writeBytes(srcBuffer + srcBufferIdx, vbs);
}
} else {
vb.writeBytes(reinterpret_cast<char *>(srcVB.getBuffer()) + srcVertexBytesOffset, vertexBytes);
}
// batch handle
if (_enableBatch) {
cc::Vec3 *point = nullptr;
for (auto posIndex = 0; posIndex < vertexFloats; posIndex += vs) {
point = reinterpret_cast<cc::Vec3 *>(dstVertexBuffer + posIndex);
point->z = 0;
point->transformMat4(*point, nodeWorldMat);
}
}
// handle vertex color
if (needColor) {
int srcVertexFloatOffset = static_cast<int16_t>(srcVertexBytesOffset / sizeof(float));
if (_useTint) {
for (auto colorIndex = 0; colorIndex < vertexFloats; colorIndex += vs, srcVertexFloatOffset += vs2) {
if (srcVertexFloatOffset >= maxVFOffset) {
nowColor = colors[colorOffset++];
handleColor(nowColor);
maxVFOffset = nowColor->vertexFloatOffset;
}
memcpy(dstColorBuffer + colorIndex + 5, &finalColor, sizeof(finalColor));
memcpy(dstColorBuffer + colorIndex + 6, &darkColor, sizeof(darkColor));
}
} else {
for (auto colorIndex = 0; colorIndex < vertexFloats; colorIndex += vs, srcVertexFloatOffset += vs2) {
if (srcVertexFloatOffset >= maxVFOffset) {
nowColor = colors[colorOffset++];
handleColor(nowColor);
maxVFOffset = nowColor->vertexFloatOffset;
}
memcpy(dstColorBuffer + colorIndex + 5, &finalColor, sizeof(finalColor));
}
}
}
// move src vertex buffer offset
srcVertexBytesOffset += srcVertexBytes;
// fill index buffer
indexBytes = static_cast<int32_t>(segment->indexCount * sizeof(uint16_t));
ib.checkSpace(indexBytes, true);
dstIndexOffset = static_cast<int32_t>(ib.getCurPos() / sizeof(uint16_t));
dstIndexBuffer = reinterpret_cast<uint16_t *>(ib.getCurBuffer());
ib.writeBytes(reinterpret_cast<char *>(srcIB.getBuffer()) + srcIndexBytesOffset, indexBytes);
for (auto indexPos = 0; indexPos < segment->indexCount; indexPos++) {
dstIndexBuffer[indexPos] += dstVertexOffset;
}
srcIndexBytesOffset += indexBytes;
// fill new index and vertex buffer id
UIMeshBuffer *uiMeshBuffer = mb->getUIMeshBuffer();
curDrawInfo->setMeshBuffer(uiMeshBuffer);
// fill new index offset
curDrawInfo->setIndexOffset(dstIndexOffset);
// fill new indice segamentation count
curDrawInfo->setIbCount(segment->indexCount);
}
if (_useAttach) {
const auto &bonesData = frameData->getBones();
auto boneCount = frameData->getBoneCount();
for (std::size_t i = 0, n = boneCount; i < n; i++) {
auto *bone = bonesData[i];
attachInfo->checkSpace(sizeof(cc::Mat4), true);
attachInfo->writeBytes(reinterpret_cast<const char *>(&bone->globalTransformMatrix), sizeof(cc::Mat4));
}
}
}
Skeleton *SkeletonCacheAnimation::getSkeleton() const {
return _skeletonCache->getSkeleton();
}
void SkeletonCacheAnimation::setTimeScale(float scale) {
_timeScale = scale;
}
float SkeletonCacheAnimation::getTimeScale() const {
return _timeScale;
}
void SkeletonCacheAnimation::paused(bool value) {
_paused = value;
}
Bone *SkeletonCacheAnimation::findBone(const std::string &boneName) const {
return _skeletonCache->findBone(boneName);
}
Slot *SkeletonCacheAnimation::findSlot(const std::string &slotName) const {
return _skeletonCache->findSlot(slotName);
}
void SkeletonCacheAnimation::setSkin(const std::string &skinName) {
_skeletonCache->setSkin(skinName);
_skeletonCache->resetAllAnimationData();
}
void SkeletonCacheAnimation::setSkin(const char *skinName) {
_skeletonCache->setSkin(skinName);
_skeletonCache->resetAllAnimationData();
}
Attachment *SkeletonCacheAnimation::getAttachment(const std::string &slotName, const std::string &attachmentName) const {
return _skeletonCache->getAttachment(slotName, attachmentName);
}
bool SkeletonCacheAnimation::setAttachment(const std::string &slotName, const std::string &attachmentName) {
auto ret = _skeletonCache->setAttachment(slotName, attachmentName);
_skeletonCache->resetAllAnimationData();
return ret;
}
bool SkeletonCacheAnimation::setAttachment(const std::string &slotName, const char *attachmentName) {
auto ret = _skeletonCache->setAttachment(slotName, attachmentName);
_skeletonCache->resetAllAnimationData();
return ret;
}
void SkeletonCacheAnimation::setColor(float r, float g, float b, float a) {
_nodeColor.r = r / 255.0F;
_nodeColor.g = g / 255.0F;
_nodeColor.b = b / 255.0F;
_nodeColor.a = a / 255.0F;
}
void SkeletonCacheAnimation::setBatchEnabled(bool enabled) {
if (_enableBatch != enabled) {
for (auto &item : _materialCaches) {
CC_SAFE_DELETE(item.second);
}
_materialCaches.clear();
_enableBatch = enabled;
}
}
void SkeletonCacheAnimation::setOpacityModifyRGB(bool value) {
_premultipliedAlpha = value;
}
bool SkeletonCacheAnimation::isOpacityModifyRGB() const {
return _premultipliedAlpha;
}
void SkeletonCacheAnimation::beginSchedule() {
MiddlewareManager::getInstance()->addTimer(this);
}
void SkeletonCacheAnimation::stopSchedule() {
MiddlewareManager::getInstance()->removeTimer(this);
if (_sharedBufferOffset) {
_sharedBufferOffset->reset();
_sharedBufferOffset->clear();
}
}
void SkeletonCacheAnimation::onEnable() {
beginSchedule();
}
void SkeletonCacheAnimation::onDisable() {
stopSchedule();
}
void SkeletonCacheAnimation::setUseTint(bool enabled) {
// cache mode default enable use tint
// _useTint = enabled;
}
void SkeletonCacheAnimation::setAttachEnabled(bool enabled) {
_useAttach = enabled;
}
void SkeletonCacheAnimation::setAnimation(const std::string &name, bool loop) {
_playTimes = loop ? 0 : 1;
_animationName = name;
_animationData = _skeletonCache->buildAnimationData(_animationName);
_isAniComplete = false;
_accTime = 0.0F;
_playCount = 0;
_curFrameIndex = 0;
}
void SkeletonCacheAnimation::addAnimation(const std::string &name, bool loop, float delay) {
auto *aniInfo = new AniQueueData();
aniInfo->animationName = name;
aniInfo->loop = loop;
aniInfo->delay = delay;
_animationQueue.push(aniInfo);
}
Animation *SkeletonCacheAnimation::findAnimation(const std::string &name) const {
return _skeletonCache->findAnimation(name);
}
void SkeletonCacheAnimation::setStartListener(const CacheFrameEvent &listener) {
_startListener = listener;
}
void SkeletonCacheAnimation::setEndListener(const CacheFrameEvent &listener) {
_endListener = listener;
}
void SkeletonCacheAnimation::setCompleteListener(const CacheFrameEvent &listener) {
_completeListener = listener;
}
void SkeletonCacheAnimation::updateAnimationCache(const std::string &animationName) {
_skeletonCache->resetAnimationData(animationName);
}
void SkeletonCacheAnimation::updateAllAnimationCache() {
_skeletonCache->resetAllAnimationData();
}
se_object_ptr SkeletonCacheAnimation::getSharedBufferOffset() const {
if (_sharedBufferOffset) {
return _sharedBufferOffset->getTypeArray();
}
return nullptr;
}
void SkeletonCacheAnimation::setToSetupPose() {
if (_skeletonCache) {
_skeletonCache->setToSetupPose();
}
}
void SkeletonCacheAnimation::setBonesToSetupPose() {
if (_skeletonCache) {
_skeletonCache->setBonesToSetupPose();
}
}
void SkeletonCacheAnimation::setSlotsToSetupPose() {
if (_skeletonCache) {
_skeletonCache->setSlotsToSetupPose();
}
}
void SkeletonCacheAnimation::setRenderEntity(cc::RenderEntity *entity) {
_entity = entity;
}
void SkeletonCacheAnimation::setMaterial(cc::Material *material) {
_material = material;
for (auto &item : _materialCaches) {
CC_SAFE_DELETE(item.second);
}
_materialCaches.clear();
}
cc::RenderDrawInfo *SkeletonCacheAnimation::requestDrawInfo(int idx) {
if (_drawInfoArray.size() < idx + 1) {
cc::RenderDrawInfo *draw = new cc::RenderDrawInfo();
draw->setDrawInfoType(static_cast<uint32_t>(RenderDrawInfoType::MIDDLEWARE));
_drawInfoArray.push_back(draw);
}
return _drawInfoArray[idx];
}
cc::Material *SkeletonCacheAnimation::requestMaterial(uint16_t blendSrc, uint16_t blendDst) {
uint32_t key = static_cast<uint32_t>(blendSrc) << 16 | static_cast<uint32_t>(blendDst);
if (_materialCaches.find(key) == _materialCaches.end()) {
const IMaterialInstanceInfo info{
(Material *)_material,
0};
MaterialInstance *materialInstance = new MaterialInstance(info);
PassOverrides overrides;
BlendStateInfo stateInfo;
stateInfo.blendColor = gfx::Color{1.0F, 1.0F, 1.0F, 1.0F};
BlendTargetInfo targetInfo;
targetInfo.blendEq = gfx::BlendOp::ADD;
targetInfo.blendAlphaEq = gfx::BlendOp::ADD;
targetInfo.blendSrc = (gfx::BlendFactor)blendSrc;
targetInfo.blendDst = (gfx::BlendFactor)blendDst;
targetInfo.blendSrcAlpha = (gfx::BlendFactor)blendSrc;
targetInfo.blendDstAlpha = (gfx::BlendFactor)blendDst;
BlendTargetInfoList targetList{targetInfo};
stateInfo.targets = targetList;
overrides.blendState = stateInfo;
materialInstance->overridePipelineStates(overrides);
const MacroRecord macros{{"TWO_COLORED", _useTint}, {"USE_LOCAL", !_enableBatch}};
materialInstance->recompileShaders(macros);
_materialCaches[key] = materialInstance;
}
return _materialCaches[key];
}
} // namespace spine

View File

@@ -0,0 +1,145 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma once
#include <queue>
#include "MiddlewareManager.h"
#include "SkeletonCache.h"
#include "base/RefCounted.h"
#include "middleware-adapter.h"
#include "spine/spine.h"
namespace cc {
class RenderEntity;
class RenderDrawInfo;
class Material;
};
namespace spine {
class SkeletonCacheAnimation : public cc::RefCounted, public cc::middleware::IMiddleware {
public:
SkeletonCacheAnimation(const std::string &uuid, bool isShare);
~SkeletonCacheAnimation() override;
void update(float dt) override;
void render(float dt) override;
Skeleton *getSkeleton() const;
void setTimeScale(float scale);
float getTimeScale() const;
void paused(bool value);
Bone *findBone(const std::string &boneName) const;
Slot *findSlot(const std::string &slotName) const;
void setSkin(const std::string &skinName);
void setSkin(const char *skinName);
Attachment *getAttachment(const std::string &slotName, const std::string &attachmentName) const;
bool setAttachment(const std::string &slotName, const std::string &attachmentName);
bool setAttachment(const std::string &slotName, const char *attachmentName);
void setColor(float r, float g, float b, float a);
void setBatchEnabled(bool enabled);
void setAttachEnabled(bool enabled);
void setOpacityModifyRGB(bool value);
bool isOpacityModifyRGB() const;
void beginSchedule();
void stopSchedule();
void onEnable();
void onDisable();
void setUseTint(bool enabled);
void setAnimation(const std::string &name, bool loop);
void addAnimation(const std::string &name, bool loop, float delay = 0);
Animation *findAnimation(const std::string &name) const;
using CacheFrameEvent = std::function<void(std::string)>;
void setStartListener(const CacheFrameEvent &listener);
void setEndListener(const CacheFrameEvent &listener);
void setCompleteListener(const CacheFrameEvent &listener);
void updateAnimationCache(const std::string &animationName);
void updateAllAnimationCache();
void setToSetupPose();
void setBonesToSetupPose();
void setSlotsToSetupPose();
/**
* @return shared buffer offset, it's a Uint32Array
* format |render info offset|attach info offset|
*/
se_object_ptr getSharedBufferOffset() const;
cc::RenderDrawInfo *requestDrawInfo(int idx);
cc::Material *requestMaterial(uint16_t blendSrc, uint16_t blendDst);
void setMaterial(cc::Material *material);
void setRenderEntity(cc::RenderEntity* entity);
private:
float _timeScale = 1;
bool _paused = false;
bool _useAttach = false;
cc::middleware::Color4F _nodeColor = cc::middleware::Color4F::WHITE;
bool _premultipliedAlpha = false;
CacheFrameEvent _startListener = nullptr;
CacheFrameEvent _endListener = nullptr;
CacheFrameEvent _completeListener = nullptr;
SkeletonCache *_skeletonCache = nullptr;
SkeletonCache::AnimationData *_animationData = nullptr;
int _curFrameIndex = -1;
float _accTime = 0.0F;
int _playCount = 0;
int _playTimes = 0;
bool _isAniComplete = true;
std::string _animationName;
bool _useTint = true;
bool _enableBatch = false;
struct AniQueueData {
std::string animationName;
bool loop = false;
float delay = 0.0F;
};
std::queue<AniQueueData *> _animationQueue;
AniQueueData *_headAnimation = nullptr;
cc::middleware::IOTypedArray *_sharedBufferOffset = nullptr;
cc::RenderEntity *_entity = nullptr;
cc::Material *_material = nullptr;
ccstd::vector<cc::RenderDrawInfo *> _drawInfoArray;
ccstd::unordered_map<uint32_t, cc::Material*> _materialCaches;
};
} // namespace spine

View File

@@ -0,0 +1,53 @@
/******************************************************************************
* 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 "SkeletonCacheMgr.h"
#include "base/DeferredReleasePool.h"
namespace spine {
SkeletonCacheMgr *SkeletonCacheMgr::instance = nullptr;
SkeletonCache *SkeletonCacheMgr::buildSkeletonCache(const std::string &uuid) {
SkeletonCache *animation = _caches.at(uuid);
if (!animation) {
animation = new SkeletonCache();
animation->addRef();
animation->initWithUUID(uuid);
_caches.insert(uuid, animation);
cc::DeferredReleasePool::add(animation);
}
return animation;
}
void SkeletonCacheMgr::removeSkeletonCache(const std::string &uuid) {
auto it = _caches.find(uuid);
if (it != _caches.end()) {
_caches.erase(it);
}
}
} // namespace spine

View File

@@ -0,0 +1,60 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma once
#include "SkeletonCache.h"
#include "base/RefMap.h"
namespace spine {
class SkeletonCacheMgr {
public:
static SkeletonCacheMgr *getInstance() {
if (instance == nullptr) {
instance = new SkeletonCacheMgr();
}
return instance;
}
static void destroyInstance() {
if (instance) {
delete instance;
instance = nullptr;
}
}
void removeSkeletonCache(const std::string &uuid);
SkeletonCache *buildSkeletonCache(const std::string &uuid);
private:
static SkeletonCacheMgr *instance;
cc::RefMap<std::string, SkeletonCache *> _caches;
};
} // namespace spine

View File

@@ -0,0 +1,116 @@
/******************************************************************************
* 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 "SkeletonDataMgr.h"
#include <algorithm>
#include <vector>
using namespace spine; //NOLINT
namespace spine {
class SkeletonDataInfo {
public:
SkeletonDataInfo() = default;
~SkeletonDataInfo() {
if (data) {
delete data;
data = nullptr;
}
if (atlas) {
delete atlas;
atlas = nullptr;
}
if (attachmentLoader) {
delete attachmentLoader;
attachmentLoader = nullptr;
}
}
SkeletonData *data = nullptr;
Atlas *atlas = nullptr;
AttachmentLoader *attachmentLoader = nullptr;
std::vector<int> texturesIndex;
};
} // namespace spine
SkeletonDataMgr *SkeletonDataMgr::instance = nullptr;
SkeletonDataMgr::~SkeletonDataMgr() {
_destroyCallback = nullptr;
for (auto &e : _dataMap) {
delete e.second;
}
_dataMap.clear();
}
bool SkeletonDataMgr::hasSkeletonData(const std::string &uuid) {
auto it = _dataMap.find(uuid);
return it != _dataMap.end();
}
void SkeletonDataMgr::setSkeletonData(const std::string &uuid, SkeletonData *data, Atlas *atlas, AttachmentLoader *attachmentLoader, const std::vector<int> &texturesIndex) {
auto it = _dataMap.find(uuid);
if (it != _dataMap.end()) {
releaseByUUID(uuid);
}
auto *info = new SkeletonDataInfo();
info->data = data;
info->atlas = atlas;
info->attachmentLoader = attachmentLoader;
info->texturesIndex = texturesIndex;
_dataMap[uuid] = info;
}
SkeletonData *SkeletonDataMgr::retainByUUID(const std::string &uuid) {
auto dataIt = _dataMap.find(uuid);
if (dataIt == _dataMap.end()) {
return nullptr;
}
return dataIt->second->data;
}
void SkeletonDataMgr::releaseByUUID(const std::string &uuid) {
auto dataIt = _dataMap.find(uuid);
if (dataIt == _dataMap.end()) {
return;
}
SkeletonDataInfo *info = dataIt->second;
_dataMap.erase(dataIt);
if (_destroyCallback) {
for (auto &item : info->texturesIndex) {
_destroyCallback(item);
}
}
delete info;
}

View File

@@ -0,0 +1,84 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma once
#include <functional>
#include <map>
#include <string>
#include <vector>
#include "base/RefCounted.h"
#include "spine/SkeletonData.h"
#include "spine/spine.h"
namespace spine {
class SkeletonDataInfo;
/**
* Cache skeleton data.
*/
class SkeletonDataMgr final {
public:
static SkeletonDataMgr *getInstance() {
if (instance == nullptr) {
instance = new SkeletonDataMgr();
}
return instance;
}
static void destroyInstance() {
if (instance) {
delete instance;
instance = nullptr;
}
}
SkeletonDataMgr() = default;
~SkeletonDataMgr();
bool hasSkeletonData(const std::string &uuid);
void setSkeletonData(const std::string &uuid, SkeletonData *data, Atlas *atlas, AttachmentLoader *attachmentLoader, const std::vector<int> &texturesIndex);
// equal to 'findByUUID'
SkeletonData *retainByUUID(const std::string &uuid);
// equal to 'deleteByUUID'
void releaseByUUID(const std::string &uuid);
using destroyCallback = std::function<void(int)>;
void setDestroyCallback(destroyCallback callback) {
_destroyCallback = std::move(callback);
}
private:
static SkeletonDataMgr *instance;
destroyCallback _destroyCallback = nullptr;
std::map<std::string, SkeletonDataInfo *> _dataMap;
};
} // namespace spine

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,192 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma once
#include <vector>
#include "IOTypedArray.h"
#include "MiddlewareManager.h"
#include "Object.h"
#include "base/Macros.h"
#include "base/RefCounted.h"
#include "base/RefMap.h"
#include "core/assets/Texture2D.h"
#include "middleware-adapter.h"
#include "spine-creator-support/VertexEffectDelegate.h"
#include "spine/spine.h"
namespace cc {
class RenderEntity;
class RenderDrawInfo;
class Material;
}; // namespace cc
namespace spine {
class AttachmentVertices;
/** Draws a skeleton.
*/
class SkeletonRenderer : public cc::RefCounted, public cc::middleware::IMiddleware {
public:
static SkeletonRenderer *create();
static SkeletonRenderer *createWithSkeleton(Skeleton *skeleton, bool ownsSkeleton = false, bool ownsSkeletonData = false);
static SkeletonRenderer *createWithData(SkeletonData *skeletonData, bool ownsSkeletonData = false);
static SkeletonRenderer *createWithFile(const std::string &skeletonDataFile, const std::string &atlasFile, float scale = 1);
void update(float deltaTime) override {}
void render(float deltaTime) override;
virtual cc::Rect getBoundingBox() const;
Skeleton *getSkeleton() const;
void setTimeScale(float scale);
float getTimeScale() const;
void updateWorldTransform();
void setToSetupPose();
void setBonesToSetupPose();
void setSlotsToSetupPose();
void paused(bool value);
/* Returns 0 if the bone was not found. */
Bone *findBone(const std::string &boneName) const;
/* Returns 0 if the slot was not found. */
Slot *findSlot(const std::string &slotName) const;
/* Sets the skin used to look up attachments not found in the SkeletonData defaultSkin. Attachments from the new skin are
* attached if the corresponding attachment from the old skin was attached.
* @param skin May be empty string ("") for no skin.*/
void setSkin(const std::string &skinName);
/** @param skin May be 0 for no skin.*/
void setSkin(const char *skinName);
/* Returns 0 if the slot or attachment was not found. */
Attachment *getAttachment(const std::string &slotName, const std::string &attachmentName) const;
/* Returns false if the slot or attachment was not found.
* @param attachmentName May be empty string ("") for no attachment. */
bool setAttachment(const std::string &slotName, const std::string &attachmentName);
/* @param attachmentName May be 0 for no attachment. */
bool setAttachment(const std::string &slotName, const char *attachmentName);
/* Enables/disables two color tinting for this instance. May break batching */
void setUseTint(bool enabled);
/* Sets the vertex effect to be used, set to 0 to disable vertex effects */
void setVertexEffectDelegate(VertexEffectDelegate *effectDelegate);
/* Sets the range of slots that should be rendered. Use -1, -1 to clear the range */
void setSlotsRange(int startSlotIndex, int endSlotIndex);
/**
* @return debug data, it's a Float32Array,
* format |debug bones length|[beginX|beginY|toX|toY|...loop...]
*/
se_object_ptr getDebugData() const;
/**
* @return shared buffer offset, it's a Uint32Array
* format |render info offset|attach info offset|
*/
se_object_ptr getSharedBufferOffset() const;
void setColor(float r, float g, float b, float a);
void setBatchEnabled(bool enabled);
void setDebugBonesEnabled(bool enabled);
void setDebugSlotsEnabled(bool enabled);
void setDebugMeshEnabled(bool enabled);
void setAttachEnabled(bool enabled);
void setOpacityModifyRGB(bool value);
bool isOpacityModifyRGB() const;
virtual void beginSchedule();
virtual void stopSchedule();
void onEnable();
void onDisable();
SkeletonRenderer();
explicit SkeletonRenderer(Skeleton *skeleton, bool ownsSkeleton = false, bool ownsSkeletonData = false, bool ownsAtlas = false);
explicit SkeletonRenderer(SkeletonData *skeletonData, bool ownsSkeletonData = false);
SkeletonRenderer(const std::string &skeletonDataFile, const std::string &atlasFile, float scale = 1);
~SkeletonRenderer() override;
void initWithUUID(const std::string &uuid);
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();
cc::RenderDrawInfo *requestDrawInfo(int idx);
cc::Material *requestMaterial(uint16_t blendSrc, uint16_t blendDst);
void setMaterial(cc::Material *material);
void setRenderEntity(cc::RenderEntity *entity);
void setSlotTexture(const std::string &slotName, cc::Texture2D *tex2d, bool createAttachment);
protected:
void setSkeletonData(SkeletonData *skeletonData, bool ownsSkeletonData);
bool _ownsSkeletonData = false;
bool _ownsSkeleton = false;
bool _ownsAtlas = false;
Atlas *_atlas = nullptr;
AttachmentLoader *_attachmentLoader = nullptr;
Skeleton *_skeleton = nullptr;
VertexEffectDelegate *_effectDelegate = nullptr;
float _timeScale = 1;
bool _paused = false;
bool _useAttach = false;
bool _debugMesh = false;
bool _debugSlots = false;
bool _debugBones = false;
cc::middleware::Color4F _nodeColor = cc::middleware::Color4F::WHITE;
bool _premultipliedAlpha = false;
SkeletonClipping *_clipper = nullptr;
bool _useTint = false;
bool _enableBatch = false;
std::string _uuid;
int _startSlotIndex = -1;
int _endSlotIndex = -1;
cc::middleware::IOTypedArray *_sharedBufferOffset = nullptr;
cc::middleware::IOTypedArray *_debugBuffer = nullptr;
cc::RenderEntity *_entity = nullptr;
cc::Material *_material = nullptr;
ccstd::vector<cc::RenderDrawInfo *> _drawInfoArray;
ccstd::unordered_map<uint32_t, cc::Material *> _materialCaches;
};
} // namespace spine

View File

@@ -0,0 +1,48 @@
#include "Vector2.h"
#include <math.h>
namespace spine {
Vector2::Vector2(): x(0), y(0) {
}
Vector2::Vector2(float x, float y) {
this->x = x;
this->y = y;
}
Vector2::~Vector2() {}
void Vector2::setX(float x) {
this->x = x;
}
float Vector2::getX() {
return x;
}
void Vector2::setY(float y) {
this->y = y;
}
float Vector2::getY() {
return y;
}
Vector2& Vector2::set(float x, float y) {
this->setX(x);
this->setY(y);
return *this;
}
float Vector2::length() {
return sqrt(x * x + y * y);
}
Vector2& Vector2::normalize() {
float invLen = 1.F / length();
this->setX(x * invLen);
this->setY(y * invLen);
return *this;
}
}

View File

@@ -0,0 +1,54 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma once
#include "spine/spine.h"
namespace spine {
class Vector2
{
public:
float x, y;
public:
Vector2();
Vector2(float x, float y);
~Vector2();
void setX(float x);
float getX();
void setY(float y);
float getY();
Vector2 &set(float x, float y);
float length();
Vector2 &normalize();
};
}

View File

@@ -0,0 +1,84 @@
/******************************************************************************
* 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 "VertexEffectDelegate.h"
namespace spine {
VertexEffectDelegate::VertexEffectDelegate() {
}
VertexEffectDelegate::~VertexEffectDelegate() {
clear();
}
void VertexEffectDelegate::clear() {
if (_interpolation) {
delete _interpolation;
_interpolation = nullptr;
}
if (_vertexEffect) {
delete _vertexEffect;
_vertexEffect = nullptr;
}
_effectType = "none";
}
JitterVertexEffect *VertexEffectDelegate::initJitter(float jitterX, float jitterY) {
clear();
_vertexEffect = new JitterVertexEffect(jitterX, jitterY);
_effectType = "jitter";
return (JitterVertexEffect *)_vertexEffect;
}
SwirlVertexEffect *VertexEffectDelegate::initSwirlWithPow(float radius, int power) {
clear();
_interpolation = new PowInterpolation(power);
_vertexEffect = new SwirlVertexEffect(radius, *_interpolation);
_effectType = "swirl";
return (SwirlVertexEffect *)_vertexEffect;
}
SwirlVertexEffect *VertexEffectDelegate::initSwirlWithPowOut(float radius, int power) {
clear();
_interpolation = new PowOutInterpolation(power);
_vertexEffect = new SwirlVertexEffect(radius, *_interpolation);
_effectType = "swirl";
return (SwirlVertexEffect *)_vertexEffect;
}
JitterVertexEffect *VertexEffectDelegate::getJitterVertexEffect() {
JitterVertexEffect *jitter = dynamic_cast<JitterVertexEffect *>(_vertexEffect);
return jitter;
}
SwirlVertexEffect *VertexEffectDelegate::getSwirlVertexEffect() {
SwirlVertexEffect *swirl = dynamic_cast<SwirlVertexEffect *>(_vertexEffect);
return swirl;
}
} // namespace spine

View File

@@ -0,0 +1,59 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma once
#include <string>
#include "base/RefCounted.h"
#include "spine/spine.h"
namespace spine {
class VertexEffectDelegate : public cc::RefCounted {
public:
VertexEffectDelegate();
~VertexEffectDelegate() override;
JitterVertexEffect *initJitter(float jitterX, float jitterY);
SwirlVertexEffect *initSwirlWithPow(float radius, int power);
SwirlVertexEffect *initSwirlWithPowOut(float radius, int power);
VertexEffect *getVertexEffect() {
return _vertexEffect;
}
JitterVertexEffect *getJitterVertexEffect();
SwirlVertexEffect *getSwirlVertexEffect();
const std::string &getEffectType() const {
return _effectType;
}
void clear();
private:
VertexEffect *_vertexEffect = nullptr;
Interpolation *_interpolation = nullptr;
std::string _effectType = "none";
};
} // namespace spine

View File

@@ -0,0 +1,152 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2019, 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.
*
* 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.
*****************************************************************************/
#include "spine-creator-support/spine-cocos2dx.h"
#include "base/Data.h"
#include "middleware-adapter.h"
#include "platform/FileUtils.h"
#include "spine-creator-support/AttachmentVertices.h"
namespace spine {
static CustomTextureLoader customTextureLoader = nullptr;
void spAtlasPage_setCustomTextureLoader(CustomTextureLoader texLoader) {
customTextureLoader = texLoader;
}
static SpineObjectDisposeCallback spineObjectDisposeCallback = nullptr;
void setSpineObjectDisposeCallback(SpineObjectDisposeCallback callback) {
spineObjectDisposeCallback = callback;
}
} // namespace spine
USING_NS_MW; // NOLINT(google-build-using-namespace)
using namespace cc; // NOLINT(google-build-using-namespace)
using namespace spine; // NOLINT(google-build-using-namespace)
static void deleteAttachmentVertices(void *vertices) {
delete static_cast<AttachmentVertices *>(vertices);
}
static uint16_t quadTriangles[6] = {0, 1, 2, 2, 3, 0};
static void setAttachmentVertices(RegionAttachment *attachment) {
auto *region = static_cast<AtlasRegion *>(attachment->getRendererObject());
auto *attachmentVertices = new AttachmentVertices(static_cast<middleware::Texture2D *>(region->page->getRendererObject()), 4, quadTriangles, 6);
V3F_T2F_C4B *vertices = attachmentVertices->_triangles->verts;
for (int i = 0, ii = 0; i < 4; ++i, ii += 2) {
vertices[i].texCoord.u = attachment->getUVs()[ii];
vertices[i].texCoord.v = attachment->getUVs()[ii + 1];
}
attachment->setRendererObject(attachmentVertices, deleteAttachmentVertices);
}
static void setAttachmentVertices(MeshAttachment *attachment) {
auto *region = static_cast<AtlasRegion *>(attachment->getRendererObject());
auto *attachmentVertices = new AttachmentVertices(static_cast<middleware::Texture2D *>(region->page->getRendererObject()),
static_cast<int32_t>(attachment->getWorldVerticesLength() >> 1), attachment->getTriangles().buffer(), static_cast<int32_t>(attachment->getTriangles().size()));
V3F_T2F_C4B *vertices = attachmentVertices->_triangles->verts;
for (size_t i = 0, ii = 0, nn = attachment->getWorldVerticesLength(); ii < nn; ++i, ii += 2) {
vertices[i].texCoord.u = attachment->getUVs()[ii];
vertices[i].texCoord.v = attachment->getUVs()[ii + 1];
}
attachment->setRendererObject(attachmentVertices, deleteAttachmentVertices);
}
Cocos2dAtlasAttachmentLoader::Cocos2dAtlasAttachmentLoader(Atlas *atlas) : AtlasAttachmentLoader(atlas) {
}
Cocos2dAtlasAttachmentLoader::~Cocos2dAtlasAttachmentLoader() = default;
void Cocos2dAtlasAttachmentLoader::configureAttachment(Attachment *attachment) {
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
setAttachmentVertices(dynamic_cast<RegionAttachment *>(attachment));
} else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
setAttachmentVertices(dynamic_cast<MeshAttachment *>(attachment));
}
}
uint32_t wrap(TextureWrap wrap) {
return static_cast<uint32_t>(wrap);
}
uint32_t filter(TextureFilter filter) {
return static_cast<uint32_t>(filter);
}
Cocos2dTextureLoader::Cocos2dTextureLoader() = default;
Cocos2dTextureLoader::~Cocos2dTextureLoader() = default;
void Cocos2dTextureLoader::load(AtlasPage &page, const spine::String &path) {
middleware::Texture2D *texture = nullptr;
if (spine::customTextureLoader) {
texture = spine::customTextureLoader(path.buffer());
}
CC_ASSERT_NOT_NULL(texture);
if (texture) {
texture->addRef();
middleware::Texture2D::TexParams textureParams = {filter(page.minFilter), filter(page.magFilter), wrap(page.uWrap), wrap(page.vWrap)};
texture->setTexParameters(textureParams);
page.setRendererObject(texture);
page.width = texture->getPixelsWide();
page.height = texture->getPixelsHigh();
}
}
void Cocos2dTextureLoader::unload(void *texture) {
if (texture) {
(static_cast<middleware::Texture2D *>(texture))->release();
}
}
Cocos2dExtension::Cocos2dExtension() = default;
Cocos2dExtension::~Cocos2dExtension() = default;
char *Cocos2dExtension::_readFile(const spine::String &path, int *length) {
*length = 0;
Data data = FileUtils::getInstance()->getDataFromFile(FileUtils::getInstance()->fullPathForFilename(path.buffer()));
if (data.isNull()) return nullptr;
char *ret = static_cast<char *>(malloc(sizeof(unsigned char) * data.getSize()));
memcpy(ret, reinterpret_cast<char *>(data.getBytes()), data.getSize());
*length = static_cast<int>(data.getSize());
return ret;
}
SpineExtension *spine::getDefaultExtension() {
return new Cocos2dExtension();
}
void Cocos2dExtension::_free(void *mem, const char *file, int line) {
spineObjectDisposeCallback(mem);
DefaultSpineExtension::_free(mem, file, line);
}

View File

@@ -0,0 +1,77 @@
/******************************************************************************
* 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.
*****************************************************************************/
#pragma once
#include "middleware-adapter.h"
#include "spine-creator-support/SkeletonAnimation.h"
#include "spine-creator-support/SkeletonCacheAnimation.h"
#include "spine-creator-support/SkeletonCacheMgr.h"
#include "spine-creator-support/SkeletonDataMgr.h"
#include "spine-creator-support/SkeletonRenderer.h"
#include "spine/spine.h"
namespace spine {
typedef cc::middleware::Texture2D *(*CustomTextureLoader)(const char *path);
// set custom texture loader for _spAtlasPage_createTexture
void spAtlasPage_setCustomTextureLoader(CustomTextureLoader texLoader);
class Cocos2dAtlasAttachmentLoader : public AtlasAttachmentLoader {
public:
Cocos2dAtlasAttachmentLoader(Atlas *atlas);
virtual ~Cocos2dAtlasAttachmentLoader();
virtual void configureAttachment(Attachment *attachment);
};
class Cocos2dTextureLoader : public TextureLoader {
public:
Cocos2dTextureLoader();
virtual ~Cocos2dTextureLoader();
virtual void load(AtlasPage &page, const String &path);
virtual void unload(void *texture);
};
class Cocos2dExtension : public DefaultSpineExtension {
public:
Cocos2dExtension();
virtual ~Cocos2dExtension();
virtual void _free(void *mem, const char *file, int line);
protected:
virtual char *_readFile(const String &path, int *length);
};
typedef void (*SpineObjectDisposeCallback)(void *);
void setSpineObjectDisposeCallback(SpineObjectDisposeCallback callback);
} // namespace spine