2019-11-23 20:27:39 +08:00
|
|
|
/****************************************************************************
|
2020-10-17 16:32:16 +08:00
|
|
|
Copyright (c) 2015-2017 Chukong Technologies Inc.
|
2019-11-23 20:27:39 +08:00
|
|
|
|
2022-10-01 16:24:52 +08:00
|
|
|
https://axmolengine.github.io/
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
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.
|
|
|
|
****************************************************************************/
|
|
|
|
|
2023-06-11 13:08:08 +08:00
|
|
|
#include "base/Director.h"
|
|
|
|
#include "base/Utils.h"
|
|
|
|
#include "renderer/Renderer.h"
|
|
|
|
#include "renderer/Shaders.h"
|
2019-11-25 01:35:26 +08:00
|
|
|
#include "renderer/backend/ProgramState.h"
|
2020-10-17 16:32:16 +08:00
|
|
|
|
2023-06-11 13:08:08 +08:00
|
|
|
#include "ActionTimeline/BoneNode.h"
|
|
|
|
#include "ActionTimeline/SkeletonNode.h"
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
NS_TIMELINE_BEGIN
|
|
|
|
|
|
|
|
BoneNode* BoneNode::create()
|
|
|
|
{
|
2021-12-08 00:11:53 +08:00
|
|
|
BoneNode* ret = new BoneNode();
|
|
|
|
if (ret->init())
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
ret->autorelease();
|
|
|
|
return ret;
|
|
|
|
}
|
2022-07-16 10:43:05 +08:00
|
|
|
AX_SAFE_DELETE(ret);
|
2019-11-23 20:27:39 +08:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
BoneNode* BoneNode::create(int length)
|
|
|
|
{
|
2021-12-08 00:11:53 +08:00
|
|
|
BoneNode* ret = new BoneNode();
|
|
|
|
if (ret->init())
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
ret->setDebugDrawLength(length);
|
|
|
|
ret->autorelease();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-07-16 10:43:05 +08:00
|
|
|
AX_SAFE_DELETE(ret);
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
BoneNode::~BoneNode() {}
|
2020-10-17 16:32:16 +08:00
|
|
|
|
|
|
|
bool BoneNode::init()
|
|
|
|
{
|
|
|
|
_rackLength = 50;
|
2021-12-25 10:04:45 +08:00
|
|
|
_rackWidth = 20;
|
2020-10-17 16:32:16 +08:00
|
|
|
updateVertices();
|
|
|
|
updateColor();
|
|
|
|
|
|
|
|
auto& pipelineDescriptor = _customCommand.getPipelineDescriptor();
|
2021-12-25 10:04:45 +08:00
|
|
|
auto* program =
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::backend::Program::getBuiltinProgram(ax::backend::ProgramType::POSITION_COLOR); // TODO: noMVP?
|
2023-08-31 18:14:26 +08:00
|
|
|
setProgramState(new ax::backend::ProgramState(program), false);
|
2020-10-17 16:32:16 +08:00
|
|
|
pipelineDescriptor.programState = _programState;
|
|
|
|
|
2021-12-31 12:12:40 +08:00
|
|
|
_mvpLocation = _programState->getUniformLocation("u_MVPMatrix"sv);
|
2020-10-17 16:32:16 +08:00
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
_customCommand.createVertexBuffer(sizeof(_vertexData[0]), 4, ax::CustomCommand::BufferUsage::DYNAMIC);
|
|
|
|
_customCommand.createIndexBuffer(ax::CustomCommand::IndexFormat::U_SHORT, 6,
|
|
|
|
ax::CustomCommand::BufferUsage::STATIC);
|
2021-12-25 10:04:45 +08:00
|
|
|
unsigned short indices[6] = {0, 1, 2, 0, 2, 3};
|
2020-10-17 16:32:16 +08:00
|
|
|
_customCommand.updateIndexBuffer(indices, sizeof(indices));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
void BoneNode::addChild(ax::Node* child, int localZOrder, int tag)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
addToChildrenListHelper(child);
|
|
|
|
Node::addChild(child, localZOrder, tag);
|
|
|
|
}
|
|
|
|
|
2021-12-31 12:12:40 +08:00
|
|
|
void BoneNode::addChild(Node* child, int localZOrder, std::string_view name)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
addToChildrenListHelper(child);
|
|
|
|
Node::addChild(child, localZOrder, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::addSkin(SkinNode* skin, bool isDisplay, bool hideOthers)
|
|
|
|
{
|
2022-07-16 10:43:05 +08:00
|
|
|
AXASSERT(skin != nullptr, "Argument must be non-nil");
|
2019-11-23 20:27:39 +08:00
|
|
|
if (hideOthers)
|
|
|
|
{
|
2022-07-21 19:19:08 +08:00
|
|
|
for (auto&& bonskin : _boneSkins)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
bonskin->setVisible(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Node::addChild(skin);
|
|
|
|
skin->setVisible(isDisplay);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::addSkin(SkinNode* skin, bool display)
|
|
|
|
{
|
|
|
|
addSkin(skin, display, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::removeChild(Node* child, bool cleanup /* = true */)
|
|
|
|
{
|
|
|
|
ssize_t index = _children.getIndex(child);
|
2022-08-08 18:02:17 +08:00
|
|
|
if (index != ax::AX_INVALID_INDEX)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
removeFromChildrenListHelper(child);
|
|
|
|
Node::removeChild(child, cleanup);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::removeFromBoneList(BoneNode* bone)
|
|
|
|
{
|
|
|
|
if (_rootSkeleton != nullptr)
|
2021-12-25 10:04:45 +08:00
|
|
|
{
|
2019-11-23 20:27:39 +08:00
|
|
|
auto skeletonNode = dynamic_cast<SkeletonNode*>(bone);
|
|
|
|
if (skeletonNode == nullptr) // is not a nested skeleton
|
|
|
|
{
|
|
|
|
auto subBones = bone->getAllSubBones();
|
|
|
|
subBones.pushBack(bone);
|
2022-07-21 19:19:08 +08:00
|
|
|
for (auto&& subBone : subBones)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
if (subBone->_rootSkeleton == nullptr)
|
|
|
|
continue;
|
|
|
|
subBone->_rootSkeleton = nullptr;
|
|
|
|
|
|
|
|
auto toremoveIter = _rootSkeleton->_subBonesMap.find(subBone->getName());
|
|
|
|
if (toremoveIter != _rootSkeleton->_subBonesMap.end())
|
|
|
|
{
|
|
|
|
_rootSkeleton->_subBonesMap.erase(toremoveIter);
|
2021-12-25 10:04:45 +08:00
|
|
|
_rootSkeleton->_subBonesDirty = true;
|
2019-11-23 20:27:39 +08:00
|
|
|
_rootSkeleton->_subBonesOrderDirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
_rootSkeleton->_subBonesDirty = true;
|
2019-11-23 20:27:39 +08:00
|
|
|
_rootSkeleton->_subBonesOrderDirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_childBones.eraseObject(bone);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::addToBoneList(BoneNode* bone)
|
|
|
|
{
|
|
|
|
_childBones.pushBack(bone);
|
|
|
|
if (_rootSkeleton != nullptr)
|
|
|
|
{
|
|
|
|
auto skeletonNode = dynamic_cast<SkeletonNode*>(bone);
|
2021-12-25 10:04:45 +08:00
|
|
|
if (skeletonNode == nullptr && bone->_rootSkeleton == nullptr) // not nest skeleton
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
auto subBones = bone->getAllSubBones();
|
|
|
|
subBones.pushBack(bone);
|
2022-07-21 19:19:08 +08:00
|
|
|
for (auto&& subBone : subBones)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
subBone->_rootSkeleton = _rootSkeleton;
|
2021-12-25 10:04:45 +08:00
|
|
|
auto bonename = subBone->getName();
|
2019-11-23 20:27:39 +08:00
|
|
|
if (_rootSkeleton->_subBonesMap.find(bonename) == _rootSkeleton->_subBonesMap.end())
|
|
|
|
{
|
|
|
|
_rootSkeleton->_subBonesMap.insert(subBone->getName(), subBone);
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
_rootSkeleton->_subBonesDirty = true;
|
2019-11-23 20:27:39 +08:00
|
|
|
_rootSkeleton->_subBonesOrderDirty = true;
|
|
|
|
}
|
|
|
|
else
|
2022-07-16 10:43:05 +08:00
|
|
|
AXLOG("already has a bone named %s in skeleton %s", bonename.data(),
|
2021-12-31 12:12:40 +08:00
|
|
|
_rootSkeleton->getName().data());
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
_rootSkeleton->_subBonesDirty = true;
|
2019-11-23 20:27:39 +08:00
|
|
|
_rootSkeleton->_subBonesOrderDirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::addToSkinList(SkinNode* skin)
|
|
|
|
{
|
|
|
|
_boneSkins.pushBack(skin);
|
|
|
|
auto blendSkin = dynamic_cast<BlendProtocol*>(skin);
|
|
|
|
if (nullptr != blendSkin && _blendFunc != blendSkin->getBlendFunc())
|
|
|
|
{
|
|
|
|
blendSkin->setBlendFunc(_blendFunc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::removeFromSkinList(SkinNode* skin)
|
|
|
|
{
|
|
|
|
_boneSkins.eraseObject(skin);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::displaySkin(SkinNode* skin, bool hideOthers)
|
|
|
|
{
|
2022-07-21 19:19:08 +08:00
|
|
|
for (auto&& boneskin : _boneSkins)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
if (boneskin == skin)
|
|
|
|
{
|
|
|
|
boneskin->setVisible(true);
|
|
|
|
}
|
|
|
|
else if (hideOthers)
|
|
|
|
{
|
|
|
|
boneskin->setVisible(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-31 12:12:40 +08:00
|
|
|
void BoneNode::displaySkin(std::string_view skinName, bool hideOthers)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
2022-07-21 19:19:08 +08:00
|
|
|
for (auto&& skin : _boneSkins)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
if (skinName == skin->getName())
|
|
|
|
{
|
|
|
|
skin->setVisible(true);
|
|
|
|
}
|
|
|
|
else if (hideOthers)
|
|
|
|
{
|
|
|
|
skin->setVisible(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Vector<SkinNode*> BoneNode::getVisibleSkins() const
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Vector<SkinNode*> displayingSkins;
|
2021-12-25 10:04:45 +08:00
|
|
|
for (const auto& boneskin : _boneSkins)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
if (boneskin->isVisible())
|
|
|
|
{
|
|
|
|
displayingSkins.pushBack(boneskin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return displayingSkins;
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Rect BoneNode::getBoundingBox() const
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Rect boundingBox = getVisibleSkinsRect();
|
2019-11-23 20:27:39 +08:00
|
|
|
return RectApplyAffineTransform(boundingBox, this->getNodeToParentAffineTransform());
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Rect BoneNode::getVisibleSkinsRect() const
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
float minx, miny, maxx, maxy = 0;
|
|
|
|
minx = miny = maxx = maxy;
|
2021-12-25 10:04:45 +08:00
|
|
|
bool first = true;
|
2019-11-23 20:27:39 +08:00
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Rect displayRect = ax::Rect(0, 0, 0, 0);
|
2019-11-23 20:27:39 +08:00
|
|
|
if (_isRackShow && _rootSkeleton != nullptr && _rootSkeleton->_isRackShow)
|
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
maxx = _rackLength;
|
|
|
|
maxy = _rackWidth;
|
2019-11-23 20:27:39 +08:00
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& skin : _boneSkins)
|
|
|
|
{
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Rect r = skin->getBoundingBox();
|
|
|
|
if (!skin->isVisible() || r.equals(ax::Rect::ZERO))
|
2019-11-23 20:27:39 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (first)
|
|
|
|
{
|
|
|
|
minx = r.getMinX();
|
|
|
|
miny = r.getMinY();
|
|
|
|
maxx = r.getMaxX();
|
|
|
|
maxy = r.getMaxY();
|
|
|
|
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
minx = MIN(r.getMinX(), minx);
|
|
|
|
miny = MIN(r.getMinY(), miny);
|
|
|
|
maxx = MAX(r.getMaxX(), maxx);
|
|
|
|
maxy = MAX(r.getMaxY(), maxy);
|
|
|
|
}
|
|
|
|
displayRect.setRect(minx, miny, maxx - minx, maxy - miny);
|
|
|
|
}
|
|
|
|
return displayRect;
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
void BoneNode::setBlendFunc(const ax::BlendFunc& blendFunc)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
if (_blendFunc != blendFunc)
|
|
|
|
{
|
|
|
|
_blendFunc = blendFunc;
|
2022-07-21 19:19:08 +08:00
|
|
|
for (auto&& skin : _boneSkins)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
auto blendSkin = dynamic_cast<BlendProtocol*>(skin);
|
|
|
|
if (nullptr != blendSkin)
|
|
|
|
{
|
|
|
|
blendSkin->setBlendFunc(_blendFunc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::setDebugDrawLength(float length)
|
|
|
|
{
|
|
|
|
_rackLength = length;
|
|
|
|
updateVertices();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::setDebugDrawWidth(float width)
|
|
|
|
{
|
|
|
|
_rackWidth = width;
|
|
|
|
updateVertices();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::setDebugDrawEnabled(bool isDebugDraw)
|
|
|
|
{
|
|
|
|
if (_isRackShow == isDebugDraw)
|
|
|
|
return;
|
|
|
|
_isRackShow = isDebugDraw;
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
void BoneNode::setDebugDrawColor(const ax::Color4F& color)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
_rackColor = color;
|
|
|
|
updateColor();
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
void BoneNode::visit(ax::Renderer* renderer, const ax::Mat4& parentTransform, uint32_t parentFlags)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
// 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
|
2022-08-08 18:02:17 +08:00
|
|
|
_director->pushMatrix(ax::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
|
|
|
_director->loadMatrix(ax::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
bool visibleByCamera = isVisitableByVisitingCamera();
|
2021-12-25 10:04:45 +08:00
|
|
|
bool isdebugdraw = visibleByCamera && _isRackShow && nullptr == _rootSkeleton;
|
|
|
|
int i = 0;
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
if (!_children.empty())
|
|
|
|
{
|
|
|
|
sortAllChildren();
|
|
|
|
// draw children zOrder < 0
|
|
|
|
for (; i < _children.size(); i++)
|
|
|
|
{
|
|
|
|
auto node = _children.at(i);
|
2021-12-25 10:04:45 +08:00
|
|
|
if (_rootSkeleton != nullptr && _boneSkins.contains(node)) // skip skin when bone is in a skeleton
|
2019-11-23 20:27:39 +08:00
|
|
|
continue;
|
|
|
|
if (node && node->getLocalZOrder() < 0)
|
|
|
|
node->visit(renderer, _modelViewTransform, flags);
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// self draw
|
|
|
|
if (isdebugdraw)
|
|
|
|
this->draw(renderer, _modelViewTransform, flags);
|
|
|
|
|
|
|
|
for (auto it = _children.cbegin() + i; it != _children.cend(); ++it)
|
|
|
|
{
|
|
|
|
auto node = (*it);
|
2021-12-25 10:04:45 +08:00
|
|
|
if (_rootSkeleton != nullptr && _boneSkins.contains(node)) // skip skin when bone is in a skeleton
|
2019-11-23 20:27:39 +08:00
|
|
|
continue;
|
|
|
|
node->visit(renderer, _modelViewTransform, flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (isdebugdraw)
|
|
|
|
{
|
|
|
|
this->draw(renderer, _modelViewTransform, flags);
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
_director->popMatrix(ax::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
void BoneNode::draw(ax::Renderer* renderer, const ax::Mat4& transform, uint32_t flags)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
2019-11-25 01:35:26 +08:00
|
|
|
_customCommand.init(_globalZOrder, _blendFunc);
|
2019-11-23 20:27:39 +08:00
|
|
|
renderer->addCommand(&_customCommand);
|
|
|
|
|
2022-07-16 10:43:05 +08:00
|
|
|
#ifdef AX_STUDIO_ENABLED_VIEW
|
2021-12-25 10:04:45 +08:00
|
|
|
// TODO
|
2022-08-08 18:02:17 +08:00
|
|
|
// glVertexAttribPointer(ax::GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, 0, _noMVPVertices);
|
|
|
|
// glVertexAttribPointer(ax::GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_FLOAT, GL_FALSE, 0, _squareColors);
|
2019-11-25 01:35:26 +08:00
|
|
|
//
|
2021-12-25 10:04:45 +08:00
|
|
|
// glEnable(GL_LINE_SMOOTH);
|
|
|
|
// glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
|
|
|
|
// glDrawArrays(GL_LINE_LOOP, 0, 4);
|
2022-07-16 10:43:05 +08:00
|
|
|
// AX_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, 8);
|
|
|
|
#endif // AX_STUDIO_ENABLED_VIEW
|
2019-11-25 01:35:26 +08:00
|
|
|
|
2019-11-23 20:27:39 +08:00
|
|
|
for (int i = 0; i < 4; ++i)
|
|
|
|
{
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Vec4 pos;
|
2021-12-25 10:04:45 +08:00
|
|
|
pos.x = _squareVertices[i].x;
|
|
|
|
pos.y = _squareVertices[i].y;
|
|
|
|
pos.z = _positionZ;
|
2019-11-23 20:27:39 +08:00
|
|
|
pos.w = 1;
|
|
|
|
_modelViewTransform.transformVector(&pos);
|
2022-08-08 18:02:17 +08:00
|
|
|
_vertexData[i].noMVPVertices = ax::Vec3(pos.x, pos.y, pos.z) / pos.w;
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
2019-11-25 01:35:26 +08:00
|
|
|
_customCommand.updateVertexBuffer(_vertexData, sizeof(_vertexData));
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
_programState->setUniform(_mvpLocation, transform.m, sizeof(transform.m));
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::updateVertices()
|
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
if (_rackLength != _squareVertices[2].x - _anchorPointInPoints.x ||
|
|
|
|
_squareVertices[3].y != _rackWidth / 2 - _anchorPointInPoints.y)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
_squareVertices[1].x = _squareVertices[1].y = _squareVertices[3].y = .0f;
|
|
|
|
_squareVertices[0].x = _squareVertices[2].x = _rackLength * .1f;
|
2021-12-25 10:04:45 +08:00
|
|
|
_squareVertices[2].y = _rackWidth * .5f;
|
|
|
|
_squareVertices[0].y = -_squareVertices[2].y;
|
|
|
|
_squareVertices[3].x = _rackLength;
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
_squareVertices[i] += _anchorPointInPoints;
|
|
|
|
}
|
|
|
|
_transformUpdated = _transformDirty = _inverseDirty = _contentSizeDirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::updateColor()
|
|
|
|
{
|
|
|
|
for (unsigned int i = 0; i < 4; i++)
|
|
|
|
{
|
2019-11-25 01:35:26 +08:00
|
|
|
_vertexData[i].squareColor = _rackColor;
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
_transformUpdated = _transformDirty = _inverseDirty = _contentSizeDirty = true;
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
void BoneNode::updateDisplayedColor(const ax::Color3B& /*parentColor*/)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
if (_cascadeColorEnabled)
|
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
for (const auto& child : _boneSkins)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
child->updateDisplayedColor(_displayedColor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-25 01:35:26 +08:00
|
|
|
void BoneNode::updateDisplayedOpacity(uint8_t /*parentOpacity*/)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
if (_cascadeOpacityEnabled)
|
|
|
|
{
|
|
|
|
for (const auto& child : _boneSkins)
|
|
|
|
{
|
|
|
|
child->updateDisplayedOpacity(_displayedOpacity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::disableCascadeOpacity()
|
|
|
|
{
|
|
|
|
for (const auto& child : _boneSkins)
|
|
|
|
{
|
|
|
|
child->updateDisplayedOpacity(255);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::disableCascadeColor()
|
|
|
|
{
|
|
|
|
for (const auto& child : _boneSkins)
|
|
|
|
{
|
2022-08-08 18:02:17 +08:00
|
|
|
child->updateDisplayedColor(ax::Color3B::WHITE);
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Vector<BoneNode*> BoneNode::getAllSubBones() const
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Vector<BoneNode*> allBones;
|
2021-12-25 10:04:45 +08:00
|
|
|
std::stack<BoneNode*> boneStack; // for avoid recursive
|
2019-11-23 20:27:39 +08:00
|
|
|
for (const auto& bone : _childBones)
|
|
|
|
{
|
|
|
|
boneStack.push(bone);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (boneStack.size() > 0)
|
|
|
|
{
|
|
|
|
auto top = boneStack.top();
|
|
|
|
allBones.pushBack(top);
|
|
|
|
boneStack.pop();
|
|
|
|
auto topchildren = top->getChildBones();
|
|
|
|
for (const auto& childbone : topchildren)
|
|
|
|
{
|
|
|
|
boneStack.push(childbone);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return allBones;
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Vector<SkinNode*> BoneNode::getAllSubSkins() const
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
auto allbones = getAllSubBones();
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Vector<SkinNode*> allskins;
|
2019-11-23 20:27:39 +08:00
|
|
|
for (const auto& bone : allbones)
|
|
|
|
{
|
|
|
|
for (const auto& skin : bone->getSkins())
|
|
|
|
{
|
|
|
|
allskins.pushBack(skin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return allskins;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::sortAllChildren()
|
|
|
|
{
|
|
|
|
if (_reorderChildDirty)
|
|
|
|
{
|
|
|
|
sortNodes(_childBones);
|
|
|
|
sortNodes(_boneSkins);
|
|
|
|
Node::sortAllChildren();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SkeletonNode* BoneNode::getRootSkeletonNode() const
|
|
|
|
{
|
|
|
|
return _rootSkeleton;
|
|
|
|
}
|
|
|
|
|
2022-07-16 10:43:05 +08:00
|
|
|
#ifdef AX_STUDIO_ENABLED_VIEW
|
2022-08-08 18:02:17 +08:00
|
|
|
bool BoneNode::isPointOnRack(const ax::Vec2& bonePoint)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
if (bonePoint.x >= 0.0f && bonePoint.y >= _squareVertices[0].y && bonePoint.x <= _rackLength &&
|
2019-11-23 20:27:39 +08:00
|
|
|
bonePoint.y <= _squareVertices[2].y)
|
|
|
|
{
|
|
|
|
if (_rackLength != 0.0f && _rackWidth != 0.0f)
|
|
|
|
{
|
|
|
|
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;
|
2021-12-25 10:04:45 +08:00
|
|
|
if (y1 >= a1 * bonePoint.x - b1 && y1 <= a2 * bonePoint.x && y1 >= -a2 * bonePoint.x &&
|
2019-11-23 20:27:39 +08:00
|
|
|
y1 <= -a1 * bonePoint.x + b1)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2022-07-16 10:43:05 +08:00
|
|
|
#endif // AX_STUDIO_ENABLED_VIEW
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
void BoneNode::batchBoneDrawToSkeleton(BoneNode* bone) const
|
|
|
|
{
|
|
|
|
bool visibleByCamera = bone->isVisitableByVisitingCamera();
|
|
|
|
if (!visibleByCamera)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Vec3 vpos[4];
|
2019-11-23 20:27:39 +08:00
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
{
|
2022-08-08 18:02:17 +08:00
|
|
|
ax::Vec4 pos;
|
2021-12-25 10:04:45 +08:00
|
|
|
pos.x = bone->_squareVertices[i].x;
|
|
|
|
pos.y = bone->_squareVertices[i].y;
|
|
|
|
pos.z = bone->_positionZ;
|
2019-11-23 20:27:39 +08:00
|
|
|
pos.w = 1;
|
|
|
|
bone->_modelViewTransform.transformVector(&pos); // call after visit
|
2022-08-08 18:02:17 +08:00
|
|
|
vpos[i] = ax::Vec3(pos.x, pos.y, pos.z) / pos.w;
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int count = bone->_rootSkeleton->_batchedVeticesCount;
|
2021-12-25 10:04:45 +08:00
|
|
|
if (count + 8 > (int)(bone->_rootSkeleton->_batchedBoneVertexData.size()))
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
2019-11-25 01:35:26 +08:00
|
|
|
bone->_rootSkeleton->_batchedBoneVertexData.resize(count + 100);
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
{
|
2019-11-25 01:35:26 +08:00
|
|
|
bone->_rootSkeleton->_batchedBoneVertexData[count + i].vertex = vpos[i];
|
2021-12-25 10:04:45 +08:00
|
|
|
bone->_rootSkeleton->_batchedBoneVertexData[count + i].color = bone->_vertexData[i].squareColor;
|
2019-11-23 20:27:39 +08:00
|
|
|
}
|
|
|
|
bone->_rootSkeleton->_batchedVeticesCount += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// call after self visit
|
2022-08-08 18:02:17 +08:00
|
|
|
void BoneNode::visitSkins(ax::Renderer* renderer, BoneNode* bone) const
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
// 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
|
2022-08-08 18:02:17 +08:00
|
|
|
_director->pushMatrix(ax::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
|
|
|
_director->loadMatrix(ax::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, bone->_modelViewTransform);
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
if (!bone->_boneSkins.empty())
|
|
|
|
{
|
|
|
|
bone->sortAllChildren();
|
|
|
|
for (auto it = bone->_boneSkins.cbegin(); it != bone->_boneSkins.cend(); ++it)
|
|
|
|
(*it)->visit(renderer, bone->_modelViewTransform, true);
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
_director->popMatrix(ax::MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
// 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::setRootSkeleton(BoneNode* bone, SkeletonNode* skeleton) const
|
|
|
|
{
|
|
|
|
bone->_rootSkeleton = skeleton;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::setLocalZOrder(int localZOrder)
|
|
|
|
{
|
|
|
|
Node::setLocalZOrder(localZOrder);
|
|
|
|
if (_rootSkeleton != nullptr)
|
|
|
|
_rootSkeleton->_subBonesOrderDirty = true;
|
|
|
|
}
|
|
|
|
|
2021-12-31 12:12:40 +08:00
|
|
|
void BoneNode::setName(std::string_view name)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
auto oldname = getName();
|
|
|
|
Node::setName(name);
|
|
|
|
if (_rootSkeleton != nullptr)
|
|
|
|
{
|
|
|
|
auto oiter = _rootSkeleton->_subBonesMap.find(oldname);
|
|
|
|
auto niter = _rootSkeleton->_subBonesMap.find(name);
|
2021-12-25 10:04:45 +08:00
|
|
|
if (oiter != _rootSkeleton->_subBonesMap.end() && niter == _rootSkeleton->_subBonesMap.end())
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
auto node = oiter->second;
|
|
|
|
_rootSkeleton->_subBonesMap.erase(oiter);
|
|
|
|
_rootSkeleton->_subBonesMap.insert(name, node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
void BoneNode::addToChildrenListHelper(Node* child)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
BoneNode* bone = dynamic_cast<BoneNode*>(child);
|
|
|
|
if (nullptr != bone)
|
|
|
|
{
|
|
|
|
addToBoneList(bone);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SkinNode* skin = dynamic_cast<SkinNode*>(child);
|
|
|
|
if (nullptr != skin)
|
|
|
|
{
|
|
|
|
addToSkinList(skin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
void BoneNode::removeFromChildrenListHelper(Node* child)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
BoneNode* bone = dynamic_cast<BoneNode*>(child);
|
|
|
|
if (nullptr != bone)
|
|
|
|
{
|
|
|
|
removeFromBoneList(bone);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SkinNode* skin = dynamic_cast<SkinNode*>(child);
|
|
|
|
if (nullptr != skin)
|
|
|
|
{
|
|
|
|
removeFromSkinList(skin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoneNode::setVisible(bool visible)
|
|
|
|
{
|
|
|
|
if (_visible == visible)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Node::setVisible(visible);
|
|
|
|
if (_rootSkeleton != nullptr)
|
|
|
|
{
|
2021-12-25 10:04:45 +08:00
|
|
|
_rootSkeleton->_subBonesDirty = true;
|
2019-11-23 20:27:39 +08:00
|
|
|
_rootSkeleton->_subBonesOrderDirty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
void BoneNode::setContentSize(const ax::Size& contentSize)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
Node::setContentSize(contentSize);
|
|
|
|
updateVertices();
|
|
|
|
}
|
|
|
|
|
2022-08-08 18:02:17 +08:00
|
|
|
void BoneNode::setAnchorPoint(const ax::Vec2& anchorPoint)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
Node::setAnchorPoint(anchorPoint);
|
|
|
|
updateVertices();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_TIMELINE_END
|