CCClippingNode.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /*
  2. * Copyright (c) 2012 Pierre-David Bélanger
  3. * Copyright (c) 2012 cocos2d-x.org
  4. * Copyright (c) 2013-2016 Chukong Technologies Inc.
  5. * Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
  6. *
  7. * cocos2d-x: http://www.cocos2d-x.org
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. */
  28. #include "2d/CCClippingNode.h"
  29. #include "2d/CCDrawingPrimitives.h"
  30. #include "renderer/CCGLProgramCache.h"
  31. #include "renderer/ccGLStateCache.h"
  32. #include "renderer/CCRenderer.h"
  33. #include "renderer/CCRenderState.h"
  34. #include "base/CCDirector.h"
  35. #include "base/CCStencilStateManager.h"
  36. #if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
  37. #define CC_CLIPPING_NODE_OPENGLES 0
  38. #else
  39. #define CC_CLIPPING_NODE_OPENGLES 1
  40. #endif
  41. NS_CC_BEGIN
  42. #if CC_CLIPPING_NODE_OPENGLES
  43. static void setProgram(Node *n, GLProgram *p)
  44. {
  45. n->setGLProgram(p);
  46. auto& children = n->getChildren();
  47. for(const auto &child : children) {
  48. setProgram(child, p);
  49. }
  50. }
  51. #endif
  52. ClippingNode::ClippingNode()
  53. : _stencil(nullptr)
  54. , _stencilStateManager(new StencilStateManager())
  55. , _originStencilProgram(nullptr)
  56. {
  57. }
  58. ClippingNode::~ClippingNode()
  59. {
  60. if (_stencil)
  61. {
  62. _stencil->stopAllActions();
  63. _stencil->release();
  64. }
  65. CC_SAFE_DELETE(_stencilStateManager);
  66. }
  67. ClippingNode* ClippingNode::create()
  68. {
  69. ClippingNode *ret = new (std::nothrow) ClippingNode();
  70. if (ret && ret->init())
  71. {
  72. ret->autorelease();
  73. }
  74. else
  75. {
  76. CC_SAFE_DELETE(ret);
  77. }
  78. return ret;
  79. }
  80. ClippingNode* ClippingNode::create(Node *pStencil)
  81. {
  82. ClippingNode *ret = new (std::nothrow) ClippingNode();
  83. if (ret && ret->init(pStencil))
  84. {
  85. ret->autorelease();
  86. }
  87. else
  88. {
  89. CC_SAFE_DELETE(ret);
  90. }
  91. return ret;
  92. }
  93. bool ClippingNode::init()
  94. {
  95. return init(nullptr);
  96. }
  97. bool ClippingNode::init(Node *stencil)
  98. {
  99. setStencil(stencil);
  100. return true;
  101. }
  102. void ClippingNode::onEnter()
  103. {
  104. #if CC_ENABLE_SCRIPT_BINDING
  105. if (_scriptType == kScriptTypeJavascript)
  106. {
  107. if (ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnter))
  108. return;
  109. }
  110. #endif
  111. Node::onEnter();
  112. if (_stencil != nullptr)
  113. {
  114. _stencil->onEnter();
  115. }
  116. else
  117. {
  118. CCLOG("ClippingNode warning: _stencil is nil.");
  119. }
  120. }
  121. void ClippingNode::onEnterTransitionDidFinish()
  122. {
  123. #if CC_ENABLE_SCRIPT_BINDING
  124. if (_scriptType == kScriptTypeJavascript)
  125. {
  126. if (ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnterTransitionDidFinish))
  127. return;
  128. }
  129. #endif
  130. Node::onEnterTransitionDidFinish();
  131. if (_stencil != nullptr)
  132. {
  133. _stencil->onEnterTransitionDidFinish();
  134. }
  135. }
  136. void ClippingNode::onExitTransitionDidStart()
  137. {
  138. #if CC_ENABLE_SCRIPT_BINDING
  139. if (_scriptType == kScriptTypeJavascript)
  140. {
  141. if (ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExitTransitionDidStart))
  142. return;
  143. }
  144. #endif
  145. if (_stencil != nullptr)
  146. {
  147. _stencil->onExitTransitionDidStart();
  148. }
  149. Node::onExitTransitionDidStart();
  150. }
  151. void ClippingNode::onExit()
  152. {
  153. #if CC_ENABLE_SCRIPT_BINDING
  154. if (_scriptType == kScriptTypeJavascript)
  155. {
  156. if (ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExit))
  157. return;
  158. }
  159. #endif
  160. if (_stencil != nullptr)
  161. {
  162. _stencil->onExit();
  163. }
  164. Node::onExit();
  165. }
  166. void ClippingNode::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags)
  167. {
  168. if (!_visible || !hasContent())
  169. return;
  170. uint32_t flags = processParentFlags(parentTransform, parentFlags);
  171. // IMPORTANT:
  172. // To ease the migration to v3.0, we still support the Mat4 stack,
  173. // but it is deprecated and your code should not rely on it
  174. Director* director = Director::getInstance();
  175. CCASSERT(nullptr != director, "Director is null when setting matrix stack");
  176. director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  177. director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
  178. //Add group command
  179. _groupCommand.init(_globalZOrder);
  180. renderer->addCommand(&_groupCommand);
  181. renderer->pushGroup(_groupCommand.getRenderQueueID());
  182. _beforeVisitCmd.init(_globalZOrder);
  183. _beforeVisitCmd.func = CC_CALLBACK_0(StencilStateManager::onBeforeVisit, _stencilStateManager);
  184. renderer->addCommand(&_beforeVisitCmd);
  185. auto alphaThreshold = this->getAlphaThreshold();
  186. if (alphaThreshold < 1)
  187. {
  188. #if CC_CLIPPING_NODE_OPENGLES
  189. // since glAlphaTest do not exists in OES, use a shader that writes
  190. // pixel only if greater than an alpha threshold
  191. GLProgram *program = GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_ALPHA_TEST_NO_MV);
  192. GLint alphaValueLocation = glGetUniformLocation(program->getProgram(), GLProgram::UNIFORM_NAME_ALPHA_TEST_VALUE);
  193. // set our alphaThreshold
  194. program->use();
  195. program->setUniformLocationWith1f(alphaValueLocation, alphaThreshold);
  196. // we need to recursively apply this shader to all the nodes in the stencil node
  197. // FIXME: we should have a way to apply shader to all nodes without having to do this
  198. setProgram(_stencil, program);
  199. #endif
  200. }
  201. _stencil->visit(renderer, _modelViewTransform, flags);
  202. _afterDrawStencilCmd.init(_globalZOrder);
  203. _afterDrawStencilCmd.func = CC_CALLBACK_0(StencilStateManager::onAfterDrawStencil, _stencilStateManager);
  204. renderer->addCommand(&_afterDrawStencilCmd);
  205. int i = 0;
  206. bool visibleByCamera = isVisitableByVisitingCamera();
  207. if(!_children.empty())
  208. {
  209. sortAllChildren();
  210. // draw children zOrder < 0
  211. for(auto size = _children.size(); i < size; ++i)
  212. {
  213. auto node = _children.at(i);
  214. if ( node && node->getLocalZOrder() < 0 )
  215. node->visit(renderer, _modelViewTransform, flags);
  216. else
  217. break;
  218. }
  219. // self draw
  220. if (visibleByCamera)
  221. this->draw(renderer, _modelViewTransform, flags);
  222. for(auto it=_children.cbegin()+i, itCend = _children.cend(); it != itCend; ++it)
  223. (*it)->visit(renderer, _modelViewTransform, flags);
  224. }
  225. else if (visibleByCamera)
  226. {
  227. this->draw(renderer, _modelViewTransform, flags);
  228. }
  229. _afterVisitCmd.init(_globalZOrder);
  230. _afterVisitCmd.func = CC_CALLBACK_0(StencilStateManager::onAfterVisit, _stencilStateManager);
  231. renderer->addCommand(&_afterVisitCmd);
  232. renderer->popGroup();
  233. director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  234. }
  235. void ClippingNode::setCameraMask(unsigned short mask, bool applyChildren)
  236. {
  237. Node::setCameraMask(mask, applyChildren);
  238. if (_stencil)
  239. _stencil->setCameraMask(mask, applyChildren);
  240. }
  241. Node* ClippingNode::getStencil() const
  242. {
  243. return _stencil;
  244. }
  245. void ClippingNode::setStencil(Node *stencil)
  246. {
  247. //early out if the stencil is already set
  248. if (_stencil == stencil)
  249. return;
  250. #if CC_ENABLE_GC_FOR_NATIVE_OBJECTS
  251. auto sEngine = ScriptEngineManager::getInstance()->getScriptEngine();
  252. if (sEngine)
  253. {
  254. if (_stencil)
  255. sEngine->releaseScriptObject(this, _stencil);
  256. if (stencil)
  257. sEngine->retainScriptObject(this, stencil);
  258. }
  259. #endif // CC_ENABLE_GC_FOR_NATIVE_OBJECTS
  260. //cleanup current stencil
  261. if(_stencil != nullptr && _stencil->isRunning())
  262. {
  263. _stencil->onExitTransitionDidStart();
  264. _stencil->onExit();
  265. }
  266. CC_SAFE_RELEASE_NULL(_stencil);
  267. //initialise new stencil
  268. _stencil = stencil;
  269. CC_SAFE_RETAIN(_stencil);
  270. if(_stencil != nullptr && this->isRunning())
  271. {
  272. _stencil->onEnter();
  273. if(this->_isTransitionFinished)
  274. {
  275. _stencil->onEnterTransitionDidFinish();
  276. }
  277. }
  278. if (_stencil != nullptr)
  279. _originStencilProgram = _stencil->getGLProgram();
  280. }
  281. bool ClippingNode::hasContent() const
  282. {
  283. return _children.size() > 0;
  284. }
  285. GLfloat ClippingNode::getAlphaThreshold() const
  286. {
  287. return _stencilStateManager->getAlphaThreshold();
  288. }
  289. void ClippingNode::setAlphaThreshold(GLfloat alphaThreshold)
  290. {
  291. #if CC_CLIPPING_NODE_OPENGLES
  292. if (alphaThreshold == 1 && alphaThreshold != _stencilStateManager->getAlphaThreshold())
  293. {
  294. // should reset program used by _stencil
  295. if (_stencil)
  296. setProgram(_stencil, _originStencilProgram);
  297. }
  298. #endif
  299. _stencilStateManager->setAlphaThreshold(alphaThreshold);
  300. }
  301. bool ClippingNode::isInverted() const
  302. {
  303. return _stencilStateManager->isInverted();
  304. }
  305. void ClippingNode::setInverted(bool inverted)
  306. {
  307. _stencilStateManager->setInverted(inverted);
  308. }
  309. NS_CC_END