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.
 
 
 
 
 
 

464 lines
16 KiB

/****************************************************************************
Copyright (c) 2012-2020 DragonBones team and other contributors
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "CCArmatureCacheDisplay.h"
#include "2d/renderer/RenderDrawInfo.h"
#include "2d/renderer/RenderEntity.h"
#include "ArmatureCacheMgr.h"
#include "CCFactory.h"
#include "MiddlewareManager.h"
#include "SharedBufferManager.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 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";
static const std::string START_EVENT = "start";
static const std::string LOOP_COMPLETE_EVENT = "loopComplete";
static const std::string COMPLETE_EVENT = "complete";
DRAGONBONES_NAMESPACE_BEGIN
USING_NS_MW; // NOLINT(google-build-using-namespace)
CCArmatureCacheDisplay::CCArmatureCacheDisplay(const std::string &armatureName, const std::string &armatureKey, const std::string &atlasUUID, bool isShare) {
_eventObject = BaseObject::borrowObject<EventObject>();
if (isShare) {
_armatureCache = ArmatureCacheMgr::getInstance()->buildArmatureCache(armatureName, armatureKey, atlasUUID);
_armatureCache->addRef();
} else {
_armatureCache = new ArmatureCache(armatureName, armatureKey, atlasUUID);
_armatureCache->addRef();
}
// store global TypedArray begin and end offset
_sharedBufferOffset = new IOTypedArray(se::Object::TypedArrayType::UINT32, sizeof(uint32_t) * 2);
}
CCArmatureCacheDisplay::~CCArmatureCacheDisplay() {
dispose();
if (_sharedBufferOffset) {
delete _sharedBufferOffset;
_sharedBufferOffset = nullptr;
}
for (auto *draw : _drawInfoArray) {
CC_SAFE_DELETE(draw);
}
for (auto &item : _materialCaches) {
CC_SAFE_DELETE(item.second);
}
}
void CCArmatureCacheDisplay::dispose() {
if (_armatureCache) {
_armatureCache->release();
_armatureCache = nullptr;
}
if (_eventObject) {
_eventObject->returnToPool();
_eventObject = nullptr;
}
stopSchedule();
}
void CCArmatureCacheDisplay::update(float dt) {
auto gTimeScale = dragonBones::CCFactory::getFactory()->getTimeScale();
dt *= _timeScale * gTimeScale;
if (_isAniComplete || !_animationData) {
if (_animationData && !_animationData->isComplete()) {
_armatureCache->updateToFrame(_animationName);
}
return;
}
if (_accTime <= 0.00001 && _playCount == 0) {
_eventObject->type = EventObject::START;
dispatchDBEvent(START_EVENT, _eventObject);
}
_accTime += dt;
int frameIdx = floor(_accTime / ArmatureCache::FrameTime);
if (!_animationData->isComplete()) {
_armatureCache->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;
}
_eventObject->type = EventObject::COMPLETE;
dispatchDBEvent(COMPLETE_EVENT, _eventObject);
_eventObject->type = EventObject::LOOP_COMPLETE;
dispatchDBEvent(LOOP_COMPLETE_EVENT, _eventObject);
}
_curFrameIndex = frameIdx;
}
void CCArmatureCacheDisplay::render(float /*dt*/) {
if (!_animationData) return;
ArmatureCache::FrameData *frameData = _animationData->getFrameData(_curFrameIndex);
if (!frameData) return;
auto *mgr = MiddlewareManager::getInstance();
if (!mgr->isRendering) return;
auto *entity = _entity;
entity->clearDynamicRenderDrawInfos();
const auto &segments = frameData->getSegments();
const auto &colors = frameData->getColors();
_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));
if (segments.empty() || colors.empty()) return;
middleware::MeshBuffer *mb = mgr->getMeshBuffer(VF_XYZUVC);
middleware::IOBuffer &vb = mb->getVB();
middleware::IOBuffer &ib = mb->getIB();
const auto &srcVB = frameData->vb;
const auto &srcIB = frameData->ib;
auto &nodeWorldMat = entity->getNode()->getWorldMatrix();
int colorOffset = 0;
ArmatureCache::ColorData *nowColor = colors[colorOffset++];
auto maxVFOffset = nowColor->vertexFloatOffset;
Color4B color;
float tempR = 0.0F;
float tempG = 0.0F;
float tempB = 0.0F;
float tempA = 0.0F;
float multiplier = 1.0F;
std::size_t srcVertexBytesOffset = 0;
std::size_t srcIndexBytesOffset = 0;
std::size_t vertexBytes = 0;
std::size_t indexBytes = 0;
BlendMode blendMode = BlendMode::Normal;
std::size_t dstVertexOffset = 0;
std::size_t 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 = [&](ArmatureCache::ColorData *colorData) {
tempA = colorData->color.a * _nodeColor.a;
multiplier = _premultipliedAlpha ? tempA / 255.0f : 1.0f;
tempR = _nodeColor.r * multiplier;
tempG = _nodeColor.g * multiplier;
tempB = _nodeColor.b * multiplier;
color.a = (uint8_t)floorf(tempA);
color.r = (uint8_t)floorf(colorData->color.r * tempR);
color.g = (uint8_t)floorf(colorData->color.g * tempG);
color.b = (uint8_t)floorf(colorData->color.b * tempB);
};
handleColor(nowColor);
int segmentCount = 0;
for (auto *segment : segments) {
vertexBytes = segment->vertexFloatCount * sizeof(float);
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 = static_cast<BlendMode>(segment->blendMode);
switch (blendMode) {
case BlendMode::Add:
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);
break;
}
// fill new blend src and dst
auto *material = requestMaterial(curBlendSrc, curBlendDst);
curDrawInfo->setMaterial(material);
// fill vertex buffer
vb.checkSpace(vertexBytes, true);
dstVertexOffset = vb.getCurPos() / sizeof(V3F_T2F_C4B);
dstVertexBuffer = reinterpret_cast<float *>(vb.getCurBuffer());
dstColorBuffer = reinterpret_cast<unsigned int *>(vb.getCurBuffer());
vb.writeBytes(reinterpret_cast<char *>(srcVB.getBuffer()) + srcVertexBytesOffset, vertexBytes);
// batch handle
cc::Vec3 *point = nullptr;
for (auto posIndex = 0; posIndex < segment->vertexFloatCount; posIndex += VF_XYZUVC) {
point = reinterpret_cast<cc::Vec3 *>(dstVertexBuffer + posIndex);
point->z = 0;
point->transformMat4(*point, nodeWorldMat);
}
// handle vertex color
if (needColor) {
auto frameFloatOffset = srcVertexBytesOffset / sizeof(float);
for (auto colorIndex = 0; colorIndex < segment->vertexFloatCount; colorIndex += VF_XYZUVC, frameFloatOffset += VF_XYZUVC) {
if (frameFloatOffset >= maxVFOffset) {
nowColor = colors[colorOffset++];
handleColor(nowColor);
maxVFOffset = nowColor->vertexFloatOffset;
}
memcpy(dstColorBuffer + colorIndex + 5, &color, sizeof(color));
}
}
// move src vertex buffer offset
srcVertexBytesOffset += vertexBytes;
// fill index buffer
indexBytes = segment->indexCount * sizeof(uint16_t);
ib.checkSpace(indexBytes, true);
dstIndexOffset = static_cast<int>(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 (int i = 0; i < boneCount; i++) {
auto *bone = bonesData[i];
attachInfo->checkSpace(sizeof(cc::Mat4), true);
attachInfo->writeBytes(reinterpret_cast<const char *>(&bone->globalTransformMatrix), sizeof(cc::Mat4));
}
}
}
void CCArmatureCacheDisplay::beginSchedule() {
MiddlewareManager::getInstance()->addTimer(this);
}
void CCArmatureCacheDisplay::stopSchedule() {
MiddlewareManager::getInstance()->removeTimer(this);
if (_sharedBufferOffset) {
_sharedBufferOffset->reset();
_sharedBufferOffset->clear();
}
}
void CCArmatureCacheDisplay::onEnable() {
beginSchedule();
}
void CCArmatureCacheDisplay::onDisable() {
stopSchedule();
}
Armature *CCArmatureCacheDisplay::getArmature() const {
auto *armatureDisplay = _armatureCache->getArmatureDisplay();
return armatureDisplay->getArmature();
}
Animation *CCArmatureCacheDisplay::getAnimation() const {
auto *armature = getArmature();
return armature->getAnimation();
}
void CCArmatureCacheDisplay::playAnimation(const std::string &name, int playTimes) {
_playTimes = playTimes;
_animationName = name;
_animationData = _armatureCache->buildAnimationData(_animationName);
_isAniComplete = false;
_accTime = 0.0F;
_playCount = 0;
_curFrameIndex = 0;
}
void CCArmatureCacheDisplay::addDBEventListener(const std::string &type) {
_listenerIDMap[type] = true;
}
void CCArmatureCacheDisplay::removeDBEventListener(const std::string &type) {
auto it = _listenerIDMap.find(type);
if (it != _listenerIDMap.end()) {
_listenerIDMap.erase(it);
}
}
void CCArmatureCacheDisplay::dispatchDBEvent(const std::string &type, EventObject *value) {
auto it = _listenerIDMap.find(type);
if (it == _listenerIDMap.end()) {
return;
}
if (_dbEventCallback) {
_dbEventCallback(value);
}
}
void CCArmatureCacheDisplay::updateAnimationCache(const std::string &animationName) {
_armatureCache->resetAnimationData(animationName);
}
void CCArmatureCacheDisplay::updateAllAnimationCache() {
_armatureCache->resetAllAnimationData();
}
void CCArmatureCacheDisplay::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 CCArmatureCacheDisplay::setAttachEnabled(bool enabled) {
_useAttach = enabled;
}
void CCArmatureCacheDisplay::setBatchEnabled(bool enabled) {
if (enabled != _enableBatch) {
for (auto &item : _materialCaches) {
CC_SAFE_DELETE(item.second);
}
_materialCaches.clear();
_enableBatch = enabled;
}
}
se_object_ptr CCArmatureCacheDisplay::getSharedBufferOffset() const {
if (_sharedBufferOffset) {
return _sharedBufferOffset->getTypeArray();
}
return nullptr;
}
void CCArmatureCacheDisplay::setRenderEntity(cc::RenderEntity *entity) {
_entity = entity;
}
void CCArmatureCacheDisplay::setMaterial(cc::Material *material) {
_material = material;
for (auto &item : _materialCaches) {
CC_SAFE_DELETE(item.second);
}
_materialCaches.clear();
}
cc::RenderDrawInfo *CCArmatureCacheDisplay::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 *CCArmatureCacheDisplay::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{{"USE_LOCAL", false}};
materialInstance->recompileShaders(macros);
_materialCaches[key] = materialInstance;
}
return _materialCaches[key];
}
DRAGONBONES_NAMESPACE_END