mirror of
				https://github.com/smallmain/cocos-enhance-kit.git
				synced 2025-11-04 04:25:23 +00:00 
			
		
		
		
	
		
			
	
	
		
			588 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			588 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								/****************************************************************************
							 | 
						||
| 
								 | 
							
								 Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								 http://www.cocos2d-x.org
							 | 
						||
| 
								 | 
							
								 
							 | 
						||
| 
								 | 
							
								 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 "NodeProxy.hpp"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <string>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "ModelBatcher.hpp"
							 | 
						||
| 
								 | 
							
								#include "../renderer/Scene.h"
							 | 
						||
| 
								 | 
							
								#include "base/ccMacros.h"
							 | 
						||
| 
								 | 
							
								#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
							 | 
						||
| 
								 | 
							
								#include "cocos/scripting/js-bindings/manual/jsb_conversions.hpp"
							 | 
						||
| 
								 | 
							
								#include "cocos/scripting/js-bindings/auto/jsb_renderer_auto.hpp"
							 | 
						||
| 
								 | 
							
								#include "NodeMemPool.hpp"
							 | 
						||
| 
								 | 
							
								#include <math.h>
							 | 
						||
| 
								 | 
							
								#include "RenderFlow.hpp"
							 | 
						||
| 
								 | 
							
								#include "assembler/AssemblerSprite.hpp"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RENDERER_BEGIN
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								uint32_t NodeProxy::_globalRenderOrder = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								NodeProxy::NodeProxy(std::size_t unitID, std::size_t index, const std::string& id, const std::string& name)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    traverseHandle = render;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    _id = id;
							 | 
						||
| 
								 | 
							
								    _unitID = unitID;
							 | 
						||
| 
								 | 
							
								    _index = index;
							 | 
						||
| 
								 | 
							
								    _name = name;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    NodeMemPool* pool = NodeMemPool::getInstance();
							 | 
						||
| 
								 | 
							
								    CCASSERT(pool, "NodeProxy constructor NodeMemPool is null");
							 | 
						||
| 
								 | 
							
								    UnitNode* unit = pool->getUnit(unitID);
							 | 
						||
| 
								 | 
							
								    CCASSERT(unit, "NodeProxy constructor unit is null");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    UnitCommon* common = pool->getCommonUnit(unitID);
							 | 
						||
| 
								 | 
							
								    _signData = common->getSignData(_index);
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    _dirty = unit->getDirty(index);
							 | 
						||
| 
								 | 
							
								    *_dirty &= ~RenderFlow::PRE_CALCULATE_VERTICES;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    _trs = unit->getTRS(index);
							 | 
						||
| 
								 | 
							
								    _localMat = unit->getLocalMat(index);
							 | 
						||
| 
								 | 
							
								    _worldMat = unit->getWorldMat(index);
							 | 
						||
| 
								 | 
							
								    _parentInfo = unit->getParent(index);
							 | 
						||
| 
								 | 
							
								    _parentInfo->unitID = PARENT_INVALID;
							 | 
						||
| 
								 | 
							
								    _parentInfo->index = PARENT_INVALID;
							 | 
						||
| 
								 | 
							
								    _localZOrder = unit->getZOrder(index);
							 | 
						||
| 
								 | 
							
								    _cullingMask = unit->getCullingMask(index);
							 | 
						||
| 
								 | 
							
								    _opacity = unit->getOpacity(index);
							 | 
						||
| 
								 | 
							
								    _is3DNode = unit->getIs3D(index);
							 | 
						||
| 
								 | 
							
								    _skew = unit->getSkew(index);
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    uint64_t* self = unit->getNode(index);
							 | 
						||
| 
								 | 
							
								    *self = (uint64_t)this;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								NodeProxy::~NodeProxy()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    for (auto& child : _children)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        child->_parent = nullptr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    CC_SAFE_RELEASE(_assembler);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::destroyImmediately()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (_parent)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        _parent->removeChild(this);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    RenderFlow::getInstance()->removeNodeLevel(_level, _worldMat);
							 | 
						||
| 
								 | 
							
								    CC_SAFE_RELEASE_NULL(_assembler);
							 | 
						||
| 
								 | 
							
								    _level = NODE_LEVEL_INVALID;
							 | 
						||
| 
								 | 
							
								    _dirty = nullptr;
							 | 
						||
| 
								 | 
							
								    _trs = nullptr;
							 | 
						||
| 
								 | 
							
								    _localMat = nullptr;
							 | 
						||
| 
								 | 
							
								    _worldMat = nullptr;
							 | 
						||
| 
								 | 
							
								    _parentInfo = nullptr;
							 | 
						||
| 
								 | 
							
								    _localZOrder = nullptr;
							 | 
						||
| 
								 | 
							
								    _cullingMask = nullptr;
							 | 
						||
| 
								 | 
							
								    _opacity = nullptr;
							 | 
						||
| 
								 | 
							
								    _is3DNode = nullptr;
							 | 
						||
| 
								 | 
							
								    _skew = nullptr;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// lazy allocs
							 | 
						||
| 
								 | 
							
								void NodeProxy::childrenAlloc()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    _children.reserve(4);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::addChild(NodeProxy* child)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (child == nullptr)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        CCLOGWARN("Argument must be non-nil");
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (child->_parent != nullptr)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        CCLOGWARN("child already added. It can't be added again");
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    auto assertNotSelfChild
							 | 
						||
| 
								 | 
							
								        ( [ this, child ]() -> bool
							 | 
						||
| 
								 | 
							
								          {
							 | 
						||
| 
								 | 
							
								              for ( NodeProxy* parent( this ); parent != nullptr;
							 | 
						||
| 
								 | 
							
								                    parent = parent->getParent() )
							 | 
						||
| 
								 | 
							
								                  if ( parent == child )
							 | 
						||
| 
								 | 
							
								                      return false;
							 | 
						||
| 
								 | 
							
								              
							 | 
						||
| 
								 | 
							
								              return true;
							 | 
						||
| 
								 | 
							
								          } );
							 | 
						||
| 
								 | 
							
								    (void)assertNotSelfChild;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    if (!assertNotSelfChild())
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        CCLOGWARN("A node cannot be the child of his own children" );
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    if (_children.empty())
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        this->childrenAlloc();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    _children.pushBack(child);
							 | 
						||
| 
								 | 
							
								    child->setParent(this);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::detachChild(NodeProxy *child, ssize_t childIndex)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // set parent nil at the end
							 | 
						||
| 
								 | 
							
								    child->setParent(nullptr);
							 | 
						||
| 
								 | 
							
								    _children.erase(childIndex);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::removeChild(NodeProxy* child)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // explicit nil handling
							 | 
						||
| 
								 | 
							
								    if (_children.empty())
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ssize_t index = _children.getIndex(child);
							 | 
						||
| 
								 | 
							
								    if( index != CC_INVALID_INDEX )
							 | 
						||
| 
								 | 
							
								        this->detachChild( child, index );
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::removeAllChildren()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // not using detachChild improves speed here
							 | 
						||
| 
								 | 
							
								    for (const auto& child : _children)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        // set parent nil at the end
							 | 
						||
| 
								 | 
							
								        child->setParent(nullptr);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    _children.clear();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								NodeProxy* NodeProxy::getChildByName(std::string childName)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    for (auto child : _children)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if (child->_name == childName)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return child;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return nullptr;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								NodeProxy* NodeProxy::getChildByID(std::string id)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    for (auto child : _children)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if (child->_id == id)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            return child;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return nullptr;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::notifyUpdateParent()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (_parentInfo->index == PARENT_INVALID)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if (_parent)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _parent->removeChild(this);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        updateLevel();
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    NodeMemPool* pool = NodeMemPool::getInstance();
							 | 
						||
| 
								 | 
							
								    CCASSERT(pool, "NodeProxy updateParent NodeMemPool is null");
							 | 
						||
| 
								 | 
							
								    UnitNode* unit = pool->getUnit(_parentInfo->unitID);
							 | 
						||
| 
								 | 
							
								    CCASSERT(unit, "NodeProxy updateParent unit is null");
							 | 
						||
| 
								 | 
							
								    uint64_t* parentAddrs = unit->getNode(_parentInfo->index);
							 | 
						||
| 
								 | 
							
								    NodeProxy* parent = (NodeProxy*)*parentAddrs;
							 | 
						||
| 
								 | 
							
								    CCASSERT(parent, "NodeProxy updateParent parent is null");
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    if (parent != _parent) {
							 | 
						||
| 
								 | 
							
								        if (_parent)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _parent->removeChild(this);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        parent->addChild(this);
							 | 
						||
| 
								 | 
							
								        updateLevel();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::updateLevel()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    static RenderFlow::LevelInfo levelInfo;
							 | 
						||
| 
								 | 
							
								    auto renderFlow = RenderFlow::getInstance();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    renderFlow->removeNodeLevel(_level, _worldMat);
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    levelInfo.dirty = _dirty;
							 | 
						||
| 
								 | 
							
								    levelInfo.localMat = _localMat;
							 | 
						||
| 
								 | 
							
								    levelInfo.worldMat = _worldMat;
							 | 
						||
| 
								 | 
							
								    levelInfo.opacity = _opacity;
							 | 
						||
| 
								 | 
							
								    levelInfo.realOpacity = &_realOpacity;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    if (_parent)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        _level = _parent->_level + 1;
							 | 
						||
| 
								 | 
							
								        levelInfo.parentWorldMat = _parent->_worldMat;
							 | 
						||
| 
								 | 
							
								        levelInfo.parentDirty = _parent->_dirty;
							 | 
						||
| 
								 | 
							
								        levelInfo.parentRealOpacity = &_parent->_realOpacity;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        _level = 0;
							 | 
						||
| 
								 | 
							
								        levelInfo.parentWorldMat = nullptr;
							 | 
						||
| 
								 | 
							
								        levelInfo.parentDirty = nullptr;
							 | 
						||
| 
								 | 
							
								        levelInfo.parentRealOpacity = nullptr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    renderFlow->insertNodeLevel(_level, levelInfo);
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    for (auto it = _children.begin(); it != _children.end(); it++)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        (*it)->updateLevel();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::setLocalZOrder(int zOrder)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (*_localZOrder != zOrder)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        *_localZOrder = zOrder;
							 | 
						||
| 
								 | 
							
								        if (_parent != nullptr)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            *_parent->_dirty |= RenderFlow::REORDER_CHILDREN;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::reorderChildren()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (*_dirty & RenderFlow::REORDER_CHILDREN)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								#if CC_64BITS
							 | 
						||
| 
								 | 
							
								        std::sort(std::begin(_children), std::end(_children), [](NodeProxy* n1, NodeProxy* n2) {
							 | 
						||
| 
								 | 
							
								            return (*n1->_localZOrder < *n2->_localZOrder);
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								        std::stable_sort(std::begin(_children), std::end(_children), [](NodeProxy* n1, NodeProxy* n2) {
							 | 
						||
| 
								 | 
							
								            return *n1->_localZOrder < *n2->_localZOrder;
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								        *_dirty &= ~RenderFlow::REORDER_CHILDREN;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::setAssembler(AssemblerBase* assembler)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (assembler == _assembler) return;
							 | 
						||
| 
								 | 
							
								    CC_SAFE_RELEASE(_assembler);
							 | 
						||
| 
								 | 
							
								    _assembler = assembler;
							 | 
						||
| 
								 | 
							
								    CC_SAFE_RETAIN(_assembler);
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    auto assemblerSprite = dynamic_cast<AssemblerSprite*>(_assembler);
							 | 
						||
| 
								 | 
							
								    if (assemblerSprite)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        *_dirty |= RenderFlow::PRE_CALCULATE_VERTICES;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        *_dirty &= ~RenderFlow::PRE_CALCULATE_VERTICES;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::clearAssembler()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CC_SAFE_RELEASE_NULL(_assembler);
							 | 
						||
| 
								 | 
							
								    *_dirty &= ~RenderFlow::PRE_CALCULATE_VERTICES;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								AssemblerBase* NodeProxy::getAssembler() const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return _assembler;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::getPosition(cocos2d::Vec3* out) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    out->x = _trs->x;
							 | 
						||
| 
								 | 
							
								    out->y = _trs->y;
							 | 
						||
| 
								 | 
							
								    out->z = _trs->z;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::getRotation(cocos2d::Quaternion* out) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    out->x = _trs->qx;
							 | 
						||
| 
								 | 
							
								    out->y = _trs->qy;
							 | 
						||
| 
								 | 
							
								    out->z = _trs->qz;
							 | 
						||
| 
								 | 
							
								    out->w = _trs->qw;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::getScale(cocos2d::Vec3* out) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    out->x = _trs->sx;
							 | 
						||
| 
								 | 
							
								    out->y = _trs->sy;
							 | 
						||
| 
								 | 
							
								    out->z = _trs->sz;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::getWorldRotation(cocos2d::Quaternion* out) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    getRotation(out);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    cocos2d::Quaternion rot;
							 | 
						||
| 
								 | 
							
								    NodeProxy* curr = _parent;
							 | 
						||
| 
								 | 
							
								    while (curr != nullptr)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        curr->getRotation(&rot);
							 | 
						||
| 
								 | 
							
								        Quaternion::multiply(rot, *out, out);
							 | 
						||
| 
								 | 
							
								        curr = curr->getParent();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::getWorldPosition(cocos2d::Vec3* out) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    getPosition(out);
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    cocos2d::Vec3 pos;
							 | 
						||
| 
								 | 
							
								    cocos2d::Quaternion rot;
							 | 
						||
| 
								 | 
							
								    cocos2d::Vec3 scale;
							 | 
						||
| 
								 | 
							
								    NodeProxy* curr = _parent;
							 | 
						||
| 
								 | 
							
								    while (curr != nullptr)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        curr->getPosition(&pos);
							 | 
						||
| 
								 | 
							
								        curr->getRotation(&rot);
							 | 
						||
| 
								 | 
							
								        curr->getScale(&scale);
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        out->multiply(scale);
							 | 
						||
| 
								 | 
							
								        out->transformQuat(rot);
							 | 
						||
| 
								 | 
							
								        out->add(pos);
							 | 
						||
| 
								 | 
							
								        curr = curr->getParent();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::getWorldRT(cocos2d::Mat4* out) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    cocos2d::Vec3 opos(_trs->x, _trs->y, _trs->z);
							 | 
						||
| 
								 | 
							
								    cocos2d::Quaternion orot(_trs->qx, _trs->qy, _trs->qz, _trs->qw);
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    cocos2d::Vec3 pos;
							 | 
						||
| 
								 | 
							
								    cocos2d::Quaternion rot;
							 | 
						||
| 
								 | 
							
								    cocos2d::Vec3 scale;
							 | 
						||
| 
								 | 
							
								    NodeProxy* curr = _parent;
							 | 
						||
| 
								 | 
							
								    while (curr != nullptr)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        curr->getPosition(&pos);
							 | 
						||
| 
								 | 
							
								        curr->getRotation(&rot);
							 | 
						||
| 
								 | 
							
								        curr->getScale(&scale);
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        opos.multiply(scale);
							 | 
						||
| 
								 | 
							
								        opos.transformQuat(rot);
							 | 
						||
| 
								 | 
							
								        opos.add(pos);
							 | 
						||
| 
								 | 
							
								        Quaternion::multiply(rot, orot, &orot);
							 | 
						||
| 
								 | 
							
								        curr = curr->getParent();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    out->setIdentity();
							 | 
						||
| 
								 | 
							
								    out->translate(opos);
							 | 
						||
| 
								 | 
							
								    cocos2d::Mat4 quatMat;
							 | 
						||
| 
								 | 
							
								    cocos2d::Mat4::createRotation(orot, &quatMat);
							 | 
						||
| 
								 | 
							
								    out->multiply(quatMat);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::setOpacity(uint8_t opacity)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (*_opacity != opacity)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        *_opacity = opacity;
							 | 
						||
| 
								 | 
							
								        *_dirty |= RenderFlow::OPACITY;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::updateRealOpacity()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    bool selfOpacityDirty = *_dirty & RenderFlow::OPACITY;
							 | 
						||
| 
								 | 
							
								    if (_parent)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if (selfOpacityDirty || *_parent->_dirty & RenderFlow::NODE_OPACITY_CHANGED)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _realOpacity = *_opacity * _parent->getRealOpacity() / 255.0f;
							 | 
						||
| 
								 | 
							
								            *_dirty &= ~RenderFlow::OPACITY;
							 | 
						||
| 
								 | 
							
								            *_dirty |= RenderFlow::NODE_OPACITY_CHANGED;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if (selfOpacityDirty)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _realOpacity = *_opacity;
							 | 
						||
| 
								 | 
							
								            *_dirty &= ~RenderFlow::OPACITY;
							 | 
						||
| 
								 | 
							
								            *_dirty |= RenderFlow::NODE_OPACITY_CHANGED;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::updateWorldMatrix()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (!_updateWorldMatrix) return;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    bool selfWorldDirty = *_dirty & RenderFlow::WORLD_TRANSFORM;
							 | 
						||
| 
								 | 
							
								    if (_parent)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if (selfWorldDirty || *_parent->_dirty & RenderFlow::WORLD_TRANSFORM_CHANGED)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            cocos2d::Mat4::multiply(_parent->getWorldMatrix(), *_localMat, _worldMat);
							 | 
						||
| 
								 | 
							
								            *_dirty &= ~RenderFlow::WORLD_TRANSFORM;
							 | 
						||
| 
								 | 
							
								            *_dirty |= RenderFlow::WORLD_TRANSFORM_CHANGED;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else if (selfWorldDirty)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        *_worldMat = *_localMat;
							 | 
						||
| 
								 | 
							
								        *_dirty &= ~RenderFlow::WORLD_TRANSFORM;
							 | 
						||
| 
								 | 
							
								        *_dirty |= RenderFlow::WORLD_TRANSFORM_CHANGED;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::updateWorldMatrix(const cocos2d::Mat4& worldMatrix)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    *_worldMat = worldMatrix;
							 | 
						||
| 
								 | 
							
								    *_dirty &= ~RenderFlow::WORLD_TRANSFORM;
							 | 
						||
| 
								 | 
							
								    *_dirty |= RenderFlow::WORLD_TRANSFORM_CHANGED;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::updateLocalMatrix()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    bool skew = std::abs(_skew->x - 0.0f) > MATH_EPSILON || std::abs(_skew->y - 0.0f) > MATH_EPSILON;
							 | 
						||
| 
								 | 
							
								    if (*_dirty & RenderFlow::LOCAL_TRANSFORM || skew)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        _localMat->setIdentity();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Transform = Translate * Rotation * Scale;
							 | 
						||
| 
								 | 
							
								        cocos2d::Quaternion q(_trs->qx, _trs->qy, _trs->qz, _trs->qw);
							 | 
						||
| 
								 | 
							
								        if (*_is3DNode)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _localMat->translate(_trs->x, _trs->y, _trs->z);
							 | 
						||
| 
								 | 
							
								            _localMat->rotate(q);
							 | 
						||
| 
								 | 
							
								            _localMat->scale(_trs->sx, _trs->sy, _trs->sz);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            _localMat->translate(_trs->x, _trs->y, 0);
							 | 
						||
| 
								 | 
							
								            _localMat->rotate(q);
							 | 
						||
| 
								 | 
							
								            _localMat->scale(_trs->sx, _trs->sy, 1);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        if (skew)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            auto& m = _localMat->m;
							 | 
						||
| 
								 | 
							
								            auto a = m[0];
							 | 
						||
| 
								 | 
							
								            auto b = m[1];
							 | 
						||
| 
								 | 
							
								            auto c = m[4];
							 | 
						||
| 
								 | 
							
								            auto d = m[5];
							 | 
						||
| 
								 | 
							
								            auto skx = (float)tanf(CC_DEGREES_TO_RADIANS(_skew->x));
							 | 
						||
| 
								 | 
							
								            auto sky = (float)tanf(CC_DEGREES_TO_RADIANS(_skew->y));
							 | 
						||
| 
								 | 
							
								            m[0] = a + c * sky;
							 | 
						||
| 
								 | 
							
								            m[1] = b + d * sky;
							 | 
						||
| 
								 | 
							
								            m[4] = c + a * skx;
							 | 
						||
| 
								 | 
							
								            m[5] = d + b * skx;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        *_dirty &= ~RenderFlow::LOCAL_TRANSFORM;
							 | 
						||
| 
								 | 
							
								        *_dirty |= RenderFlow::WORLD_TRANSFORM;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::render(NodeProxy* node, ModelBatcher* batcher, Scene* scene)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    node->_renderOrder = _globalRenderOrder++;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    if (!node->_needVisit || node->_realOpacity == 0) return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool needRender = *node->_dirty & RenderFlow::RENDER;
							 | 
						||
| 
								 | 
							
								    if (node->_needRender != needRender)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if (node->_assembler) node->_assembler->enableDirty(AssemblerBase::VERTICES_OPACITY_CHANGED);
							 | 
						||
| 
								 | 
							
								        node->_needRender = needRender;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    // pre render
							 | 
						||
| 
								 | 
							
								    if (node->_assembler && needRender) node->_assembler->handle(node, batcher, scene);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    node->reorderChildren();
							 | 
						||
| 
								 | 
							
								    for (const auto& child : node->_children)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        auto traverseHandle = child->traverseHandle;
							 | 
						||
| 
								 | 
							
								        traverseHandle(child, batcher, scene);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // post render
							 | 
						||
| 
								 | 
							
								    bool needPostRender = *(node->_dirty) & RenderFlow::POST_RENDER;
							 | 
						||
| 
								 | 
							
								    if (node->_assembler && needPostRender) node->_assembler->postHandle(node, batcher, scene);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void NodeProxy::visit(NodeProxy* node, ModelBatcher* batcher, Scene* scene)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    node->_renderOrder = _globalRenderOrder++;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    if (!node->_needVisit) return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    node->updateRealOpacity();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (node->_realOpacity == 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    node->updateLocalMatrix();
							 | 
						||
| 
								 | 
							
								    node->updateWorldMatrix();
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    bool needRender = *(node->_dirty) & RenderFlow::RENDER;
							 | 
						||
| 
								 | 
							
								    if (node->_needRender != needRender)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if (node->_assembler) node->_assembler->enableDirty(AssemblerBase::VERTICES_OPACITY_CHANGED);
							 | 
						||
| 
								 | 
							
								        node->_needRender = needRender;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    // pre render
							 | 
						||
| 
								 | 
							
								    if (node->_assembler && needRender) node->_assembler->handle(node, batcher, scene);
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    node->reorderChildren();
							 | 
						||
| 
								 | 
							
								    for (const auto& child : node->_children)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        visit(child, batcher, scene);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    // post render
							 | 
						||
| 
								 | 
							
								    bool needPostRender = *(node->_dirty) & RenderFlow::POST_RENDER;
							 | 
						||
| 
								 | 
							
								    if (node->_assembler && needPostRender) node->_assembler->postHandle(node, batcher, scene);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RENDERER_END
							 |