You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
604 lines
21 KiB
604 lines
21 KiB
/******************************************************************************
|
|
* 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
|
|
|