mirror of https://github.com/axmolengine/axmol.git
Make BoneNodes ordered in Skeleton
1. Order skins differently than bones and draw them with unified local z order 2. Check children has been remove when its ansester remove 3. Checkout cocos2d::map exists iter before remove Squashed from https://github.com/cocos2d/cocos2d-x/pull/13191
This commit is contained in:
parent
d00e54ad8a
commit
9980397081
|
@ -105,14 +105,18 @@ void BoneNode::addSkin(SkinNode* skin, bool display)
|
|||
|
||||
void BoneNode::removeChild(Node* child, bool cleanup /* = true */)
|
||||
{
|
||||
ssize_t index = _children.getIndex(child);
|
||||
if (index != cocos2d::CC_INVALID_INDEX)
|
||||
{
|
||||
Node::removeChild(child, cleanup);
|
||||
removeFromChildrenListHelper(child);
|
||||
}
|
||||
}
|
||||
|
||||
void BoneNode::removeFromBoneList(BoneNode* bone)
|
||||
{
|
||||
auto skeletonNode = dynamic_cast<SkeletonNode*>(bone);
|
||||
if (skeletonNode == nullptr) //not a nested skeleton
|
||||
if (skeletonNode == nullptr) // is not a nested skeleton
|
||||
{
|
||||
bone->_rootSkeleton = nullptr;
|
||||
auto subBones = bone->getAllSubBones();
|
||||
|
@ -120,21 +124,30 @@ void BoneNode::removeFromBoneList(BoneNode* bone)
|
|||
for (auto &subBone : subBones)
|
||||
{
|
||||
subBone->_rootSkeleton = nullptr;
|
||||
_rootSkeleton->_subBonesMap.erase(subBone->getName());
|
||||
if (bone->_isRackShow && bone->_visible)
|
||||
auto toremoveIter = _rootSkeleton->_subBonesMap.find(subBone->getName());
|
||||
if (toremoveIter != _rootSkeleton->_subBonesMap.end())
|
||||
{
|
||||
_rootSkeleton->_subDrawBonesDirty = true;
|
||||
_rootSkeleton->_subDrawBonesOrderDirty = true;
|
||||
_rootSkeleton->_subBonesMap.erase(toremoveIter);
|
||||
_rootSkeleton->_subBonesDirty = true;
|
||||
_rootSkeleton->_subBonesOrderDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_rootSkeleton->_subBonesDirty = true;
|
||||
_rootSkeleton->_subBonesOrderDirty = true;
|
||||
}
|
||||
_childBones.eraseObject(bone);
|
||||
}
|
||||
|
||||
void BoneNode::addToBoneList(BoneNode* bone)
|
||||
{
|
||||
_childBones.pushBack(bone);
|
||||
if (bone->_rootSkeleton == nullptr && _rootSkeleton != nullptr)
|
||||
if (_rootSkeleton != nullptr)
|
||||
{
|
||||
auto skeletonNode = dynamic_cast<SkeletonNode*>(bone);
|
||||
if (skeletonNode == nullptr && bone->_rootSkeleton == nullptr) // not nest skeleton
|
||||
{
|
||||
auto subBones = bone->getAllSubBones();
|
||||
subBones.pushBack(bone);
|
||||
|
@ -145,20 +158,18 @@ void BoneNode::addToBoneList(BoneNode* bone)
|
|||
if (_rootSkeleton->_subBonesMap.find(bonename) == _rootSkeleton->_subBonesMap.end())
|
||||
{
|
||||
_rootSkeleton->_subBonesMap.insert(subBone->getName(), subBone);
|
||||
if (bone->_isRackShow && bone->_visible)
|
||||
{
|
||||
_rootSkeleton->_subDrawBonesDirty = true;
|
||||
_rootSkeleton->_subDrawBonesOrderDirty = true;
|
||||
}
|
||||
|
||||
_rootSkeleton->_subBonesDirty = true;
|
||||
_rootSkeleton->_subBonesOrderDirty = true;
|
||||
}
|
||||
else
|
||||
CCLOG("already has a bone named %s in skeleton %s", bonename.c_str(), _rootSkeleton->getName().c_str());
|
||||
}
|
||||
|
||||
if (bone->_isRackShow && bone->_visible)
|
||||
}
|
||||
else
|
||||
{
|
||||
_rootSkeleton->_subDrawBonesDirty = true;
|
||||
_rootSkeleton->_subDrawBonesOrderDirty = true;
|
||||
_rootSkeleton->_subBonesDirty = true;
|
||||
_rootSkeleton->_subBonesOrderDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -287,8 +298,8 @@ void BoneNode::setDebugDrawEnabled(bool isDebugDraw)
|
|||
_isRackShow = isDebugDraw;
|
||||
if (_visible && nullptr != _rootSkeleton)
|
||||
{
|
||||
_rootSkeleton->_subDrawBonesDirty = true;
|
||||
_rootSkeleton->_subDrawBonesOrderDirty = true;
|
||||
_rootSkeleton->_subBonesDirty = true;
|
||||
_rootSkeleton->_subBonesOrderDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,6 +309,57 @@ void BoneNode::setDebugDrawColor(const cocos2d::Color4F &color)
|
|||
updateColor();
|
||||
}
|
||||
|
||||
void BoneNode::visit(cocos2d::Renderer *renderer, const cocos2d::Mat4& parentTransform, uint32_t parentFlags)
|
||||
{
|
||||
// quick return if not visible. children won't be drawn.
|
||||
if (!_visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t flags = processParentFlags(parentTransform, parentFlags);
|
||||
|
||||
// IMPORTANT:
|
||||
// To ease the migration to v3.0, we still support the Mat4 stack,
|
||||
// but it is deprecated and your code should not rely on it
|
||||
_director->pushMatrix(cocos2d::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
||||
_director->loadMatrix(cocos2d::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
|
||||
|
||||
bool visibleByCamera = isVisitableByVisitingCamera();
|
||||
|
||||
int i = 0;
|
||||
|
||||
if (!_childBones.empty())
|
||||
{
|
||||
sortAllChildren();
|
||||
// draw children zOrder < 0
|
||||
for (; i < _childBones.size(); i++)
|
||||
{
|
||||
auto bone = _childBones.at(i);
|
||||
if (bone && bone->getZOrder() < 0)
|
||||
bone->visit(renderer, _modelViewTransform, flags);
|
||||
else
|
||||
break;
|
||||
}
|
||||
// self draw
|
||||
if (visibleByCamera)
|
||||
this->draw(renderer, _modelViewTransform, flags);
|
||||
|
||||
for (auto it = _childBones.cbegin() + i; it != _childBones.cend(); ++it)
|
||||
(*it)->visit(renderer, _modelViewTransform, flags);
|
||||
}
|
||||
else if (visibleByCamera)
|
||||
{
|
||||
this->draw(renderer, _modelViewTransform, flags);
|
||||
}
|
||||
|
||||
_director->popMatrix(cocos2d::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
||||
|
||||
// FIX ME: Why need to set _orderOfArrival to 0??
|
||||
// Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920
|
||||
// reset for next frame
|
||||
// _orderOfArrival = 0;
|
||||
}
|
||||
|
||||
void BoneNode::draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, uint32_t flags)
|
||||
{
|
||||
|
@ -451,7 +513,7 @@ bool BoneNode::isPointOnRack(const cocos2d::Vec2& bonePoint)
|
|||
{
|
||||
if (_rackLength != 0.0f && _rackWidth != 0.0f)
|
||||
{
|
||||
float a1 = (_squareVertices[2].y - _squareVertices[3].y ) / (_squareVertices[3].x - _squareVertices[0].x);
|
||||
float a1 = (_squareVertices[2].y - _squareVertices[3].y) / (_squareVertices[3].x - _squareVertices[0].x);
|
||||
float a2 = (_squareVertices[2].y - _squareVertices[3].y) / (_squareVertices[0].x - _squareVertices[1].x);;
|
||||
float b1 = a1 * _squareVertices[3].x;
|
||||
float y1 = bonePoint.y - _squareVertices[1].y;
|
||||
|
@ -479,7 +541,7 @@ void BoneNode::batchBoneDrawToSkeleton(BoneNode* bone) const
|
|||
}
|
||||
|
||||
int count = bone->_rootSkeleton->_batchedVeticesCount;
|
||||
if (count + 8 >(int)(bone->_rootSkeleton->_batchedBoneVetices.capacity()))
|
||||
if (count + 8 >(int)(bone->_rootSkeleton->_batchedBoneVetices.size()))
|
||||
{
|
||||
bone->_rootSkeleton->_batchedBoneVetices.resize(count + 100);
|
||||
bone->_rootSkeleton->_batchedBoneColors.resize(count + 100);
|
||||
|
@ -501,11 +563,45 @@ void BoneNode::batchBoneDrawToSkeleton(BoneNode* bone) const
|
|||
#endif //CC_STUDIO_ENABLED_VIEW
|
||||
}
|
||||
|
||||
|
||||
// call after self visit
|
||||
void BoneNode::visitSkins(cocos2d::Renderer* renderer, BoneNode* bone)
|
||||
{
|
||||
// quick return if not visible. children won't be drawn.
|
||||
if (!bone->_visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// IMPORTANT:
|
||||
// To ease the migration to v3.0, we still support the Mat4 stack,
|
||||
// but it is deprecated and your code should not rely on it
|
||||
_director->pushMatrix(cocos2d::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
||||
_director->loadMatrix(cocos2d::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, bone->_modelViewTransform);
|
||||
|
||||
bool visibleByCamera = bone->isVisitableByVisitingCamera();
|
||||
|
||||
int i = 0;
|
||||
if (!bone->_boneSkins.empty())
|
||||
{
|
||||
bone->sortAllChildren();
|
||||
for (auto it = bone->_boneSkins.cbegin(); it != bone->_boneSkins.cend(); ++it)
|
||||
(*it)->visit(renderer, bone->_modelViewTransform, true);
|
||||
}
|
||||
|
||||
_director->popMatrix(cocos2d::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
||||
|
||||
// FIX ME: Why need to set _orderOfArrival to 0??
|
||||
// Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920
|
||||
// reset for next frame
|
||||
// _orderOfArrival = 0;
|
||||
}
|
||||
|
||||
void BoneNode::setLocalZOrder(int localZOrder)
|
||||
{
|
||||
Node::setLocalZOrder(localZOrder);
|
||||
if (_rootSkeleton != nullptr && this->_visible && this->_isRackShow)
|
||||
_rootSkeleton->_subDrawBonesOrderDirty = true;
|
||||
if (_rootSkeleton != nullptr)
|
||||
_rootSkeleton->_subBonesOrderDirty = true;
|
||||
}
|
||||
|
||||
void BoneNode::setName(const std::string& name)
|
||||
|
@ -549,11 +645,6 @@ void BoneNode::removeFromChildrenListHelper(Node * child)
|
|||
if (nullptr != bone)
|
||||
{
|
||||
removeFromBoneList(bone);
|
||||
if (bone->_isRackShow)
|
||||
{
|
||||
_rootSkeleton->_subDrawBonesDirty = true;
|
||||
_rootSkeleton->_subDrawBonesOrderDirty = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -571,10 +662,10 @@ void BoneNode::setVisible(bool visible)
|
|||
return;
|
||||
|
||||
Node::setVisible(visible);
|
||||
if (_isRackShow && _rootSkeleton != nullptr)
|
||||
if (_rootSkeleton != nullptr)
|
||||
{
|
||||
_rootSkeleton->_subDrawBonesDirty = true;
|
||||
_rootSkeleton->_subDrawBonesOrderDirty = true;
|
||||
_rootSkeleton->_subBonesDirty = true;
|
||||
_rootSkeleton->_subBonesOrderDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -186,10 +186,16 @@ protected:
|
|||
|
||||
virtual void onDraw(const cocos2d::Mat4 &transform, uint32_t flags);
|
||||
|
||||
// override Node::visit, just visit bones in children
|
||||
virtual void visit(cocos2d::Renderer *renderer, const cocos2d::Mat4& parentTransform, uint32_t parentFlags) override;
|
||||
|
||||
// a help function for SkeletonNode
|
||||
// for batch bone's draw to _rootSkeleton
|
||||
virtual void batchBoneDrawToSkeleton(BoneNode* bone) const;
|
||||
|
||||
// a help funciton for SkeletonNode
|
||||
// @param bone, visit bone's skins
|
||||
virtual void visitSkins(cocos2d::Renderer* renderer, BoneNode* bone);
|
||||
protected:
|
||||
cocos2d::CustomCommand _customCommand;
|
||||
cocos2d::BlendFunc _blendFunc;
|
||||
|
|
|
@ -100,10 +100,10 @@ cocos2d::Rect SkeletonNode::getBoundingBox() const
|
|||
}
|
||||
|
||||
SkeletonNode::SkeletonNode()
|
||||
: BoneNode()
|
||||
, _subDrawBonesDirty(true)
|
||||
, _subDrawBonesOrderDirty(true)
|
||||
, _batchedVeticesCount(0)
|
||||
: BoneNode()
|
||||
, _subBonesDirty(true)
|
||||
, _subBonesOrderDirty(true)
|
||||
, _batchedVeticesCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ void SkeletonNode::updateVertices()
|
|||
_squareVertices[5].x = -radiusl; _squareVertices[0].y = -radiusw;
|
||||
_squareVertices[6].x = radiusl; _squareVertices[3].y = radiusw;
|
||||
_squareVertices[1].x = radiusl_2; _squareVertices[7].y = radiusw_2;
|
||||
_squareVertices[2].x = - radiusl_2; _squareVertices[4].y = - radiusw_2;
|
||||
_squareVertices[2].x = -radiusl_2; _squareVertices[4].y = -radiusw_2;
|
||||
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
|
@ -165,6 +165,7 @@ void SkeletonNode::visit(cocos2d::Renderer *renderer, const cocos2d::Mat4& paren
|
|||
|
||||
int i = 0;
|
||||
|
||||
|
||||
if (!_children.empty())
|
||||
{
|
||||
sortAllChildren();
|
||||
|
@ -183,14 +184,18 @@ void SkeletonNode::visit(cocos2d::Renderer *renderer, const cocos2d::Mat4& paren
|
|||
(*it)->visit(renderer, _modelViewTransform, flags);
|
||||
}
|
||||
|
||||
if (visibleByCamera)
|
||||
checkSubBonesDirty();
|
||||
for (const auto& bone : _subOrderedAllBones)
|
||||
{
|
||||
visitSkins(renderer, bone);
|
||||
}
|
||||
|
||||
this->draw(renderer, _modelViewTransform, flags);
|
||||
// batch draw all sub bones
|
||||
_batchBoneCommand.init(_globalZOrder, _modelViewTransform, parentFlags);
|
||||
_batchBoneCommand.func = CC_CALLBACK_0(SkeletonNode::batchDrawAllSubBones, this, _modelViewTransform);
|
||||
renderer->addCommand(&_batchBoneCommand);
|
||||
}
|
||||
|
||||
_director->popMatrix(cocos2d::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
||||
// FIX ME: Why need to set _orderOfArrival to 0??
|
||||
// Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920
|
||||
|
@ -218,16 +223,12 @@ void SkeletonNode::draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transf
|
|||
|
||||
void SkeletonNode::batchDrawAllSubBones(const cocos2d::Mat4 &transform)
|
||||
{
|
||||
if (_subDrawBonesDirty)
|
||||
{
|
||||
updateAllDrawBones();
|
||||
}
|
||||
if (_subDrawBonesOrderDirty)
|
||||
sortAllDrawBones();
|
||||
checkSubBonesDirty();
|
||||
|
||||
_batchedVeticesCount = 0;
|
||||
for (const auto& bone : _subDrawBones)
|
||||
for (const auto& bone : _subOrderedAllBones)
|
||||
{
|
||||
if (bone->isDebugDrawEnabled())
|
||||
batchBoneDrawToSkeleton(bone);
|
||||
}
|
||||
cocos2d::Vec3* vetices = _batchedBoneVetices.data();
|
||||
|
@ -247,7 +248,7 @@ void SkeletonNode::batchDrawAllSubBones(const cocos2d::Mat4 &transform)
|
|||
glLineWidth(1);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
|
||||
for(int i= 0; i < _batchedVeticesCount; i += 8)
|
||||
for (int i = 0; i < _batchedVeticesCount; i += 8)
|
||||
{
|
||||
glDrawArrays(GL_TRIANGLE_FAN, i, 4);
|
||||
glDrawArrays(GL_LINE_LOOP, i + 4, 4);
|
||||
|
@ -287,7 +288,7 @@ void SkeletonNode::changeSkins(const std::map<std::string, std::string>& boneSki
|
|||
for (auto &boneskin : boneSkinNameMap)
|
||||
{
|
||||
auto bone = getBoneNode(boneskin.first);
|
||||
if ( nullptr != bone)
|
||||
if (nullptr != bone)
|
||||
bone->displaySkin(boneskin.second, true);
|
||||
}
|
||||
}
|
||||
|
@ -321,37 +322,49 @@ void SkeletonNode::addSkinGroup(std::string groupName, std::map<std::string, std
|
|||
_skinGroupMap.insert(std::make_pair(groupName, boneSkinNameMap));
|
||||
}
|
||||
|
||||
void SkeletonNode::updateAllDrawBones()
|
||||
void SkeletonNode::checkSubBonesDirty()
|
||||
{
|
||||
_subDrawBones.clear();
|
||||
// get All Visible SubBones
|
||||
if (_subBonesDirty)
|
||||
{
|
||||
updateOrderedAllbones();
|
||||
_subBonesDirty = false;
|
||||
}
|
||||
if (_subBonesOrderDirty)
|
||||
{
|
||||
sortOrderedAllBones();
|
||||
_subBonesOrderDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonNode::updateOrderedAllbones()
|
||||
{
|
||||
_subOrderedAllBones.clear();
|
||||
// update sub bones, get All Visible SubBones
|
||||
// get all sub bones as visit with visible
|
||||
std::stack<BoneNode*> boneStack;
|
||||
for (const auto& bone : _childBones)
|
||||
{
|
||||
if (bone->isVisible() && bone->isDebugDrawEnabled())
|
||||
if (bone->isVisible())
|
||||
boneStack.push(bone);
|
||||
}
|
||||
|
||||
while (boneStack.size() > 0)
|
||||
{
|
||||
auto top = boneStack.top();
|
||||
_subDrawBones.pushBack(top);
|
||||
_subOrderedAllBones.pushBack(top);
|
||||
boneStack.pop();
|
||||
auto topChildren = top->getChildBones();
|
||||
for (const auto& childbone : topChildren)
|
||||
{
|
||||
if (childbone->isVisible() && childbone->isDebugDrawEnabled())
|
||||
if (childbone->isVisible())
|
||||
boneStack.push(childbone);
|
||||
}
|
||||
}
|
||||
_subDrawBonesDirty = false;
|
||||
}
|
||||
|
||||
void SkeletonNode::sortAllDrawBones()
|
||||
void SkeletonNode::sortOrderedAllBones()
|
||||
{
|
||||
std::sort(_subDrawBones.begin(), _subDrawBones.end(), cocos2d::nodeComparisonLess);
|
||||
_subDrawBonesOrderDirty = false;
|
||||
std::sort(_subOrderedAllBones.begin(), _subOrderedAllBones.end(), cocos2d::nodeComparisonLess);
|
||||
}
|
||||
|
||||
NS_TIMELINE_END
|
|
@ -97,17 +97,19 @@ private:
|
|||
CC_DISALLOW_COPY_AND_ASSIGN(SkeletonNode);
|
||||
|
||||
|
||||
void checkSubBonesDirty();
|
||||
// for draw skins as ordered bones' local z
|
||||
cocos2d::Vector<BoneNode*> _subOrderedAllBones;
|
||||
void updateOrderedAllbones();
|
||||
void sortOrderedAllBones();
|
||||
// for batch draw sub bones
|
||||
bool _subDrawBonesDirty;
|
||||
bool _subDrawBonesOrderDirty;
|
||||
cocos2d::Vector<BoneNode*> _subDrawBones; // for draw faster, cache a list from _subBonesMap, sorted by render order
|
||||
bool _subBonesDirty;
|
||||
bool _subBonesOrderDirty;
|
||||
std::vector<cocos2d::Vec3> _batchedBoneVetices;
|
||||
std::vector<cocos2d::Color4F> _batchedBoneColors;
|
||||
int _batchedVeticesCount;
|
||||
cocos2d::CustomCommand _batchBoneCommand;
|
||||
|
||||
void updateAllDrawBones();
|
||||
void sortAllDrawBones();
|
||||
void batchDrawAllSubBones(const cocos2d::Mat4 &transform);
|
||||
void batchSubBone(BoneNode* bone);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue