| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 |
- /****************************************************************************
- 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;
- }
- }
- 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
|