#include "CCArmatureDisplay.h" #include "CCSlot.h" DRAGONBONES_NAMESPACE_BEGIN CCArmatureDisplay* CCArmatureDisplay::create() { CCArmatureDisplay* displayContainer = new (std::nothrow) CCArmatureDisplay(); if (displayContainer && displayContainer->init()) if (displayContainer) { displayContainer->autorelease(); } else { CC_SAFE_DELETE(displayContainer); } return displayContainer; } void CCArmatureDisplay::dbInit(Armature* armature) { _armature = armature; } void CCArmatureDisplay::dbClear() { setEventDispatcher(cocos2d::Director::getInstance()->getEventDispatcher()); _armature = nullptr; CC_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(const std::string& type, const std::function& callback) { auto lambda = [callback](cocos2d::EventCustom* event) -> void { callback(static_cast(event->getUserData())); }; _dispatcher->addCustomEventListener(type, lambda); } void CCArmatureDisplay::dispatchDBEvent(const std::string& type, EventObject* value) { _dispatcher->dispatchCustomEvent(type, value); } void CCArmatureDisplay::removeDBEventListener(const std::string& type, const std::function& callback) { // TODO _dispatcher->removeCustomEventListeners(type); } cocos2d::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(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()); } } cocos2d::Rect rect(minX, minY, maxX - minX, maxY - minY); return cocos2d::RectApplyTransform(rect, getNodeToParentTransform()); } DBCCSprite* DBCCSprite::create() { DBCCSprite* sprite = new (std::nothrow) DBCCSprite(); if (sprite && sprite->init()) { sprite->autorelease(); } else { CC_SAFE_DELETE(sprite); } return sprite; } bool DBCCSprite::_checkVisibility(const cocos2d::Mat4& transform, const cocos2d::Size& size, const cocos2d::Rect& rect) { auto scene = cocos2d::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() != cocos2d::Camera::getVisitingCamera())) return true; auto director = cocos2d::Director::getInstance(); cocos2d::Rect visiableRect(director->getVisibleOrigin(), director->getVisibleSize()); // transform center point to screen space float hSizeX = size.width / 2; float hSizeY = size.height / 2; cocos2d::Vec3 v3p(hSizeX, hSizeY, 0); transform.transformPoint(&v3p); cocos2d::Vec2 v2p = cocos2d::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(cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t flags) { #if CC_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 = cocos2d::Camera::getVisitingCamera(); auto defaultCamera = cocos2d::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 { _trianglesCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, _polyInfo.triangles, transform, flags); renderer->addCommand(&_trianglesCommand); #if CC_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(cocos2d::Vec2(from.x, from.y), cocos2d::Vec2(to.x, to.y), cocos2d::Color4F::WHITE); from = verts[indices[i * 3 + 1]].vertices; to = verts[indices[i * 3 + 2]].vertices; _debugDrawNode->drawLine(cocos2d::Vec2(from.x, from.y), cocos2d::Vec2(to.x, to.y), cocos2d::Color4F::WHITE); from = verts[indices[i * 3 + 2]].vertices; to = verts[indices[i * 3]].vertices; _debugDrawNode->drawLine(cocos2d::Vec2(from.x, from.y), cocos2d::Vec2(to.x, to.y), cocos2d::Color4F::WHITE); } #endif //CC_SPRITE_DEBUG_DRAW } } cocos2d::PolygonInfo& DBCCSprite::getPolygonInfoModify() { return _polyInfo; } DRAGONBONES_NAMESPACE_END