123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /*
- * Copyright (c) 2012 Pierre-David Bélanger
- * Copyright (c) 2012 cocos2d-x.org
- * Copyright (c) 2013-2016 Chukong Technologies Inc.
- * Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
- *
- * cocos2d-x: 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 "2d/CCClippingNode.h"
- #include "2d/CCDrawingPrimitives.h"
- #include "renderer/CCGLProgramCache.h"
- #include "renderer/ccGLStateCache.h"
- #include "renderer/CCRenderer.h"
- #include "renderer/CCRenderState.h"
- #include "base/CCDirector.h"
- #include "base/CCStencilStateManager.h"
- #if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
- #define CC_CLIPPING_NODE_OPENGLES 0
- #else
- #define CC_CLIPPING_NODE_OPENGLES 1
- #endif
- NS_CC_BEGIN
- #if CC_CLIPPING_NODE_OPENGLES
- static void setProgram(Node *n, GLProgram *p)
- {
- n->setGLProgram(p);
-
- auto& children = n->getChildren();
- for(const auto &child : children) {
- setProgram(child, p);
- }
- }
- #endif
- ClippingNode::ClippingNode()
- : _stencil(nullptr)
- , _stencilStateManager(new StencilStateManager())
- , _originStencilProgram(nullptr)
- {
- }
- ClippingNode::~ClippingNode()
- {
- if (_stencil)
- {
- _stencil->stopAllActions();
- _stencil->release();
- }
- CC_SAFE_DELETE(_stencilStateManager);
- }
- ClippingNode* ClippingNode::create()
- {
- ClippingNode *ret = new (std::nothrow) ClippingNode();
- if (ret && ret->init())
- {
- ret->autorelease();
- }
- else
- {
- CC_SAFE_DELETE(ret);
- }
-
- return ret;
- }
- ClippingNode* ClippingNode::create(Node *pStencil)
- {
- ClippingNode *ret = new (std::nothrow) ClippingNode();
- if (ret && ret->init(pStencil))
- {
- ret->autorelease();
- }
- else
- {
- CC_SAFE_DELETE(ret);
- }
-
- return ret;
- }
- bool ClippingNode::init()
- {
- return init(nullptr);
- }
- bool ClippingNode::init(Node *stencil)
- {
- setStencil(stencil);
- return true;
- }
- void ClippingNode::onEnter()
- {
- #if CC_ENABLE_SCRIPT_BINDING
- if (_scriptType == kScriptTypeJavascript)
- {
- if (ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnter))
- return;
- }
- #endif
-
- Node::onEnter();
-
- if (_stencil != nullptr)
- {
- _stencil->onEnter();
- }
- else
- {
- CCLOG("ClippingNode warning: _stencil is nil.");
- }
- }
- void ClippingNode::onEnterTransitionDidFinish()
- {
- #if CC_ENABLE_SCRIPT_BINDING
- if (_scriptType == kScriptTypeJavascript)
- {
- if (ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnterTransitionDidFinish))
- return;
- }
- #endif
-
- Node::onEnterTransitionDidFinish();
-
- if (_stencil != nullptr)
- {
- _stencil->onEnterTransitionDidFinish();
- }
- }
- void ClippingNode::onExitTransitionDidStart()
- {
- #if CC_ENABLE_SCRIPT_BINDING
- if (_scriptType == kScriptTypeJavascript)
- {
- if (ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExitTransitionDidStart))
- return;
- }
- #endif
-
- if (_stencil != nullptr)
- {
- _stencil->onExitTransitionDidStart();
- }
-
- Node::onExitTransitionDidStart();
- }
- void ClippingNode::onExit()
- {
- #if CC_ENABLE_SCRIPT_BINDING
- if (_scriptType == kScriptTypeJavascript)
- {
- if (ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExit))
- return;
- }
- #endif
-
- if (_stencil != nullptr)
- {
- _stencil->onExit();
- }
-
- Node::onExit();
- }
- void ClippingNode::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags)
- {
- if (!_visible || !hasContent())
- 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* director = Director::getInstance();
- CCASSERT(nullptr != director, "Director is null when setting matrix stack");
- director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
- director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
- //Add group command
-
- _groupCommand.init(_globalZOrder);
- renderer->addCommand(&_groupCommand);
- renderer->pushGroup(_groupCommand.getRenderQueueID());
- _beforeVisitCmd.init(_globalZOrder);
- _beforeVisitCmd.func = CC_CALLBACK_0(StencilStateManager::onBeforeVisit, _stencilStateManager);
- renderer->addCommand(&_beforeVisitCmd);
-
- auto alphaThreshold = this->getAlphaThreshold();
- if (alphaThreshold < 1)
- {
- #if CC_CLIPPING_NODE_OPENGLES
- // since glAlphaTest do not exists in OES, use a shader that writes
- // pixel only if greater than an alpha threshold
- GLProgram *program = GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_ALPHA_TEST_NO_MV);
- GLint alphaValueLocation = glGetUniformLocation(program->getProgram(), GLProgram::UNIFORM_NAME_ALPHA_TEST_VALUE);
- // set our alphaThreshold
- program->use();
- program->setUniformLocationWith1f(alphaValueLocation, alphaThreshold);
- // we need to recursively apply this shader to all the nodes in the stencil node
- // FIXME: we should have a way to apply shader to all nodes without having to do this
- setProgram(_stencil, program);
- #endif
- }
- _stencil->visit(renderer, _modelViewTransform, flags);
- _afterDrawStencilCmd.init(_globalZOrder);
- _afterDrawStencilCmd.func = CC_CALLBACK_0(StencilStateManager::onAfterDrawStencil, _stencilStateManager);
- renderer->addCommand(&_afterDrawStencilCmd);
- int i = 0;
- bool visibleByCamera = isVisitableByVisitingCamera();
-
- if(!_children.empty())
- {
- sortAllChildren();
- // draw children 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;
- }
- // self draw
- if (visibleByCamera)
- this->draw(renderer, _modelViewTransform, flags);
- for(auto it=_children.cbegin()+i, itCend = _children.cend(); it != itCend; ++it)
- (*it)->visit(renderer, _modelViewTransform, flags);
- }
- else if (visibleByCamera)
- {
- this->draw(renderer, _modelViewTransform, flags);
- }
- _afterVisitCmd.init(_globalZOrder);
- _afterVisitCmd.func = CC_CALLBACK_0(StencilStateManager::onAfterVisit, _stencilStateManager);
- renderer->addCommand(&_afterVisitCmd);
- renderer->popGroup();
-
- director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
- }
- void ClippingNode::setCameraMask(unsigned short mask, bool applyChildren)
- {
- Node::setCameraMask(mask, applyChildren);
-
- if (_stencil)
- _stencil->setCameraMask(mask, applyChildren);
- }
- Node* ClippingNode::getStencil() const
- {
- return _stencil;
- }
- void ClippingNode::setStencil(Node *stencil)
- {
- //early out if the stencil is already set
- if (_stencil == stencil)
- return;
-
- #if CC_ENABLE_GC_FOR_NATIVE_OBJECTS
- auto sEngine = ScriptEngineManager::getInstance()->getScriptEngine();
- if (sEngine)
- {
- if (_stencil)
- sEngine->releaseScriptObject(this, _stencil);
- if (stencil)
- sEngine->retainScriptObject(this, stencil);
- }
- #endif // CC_ENABLE_GC_FOR_NATIVE_OBJECTS
-
- //cleanup current stencil
- if(_stencil != nullptr && _stencil->isRunning())
- {
- _stencil->onExitTransitionDidStart();
- _stencil->onExit();
- }
- CC_SAFE_RELEASE_NULL(_stencil);
-
- //initialise new stencil
- _stencil = stencil;
- CC_SAFE_RETAIN(_stencil);
- if(_stencil != nullptr && this->isRunning())
- {
- _stencil->onEnter();
- if(this->_isTransitionFinished)
- {
- _stencil->onEnterTransitionDidFinish();
- }
- }
-
- if (_stencil != nullptr)
- _originStencilProgram = _stencil->getGLProgram();
- }
- bool ClippingNode::hasContent() const
- {
- return _children.size() > 0;
- }
- GLfloat ClippingNode::getAlphaThreshold() const
- {
- return _stencilStateManager->getAlphaThreshold();
- }
- void ClippingNode::setAlphaThreshold(GLfloat alphaThreshold)
- {
- #if CC_CLIPPING_NODE_OPENGLES
- if (alphaThreshold == 1 && alphaThreshold != _stencilStateManager->getAlphaThreshold())
- {
- // should reset program used by _stencil
- if (_stencil)
- setProgram(_stencil, _originStencilProgram);
- }
- #endif
-
- _stencilStateManager->setAlphaThreshold(alphaThreshold);
- }
- bool ClippingNode::isInverted() const
- {
- return _stencilStateManager->isInverted();
- }
- void ClippingNode::setInverted(bool inverted)
- {
- _stencilStateManager->setInverted(inverted);
- }
- NS_CC_END
|