mirror of https://github.com/axmolengine/axmol.git
455 lines
12 KiB
C++
455 lines
12 KiB
C++
/****************************************************************************
|
|
Copyright (c) 2008-2010 Ricardo Quesada
|
|
Copyright (c) 2009 Valentin Milea
|
|
Copyright (c) 2010-2012 cocos2d-x.org
|
|
Copyright (c) 2011 Zynga Inc.
|
|
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
|
Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md).
|
|
|
|
https://axmol.dev/
|
|
|
|
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 "2d/ProtectedNode.h"
|
|
|
|
#include "base/Director.h"
|
|
#include "2d/Scene.h"
|
|
|
|
NS_AX_BEGIN
|
|
|
|
ProtectedNode::ProtectedNode() : _reorderProtectedChildDirty(false) {}
|
|
|
|
ProtectedNode::~ProtectedNode()
|
|
{
|
|
AXLOGV("deallocing ProtectedNode: {} - tag: {}", fmt::ptr(this), _tag);
|
|
removeAllProtectedChildren();
|
|
}
|
|
|
|
ProtectedNode* ProtectedNode::create()
|
|
{
|
|
ProtectedNode* ret = new ProtectedNode();
|
|
if (ret->init())
|
|
{
|
|
ret->autorelease();
|
|
}
|
|
else
|
|
{
|
|
AX_SAFE_DELETE(ret);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ProtectedNode::cleanup()
|
|
{
|
|
Node::cleanup();
|
|
// timers
|
|
for (const auto& child : _protectedChildren)
|
|
child->cleanup();
|
|
}
|
|
|
|
void ProtectedNode::addProtectedChild(ax::Node* child)
|
|
{
|
|
addProtectedChild(child, child->getLocalZOrder(), child->getTag());
|
|
}
|
|
|
|
void ProtectedNode::addProtectedChild(ax::Node* child, int localZOrder)
|
|
{
|
|
addProtectedChild(child, localZOrder, child->getTag());
|
|
}
|
|
|
|
/* "add" logic MUST only be on this method
|
|
* If a class want's to extend the 'addChild' behavior it only needs
|
|
* to override this method
|
|
*/
|
|
void ProtectedNode::addProtectedChild(Node* child, int zOrder, int tag)
|
|
{
|
|
AXASSERT(child != nullptr, "Argument must be non-nil");
|
|
AXASSERT(child->getParent() == nullptr, "child already added. It can't be added again");
|
|
|
|
if (_protectedChildren.empty())
|
|
{
|
|
_protectedChildren.reserve(4);
|
|
}
|
|
|
|
this->insertProtectedChild(child, zOrder);
|
|
|
|
child->setTag(tag);
|
|
child->setGlobalZOrder(_globalZOrder);
|
|
child->setParent(this);
|
|
child->updateOrderOfArrival();
|
|
|
|
if (_running)
|
|
{
|
|
child->onEnter();
|
|
// prevent onEnterTransitionDidFinish to be called twice when a node is added in onEnter
|
|
if (_isTransitionFinished)
|
|
{
|
|
child->onEnterTransitionDidFinish();
|
|
}
|
|
}
|
|
|
|
if (_cascadeColorEnabled)
|
|
{
|
|
updateCascadeColor();
|
|
}
|
|
|
|
if (_cascadeOpacityEnabled)
|
|
{
|
|
updateCascadeOpacity();
|
|
}
|
|
}
|
|
|
|
Node* ProtectedNode::getProtectedChildByTag(int tag)
|
|
{
|
|
AXASSERT(tag != Node::INVALID_TAG, "Invalid tag");
|
|
|
|
for (auto&& child : _protectedChildren)
|
|
{
|
|
if (child && child->getTag() == tag)
|
|
return child;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Node* ProtectedNode::getProtectedChildByName(std::string_view name)
|
|
{
|
|
// AXASSERT(!name.empty(), "Invalid name");
|
|
for (auto&& child : _protectedChildren)
|
|
{
|
|
if (child && child->getName() == name)
|
|
return child;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/* "remove" logic MUST only be on this method
|
|
* If a class want's to extend the 'removeChild' behavior it only needs
|
|
* to override this method
|
|
*/
|
|
void ProtectedNode::removeProtectedChild(ax::Node* child, bool cleanup)
|
|
{
|
|
// explicit nil handling
|
|
if (_protectedChildren.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
ssize_t index = _protectedChildren.getIndex(child);
|
|
if (index != AX_INVALID_INDEX)
|
|
{
|
|
|
|
// IMPORTANT:
|
|
// -1st do onExit
|
|
// -2nd cleanup
|
|
if (_running)
|
|
{
|
|
child->onExitTransitionDidStart();
|
|
child->onExit();
|
|
}
|
|
|
|
// If you don't do cleanup, the child's actions will not get removed and the
|
|
// its scheduledSelectors_ dict will not get released!
|
|
if (cleanup)
|
|
{
|
|
child->cleanup();
|
|
}
|
|
|
|
// set parent nil at the end
|
|
child->setParent(nullptr);
|
|
|
|
#if AX_ENABLE_GC_FOR_NATIVE_OBJECTS
|
|
auto sEngine = ScriptEngineManager::getInstance()->getScriptEngine();
|
|
if (sEngine)
|
|
{
|
|
sEngine->releaseScriptObject(this, child);
|
|
}
|
|
#endif // AX_ENABLE_GC_FOR_NATIVE_OBJECTS
|
|
_protectedChildren.erase(index);
|
|
}
|
|
}
|
|
|
|
void ProtectedNode::removeAllProtectedChildren()
|
|
{
|
|
removeAllProtectedChildrenWithCleanup(true);
|
|
}
|
|
|
|
void ProtectedNode::removeAllProtectedChildrenWithCleanup(bool cleanup)
|
|
{
|
|
// not using detachChild improves speed here
|
|
for (auto&& child : _protectedChildren)
|
|
{
|
|
// IMPORTANT:
|
|
// -1st do onExit
|
|
// -2nd cleanup
|
|
if (_running)
|
|
{
|
|
child->onExitTransitionDidStart();
|
|
child->onExit();
|
|
}
|
|
|
|
if (cleanup)
|
|
{
|
|
child->cleanup();
|
|
}
|
|
#if AX_ENABLE_GC_FOR_NATIVE_OBJECTS
|
|
auto sEngine = ScriptEngineManager::getInstance()->getScriptEngine();
|
|
if (sEngine)
|
|
{
|
|
sEngine->releaseScriptObject(this, child);
|
|
}
|
|
#endif // AX_ENABLE_GC_FOR_NATIVE_OBJECTS
|
|
// set parent nil at the end
|
|
child->setParent(nullptr);
|
|
}
|
|
|
|
_protectedChildren.clear();
|
|
}
|
|
|
|
void ProtectedNode::removeProtectedChildByTag(int tag, bool cleanup)
|
|
{
|
|
AXASSERT(tag != Node::INVALID_TAG, "Invalid tag");
|
|
|
|
Node* child = this->getProtectedChildByTag(tag);
|
|
|
|
if (child == nullptr)
|
|
{
|
|
AXLOGD("axmol: removeChildByTag(tag = {}): child not found!", tag);
|
|
}
|
|
else
|
|
{
|
|
this->removeProtectedChild(child, cleanup);
|
|
}
|
|
}
|
|
|
|
// helper used by reorderChild & add
|
|
void ProtectedNode::insertProtectedChild(ax::Node* child, int z)
|
|
{
|
|
#if AX_ENABLE_GC_FOR_NATIVE_OBJECTS
|
|
auto sEngine = ScriptEngineManager::getInstance()->getScriptEngine();
|
|
if (sEngine)
|
|
{
|
|
sEngine->retainScriptObject(this, child);
|
|
}
|
|
#endif // AX_ENABLE_GC_FOR_NATIVE_OBJECTS
|
|
_reorderProtectedChildDirty = true;
|
|
_protectedChildren.pushBack(child);
|
|
child->setLocalZOrder(z);
|
|
}
|
|
|
|
void ProtectedNode::sortAllProtectedChildren()
|
|
{
|
|
if (_reorderProtectedChildDirty)
|
|
{
|
|
sortNodes(_protectedChildren);
|
|
_reorderProtectedChildDirty = false;
|
|
}
|
|
}
|
|
|
|
void ProtectedNode::reorderProtectedChild(ax::Node* child, int localZOrder)
|
|
{
|
|
AXASSERT(child != nullptr, "Child must be non-nil");
|
|
_reorderProtectedChildDirty = true;
|
|
child->updateOrderOfArrival();
|
|
child->setLocalZOrder(localZOrder);
|
|
}
|
|
|
|
void ProtectedNode::visit(Renderer* renderer, const 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(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
|
_director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
|
|
|
|
int i = 0; // used by _children
|
|
int j = 0; // used by _protectedChildren
|
|
|
|
sortAllChildren();
|
|
sortAllProtectedChildren();
|
|
|
|
//
|
|
// draw children and protectedChildren zOrder < 0
|
|
//
|
|
for (auto size = _children.size(); i < size; ++i)
|
|
{
|
|
auto node = _children.at(i);
|
|
|
|
if (node && node->getLocalZOrder() < 0)
|
|
node->visit(renderer, _modelViewTransform, flags);
|
|
else
|
|
break;
|
|
}
|
|
|
|
for (auto size = _protectedChildren.size(); j < size; ++j)
|
|
{
|
|
auto node = _protectedChildren.at(j);
|
|
|
|
if (node && node->getLocalZOrder() < 0)
|
|
node->visit(renderer, _modelViewTransform, flags);
|
|
else
|
|
break;
|
|
}
|
|
|
|
//
|
|
// draw self
|
|
//
|
|
if (isVisitableByVisitingCamera())
|
|
this->draw(renderer, _modelViewTransform, flags);
|
|
|
|
//
|
|
// draw children and protectedChildren zOrder >= 0
|
|
//
|
|
for (auto it = _protectedChildren.cbegin() + j, itCend = _protectedChildren.cend(); it != itCend; ++it)
|
|
(*it)->visit(renderer, _modelViewTransform, flags);
|
|
|
|
for (auto it = _children.cbegin() + i, itCend = _children.cend(); it != itCend; ++it)
|
|
(*it)->visit(renderer, _modelViewTransform, flags);
|
|
|
|
// FIX ME: Why need to set _orderOfArrival to 0??
|
|
// Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920
|
|
// setOrderOfArrival(0);
|
|
|
|
_director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
|
}
|
|
|
|
void ProtectedNode::onEnter()
|
|
{
|
|
Node::onEnter();
|
|
for (const auto& child : _protectedChildren)
|
|
child->onEnter();
|
|
}
|
|
|
|
void ProtectedNode::onEnterTransitionDidFinish()
|
|
{
|
|
Node::onEnterTransitionDidFinish();
|
|
for (const auto& child : _protectedChildren)
|
|
child->onEnterTransitionDidFinish();
|
|
}
|
|
|
|
void ProtectedNode::onExitTransitionDidStart()
|
|
{
|
|
Node::onExitTransitionDidStart();
|
|
for (const auto& child : _protectedChildren)
|
|
child->onExitTransitionDidStart();
|
|
}
|
|
|
|
void ProtectedNode::onExit()
|
|
{
|
|
Node::onExit();
|
|
for (const auto& child : _protectedChildren)
|
|
child->onExit();
|
|
}
|
|
|
|
void ProtectedNode::updateDisplayedOpacity(uint8_t parentOpacity)
|
|
{
|
|
_displayedOpacity = _realOpacity * parentOpacity / 255.0;
|
|
updateColor();
|
|
|
|
if (_cascadeOpacityEnabled)
|
|
{
|
|
for (auto&& child : _children)
|
|
{
|
|
child->updateDisplayedOpacity(_displayedOpacity);
|
|
}
|
|
}
|
|
|
|
for (auto&& child : _protectedChildren)
|
|
{
|
|
child->updateDisplayedOpacity(_displayedOpacity);
|
|
}
|
|
}
|
|
|
|
void ProtectedNode::updateDisplayedColor(const Color3B& parentColor)
|
|
{
|
|
_displayedColor.r = _realColor.r * parentColor.r / 255.0;
|
|
_displayedColor.g = _realColor.g * parentColor.g / 255.0;
|
|
_displayedColor.b = _realColor.b * parentColor.b / 255.0;
|
|
updateColor();
|
|
|
|
if (_cascadeColorEnabled)
|
|
{
|
|
for (const auto& child : _children)
|
|
{
|
|
child->updateDisplayedColor(_displayedColor);
|
|
}
|
|
}
|
|
for (const auto& child : _protectedChildren)
|
|
{
|
|
child->updateDisplayedColor(_displayedColor);
|
|
}
|
|
}
|
|
|
|
void ProtectedNode::disableCascadeColor()
|
|
{
|
|
for (auto&& child : _children)
|
|
{
|
|
child->updateDisplayedColor(Color3B::WHITE);
|
|
}
|
|
for (auto&& child : _protectedChildren)
|
|
{
|
|
child->updateDisplayedColor(Color3B::WHITE);
|
|
}
|
|
}
|
|
|
|
void ProtectedNode::disableCascadeOpacity()
|
|
{
|
|
_displayedOpacity = _realOpacity;
|
|
|
|
for (auto&& child : _children)
|
|
{
|
|
child->updateDisplayedOpacity(255);
|
|
}
|
|
|
|
for (auto&& child : _protectedChildren)
|
|
{
|
|
child->updateDisplayedOpacity(255);
|
|
}
|
|
}
|
|
|
|
void ProtectedNode::setCameraMask(unsigned short mask, bool applyChildren)
|
|
{
|
|
Node::setCameraMask(mask, applyChildren);
|
|
if (applyChildren)
|
|
{
|
|
for (auto&& iter : _protectedChildren)
|
|
{
|
|
iter->setCameraMask(mask);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ProtectedNode::setGlobalZOrder(float globalZOrder)
|
|
{
|
|
Node::setGlobalZOrder(globalZOrder);
|
|
for (auto&& child : _protectedChildren)
|
|
child->setGlobalZOrder(globalZOrder);
|
|
}
|
|
|
|
NS_AX_END
|