axmol/extensions/DragonBones/CCArmatureDisplay.cpp

233 lines
6.7 KiB
C++

#include "CCArmatureDisplay.h"
#include "CCSlot.h"
DRAGONBONES_NAMESPACE_BEGIN
CCArmatureDisplay* CCArmatureDisplay::create()
{
CCArmatureDisplay* displayContainer = new CCArmatureDisplay();
if (displayContainer->init())
{
displayContainer->autorelease();
}
else
{
AX_SAFE_DELETE(displayContainer);
}
return displayContainer;
}
void CCArmatureDisplay::dbInit(Armature* armature)
{
_armature = armature;
}
void CCArmatureDisplay::dbClear()
{
setEventDispatcher(ax::Director::getInstance()->getEventDispatcher());
_armature = nullptr;
AX_SAFE_RELEASE(_dispatcher);
release();
}
void CCArmatureDisplay::dispose(bool disposeProxy)
{
if (_armature != nullptr)
{
_armature->dispose();
_armature = nullptr;
}
}
void CCArmatureDisplay::dbUpdate()
{
const auto drawed = DragonBones::debugDraw;
if (drawed || _debugDraw)
{
_debugDraw = drawed;
if (_debugDraw)
{}
else
{
// TODO
}
}
}
void CCArmatureDisplay::addDBEventListener(std::string_view type, const std::function<void(EventObject*)>& callback)
{
auto lambda = [callback](ax::EventCustom* event) -> void {
callback(static_cast<EventObject*>(event->getUserData()));
};
_dispatcher->addCustomEventListener(type, lambda);
}
void CCArmatureDisplay::dispatchDBEvent(std::string_view type, EventObject* value)
{
_dispatcher->dispatchCustomEvent(type, value);
}
void CCArmatureDisplay::removeDBEventListener(std::string_view type, const std::function<void(EventObject*)>& callback)
{
// TODO
_dispatcher->removeCustomEventListeners(type);
}
ax::Rect CCArmatureDisplay::getBoundingBox() const
{
auto isFirst = true;
float minX = 0.0f;
float minY = 0.0f;
float maxX = 0.0f;
float maxY = 0.0f;
for (const auto slot : _armature->getSlots())
{
if (!slot->getVisible() || !slot->getDisplay())
{
continue;
}
const auto display = static_cast<CCSlot*>(slot)->getCCDisplay();
const auto bounds = display->getBoundingBox();
if (isFirst)
{
isFirst = false;
minX = bounds.getMinX();
minY = bounds.getMinY();
maxX = bounds.getMaxX();
maxY = bounds.getMaxY();
}
else
{
minX = std::min(minX, bounds.getMinX());
minY = std::min(minY, bounds.getMinY());
maxX = std::max(maxX, bounds.getMaxX());
maxY = std::max(maxY, bounds.getMaxY());
}
}
ax::Rect rect(minX, minY, maxX - minX, maxY - minY);
return ax::RectApplyTransform(rect, getNodeToParentTransform());
}
DBCCSprite* DBCCSprite::create()
{
DBCCSprite* sprite = new DBCCSprite();
if (sprite->init())
{
sprite->autorelease();
}
else
{
AX_SAFE_DELETE(sprite);
}
return sprite;
}
bool DBCCSprite::_checkVisibility(const ax::Mat4& transform, const ax::Size& size, const ax::Rect& rect)
{
auto scene = ax::Director::getInstance()->getRunningScene();
// If draw to Rendertexture, return true directly.
// only cull the default camera. The culling algorithm is valid for default camera.
if (!scene || (scene && scene->getDefaultCamera() != ax::Camera::getVisitingCamera()))
return true;
auto director = ax::Director::getInstance();
ax::Rect visiableRect(director->getVisibleOrigin(), director->getVisibleSize());
// transform center point to screen space
float hSizeX = size.width / 2;
float hSizeY = size.height / 2;
ax::Vec3 v3p(hSizeX, hSizeY, 0);
transform.transformPoint(&v3p);
ax::Vec2 v2p = ax::Camera::getVisitingCamera()->projectGL(v3p);
// convert content size to world coordinates
float wshw = std::max(fabsf(hSizeX * transform.m[0] + hSizeY * transform.m[4]),
fabsf(hSizeX * transform.m[0] - hSizeY * transform.m[4]));
float wshh = std::max(fabsf(hSizeX * transform.m[1] + hSizeY * transform.m[5]),
fabsf(hSizeX * transform.m[1] - hSizeY * transform.m[5]));
// enlarge visible rect half size in screen coord
visiableRect.origin.x -= wshw;
visiableRect.origin.y -= wshh;
visiableRect.size.width += wshw * 2;
visiableRect.size.height += wshh * 2;
bool ret = visiableRect.containsPoint(v2p);
return ret;
}
void DBCCSprite::draw(ax::Renderer* renderer, const ax::Mat4& transform, uint32_t flags)
{
#if AX_USE_CULLING
# if COCOS2D_VERSION >= 0x00031400
const auto& rect = _polyInfo.getRect();
# else
const auto& rect = _polyInfo.rect;
# endif
// Don't do calculate the culling if the transform was not updated
auto visitingCamera = ax::Camera::getVisitingCamera();
auto defaultCamera = ax::Camera::getDefaultCamera();
if (visitingCamera == defaultCamera)
{
_insideBounds = ((flags & FLAGS_TRANSFORM_DIRTY) || visitingCamera->isViewProjectionUpdated())
? _checkVisibility(transform, _contentSize, rect)
: _insideBounds;
}
else
{
_insideBounds = _checkVisibility(transform, _contentSize, rect);
}
if (_insideBounds)
#endif
{
#if COCOS2D_VERSION >= 0x00040000
_trianglesCommand.init(_globalZOrder, _texture, _blendFunc, _polyInfo.triangles, transform, flags);
#else
_trianglesCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, _polyInfo.triangles,
transform, flags);
#endif
renderer->addCommand(&_trianglesCommand);
#if AX_SPRITE_DEBUG_DRAW
_debugDrawNode->clear();
auto count = _polyInfo.triangles.indexCount / 3;
auto indices = _polyInfo.triangles.indices;
auto verts = _polyInfo.triangles.verts;
for (ssize_t i = 0; i < count; i++)
{
// draw 3 lines
auto from = verts[indices[i * 3]].vertices;
auto to = verts[indices[i * 3 + 1]].vertices;
_debugDrawNode->drawLine(ax::Vec2(from.x, from.y), ax::Vec2(to.x, to.y), ax::Color4F::WHITE);
from = verts[indices[i * 3 + 1]].vertices;
to = verts[indices[i * 3 + 2]].vertices;
_debugDrawNode->drawLine(ax::Vec2(from.x, from.y), ax::Vec2(to.x, to.y), ax::Color4F::WHITE);
from = verts[indices[i * 3 + 2]].vertices;
to = verts[indices[i * 3]].vertices;
_debugDrawNode->drawLine(ax::Vec2(from.x, from.y), ax::Vec2(to.x, to.y), ax::Color4F::WHITE);
}
#endif // AX_SPRITE_DEBUG_DRAW
}
}
ax::PolygonInfo& DBCCSprite::getPolygonInfoModify()
{
return _polyInfo;
}
DRAGONBONES_NAMESPACE_END