diff --git a/cocos/gui/UILayout.cpp b/cocos/gui/UILayout.cpp index 9c7085432c..2e4ba0750f 100644 --- a/cocos/gui/UILayout.cpp +++ b/cocos/gui/UILayout.cpp @@ -25,6 +25,14 @@ #include "gui/UILayout.h" #include "gui/UIHelper.h" #include "extensions/GUI/CCControlExtension/CCScale9Sprite.h" +#include "kazmath/GL/matrix.h" +#include "CCGLProgram.h" +#include "CCShaderCache.h" +#include "CCDirector.h" +#include "CCDrawingPrimitives.h" +#include "CCRenderer.h" +#include "CCGroupCommand.h" +#include "CCCustomCommand.h" NS_CC_BEGIN @@ -34,6 +42,7 @@ static const int BACKGROUNDIMAGE_Z = (-1); static const int BCAKGROUNDCOLORRENDERER_Z = (-2); static GLint g_sStencilBits = -1; +static GLint s_layer = -1; Layout::Layout(): _clippingEnabled(false), @@ -54,11 +63,22 @@ _backGroundImageTextureSize(Size::ZERO), _layoutType(LAYOUT_ABSOLUTE), _clippingType(LAYOUT_CLIPPING_STENCIL), _clippingStencil(nullptr), -_handleScissor(false), _scissorRectDirty(false), _clippingRect(Rect::ZERO), _clippingParent(nullptr), -_doLayoutDirty(true) +_doLayoutDirty(true), +_currentStencilEnabled(GL_FALSE), +_currentStencilWriteMask(~0), +_currentStencilFunc(GL_ALWAYS), +_currentStencilRef(0), +_currentStencilValueMask(~0), +_currentStencilFail(GL_KEEP), +_currentStencilPassDepthFail(GL_KEEP), +_currentStencilPassDepthPass(GL_KEEP), +_currentDepthWriteMask(GL_TRUE), +_currentAlphaTestEnabled(GL_FALSE), +_currentAlphaTestFunc(GL_ALWAYS), +_currentAlphaTestRef(1) { _widgetType = WidgetTypeContainer; } @@ -66,6 +86,24 @@ _doLayoutDirty(true) Layout::~Layout() { } + +void Layout::onEnter() +{ + Widget::onEnter(); + if (_clippingStencil) + { + _clippingStencil->onEnter(); + } +} + +void Layout::onExit() +{ + Widget::onExit(); + if (_clippingStencil) + { + _clippingStencil->onExit(); + } +} Layout* Layout::create() { @@ -151,104 +189,150 @@ void Layout::sortAllChildren() void Layout::stencilClippingVisit() { - if (!_clippingStencil || !_clippingStencil->isVisible()) - { - Node::visit(); + if(!_visible) return; - } - if (g_sStencilBits < 1) + + kmGLPushMatrix(); + transform(); + //Add group command + + Renderer* renderer = Director::getInstance()->getRenderer(); + + _groupCommand.init(0,_vertexZ); + renderer->addCommand(&_groupCommand); + + renderer->pushGroup(_groupCommand.getRenderQueueID()); + + _beforeVisitCmdStencil.init(0,_vertexZ); + _beforeVisitCmdStencil.func = CC_CALLBACK_0(Layout::onBeforeVisitStencil, this); + renderer->addCommand(&_beforeVisitCmdStencil); + + _clippingStencil->visit(); + + _afterDrawStencilCmd.init(0,_vertexZ); + _afterDrawStencilCmd.func = CC_CALLBACK_0(Layout::onAfterDrawStencil, this); + renderer->addCommand(&_afterDrawStencilCmd); + + int i = 0; + + if(!_children.empty()) { - Node::visit(); - return; - } - static GLint layer = -1; - if (layer + 1 == g_sStencilBits) - { - static bool once = true; - if (once) + sortAllChildren(); + // draw children zOrder < 0 + for( ; i < _children.size(); i++ ) { - char warning[200] = {0}; - snprintf(warning, sizeof(warning), "Nesting more than %d stencils is not supported. Everything will be drawn without stencil for this node and its childs.", g_sStencilBits); - CCLOG("%s", warning); + auto node = _children.at(i); - once = false; + if ( node && node->getZOrder() < 0 ) + node->visit(); + else + break; } - Node::visit(); - return; + // self draw + this->draw(); + + for(auto it=_children.cbegin()+i; it != _children.cend(); ++it) + (*it)->visit(); } - layer++; - GLint mask_layer = 0x1 << layer; + else + { + this->draw(); + } + + _afterVisitCmdStencil.init(0,_vertexZ); + _afterVisitCmdStencil.func = CC_CALLBACK_0(Layout::onAfterVisitStencil, this); + renderer->addCommand(&_afterVisitCmdStencil); + + renderer->popGroup(); + + kmGLPopMatrix(); +} + +void Layout::onBeforeVisitStencil() +{ + s_layer++; + GLint mask_layer = 0x1 << s_layer; GLint mask_layer_l = mask_layer - 1; - GLint mask_layer_le = mask_layer | mask_layer_l; - GLboolean currentStencilEnabled = GL_FALSE; - GLuint currentStencilWriteMask = ~0; - GLenum currentStencilFunc = GL_ALWAYS; - GLint currentStencilRef = 0; - GLuint currentStencilValueMask = ~0; - GLenum currentStencilFail = GL_KEEP; - GLenum currentStencilPassDepthFail = GL_KEEP; - GLenum currentStencilPassDepthPass = GL_KEEP; - currentStencilEnabled = glIsEnabled(GL_STENCIL_TEST); - glGetIntegerv(GL_STENCIL_WRITEMASK, (GLint *)¤tStencilWriteMask); - glGetIntegerv(GL_STENCIL_FUNC, (GLint *)¤tStencilFunc); - glGetIntegerv(GL_STENCIL_REF, ¤tStencilRef); - glGetIntegerv(GL_STENCIL_VALUE_MASK, (GLint *)¤tStencilValueMask); - glGetIntegerv(GL_STENCIL_FAIL, (GLint *)¤tStencilFail); - glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, (GLint *)¤tStencilPassDepthFail); - glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, (GLint *)¤tStencilPassDepthPass); + _mask_layer_le = mask_layer | mask_layer_l; + _currentStencilEnabled = glIsEnabled(GL_STENCIL_TEST); + glGetIntegerv(GL_STENCIL_WRITEMASK, (GLint *)&_currentStencilWriteMask); + glGetIntegerv(GL_STENCIL_FUNC, (GLint *)&_currentStencilFunc); + glGetIntegerv(GL_STENCIL_REF, &_currentStencilRef); + glGetIntegerv(GL_STENCIL_VALUE_MASK, (GLint *)&_currentStencilValueMask); + glGetIntegerv(GL_STENCIL_FAIL, (GLint *)&_currentStencilFail); + glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, (GLint *)&_currentStencilPassDepthFail); + glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, (GLint *)&_currentStencilPassDepthPass); + glEnable(GL_STENCIL_TEST); CHECK_GL_ERROR_DEBUG(); glStencilMask(mask_layer); - GLboolean currentDepthWriteMask = GL_TRUE; - glGetBooleanv(GL_DEPTH_WRITEMASK, ¤tDepthWriteMask); + glGetBooleanv(GL_DEPTH_WRITEMASK, &_currentDepthWriteMask); glDepthMask(GL_FALSE); glStencilFunc(GL_NEVER, mask_layer, mask_layer); - glStencilOp(GL_ZERO, GL_KEEP, GL_KEEP); + glStencilOp(!false ? GL_ZERO : GL_REPLACE, GL_KEEP, GL_KEEP); kmGLMatrixMode(KM_GL_MODELVIEW); kmGLPushMatrix(); kmGLLoadIdentity(); + kmGLMatrixMode(KM_GL_PROJECTION); kmGLPushMatrix(); kmGLLoadIdentity(); + DrawPrimitives::drawSolidRect(Point(-1,-1), Point(1,1), Color4F(1, 1, 1, 1)); + kmGLMatrixMode(KM_GL_PROJECTION); kmGLPopMatrix(); kmGLMatrixMode(KM_GL_MODELVIEW); kmGLPopMatrix(); glStencilFunc(GL_NEVER, mask_layer, mask_layer); - glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP); + glStencilOp(!false ? GL_REPLACE : GL_ZERO, GL_KEEP, GL_KEEP); +} - kmGLPushMatrix(); - transform(); - _clippingStencil->visit(); - kmGLPopMatrix(); - glDepthMask(currentDepthWriteMask); - glStencilFunc(GL_EQUAL, mask_layer_le, mask_layer_le); +void Layout::onAfterDrawStencil() +{ + glDepthMask(_currentDepthWriteMask); + glStencilFunc(GL_EQUAL, _mask_layer_le, _mask_layer_le); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - Node::visit(); - glStencilFunc(currentStencilFunc, currentStencilRef, currentStencilValueMask); - glStencilOp(currentStencilFail, currentStencilPassDepthFail, currentStencilPassDepthPass); - glStencilMask(currentStencilWriteMask); - if (!currentStencilEnabled) +} + + +void Layout::onAfterVisitStencil() +{ + glStencilFunc(_currentStencilFunc, _currentStencilRef, _currentStencilValueMask); + glStencilOp(_currentStencilFail, _currentStencilPassDepthFail, _currentStencilPassDepthPass); + glStencilMask(_currentStencilWriteMask); + if (!_currentStencilEnabled) { glDisable(GL_STENCIL_TEST); } - layer--; + s_layer--; +} + +void Layout::onBeforeVisitScissor() +{ + Rect clippingRect = getClippingRect(); + glEnable(GL_SCISSOR_TEST); + EGLView::getInstance()->setScissorInPoints(clippingRect.origin.x, clippingRect.origin.y, clippingRect.size.width, clippingRect.size.height); +} + +void Layout::onAfterVisitScissor() +{ + glDisable(GL_SCISSOR_TEST); } void Layout::scissorClippingVisit() { - Rect clippingRect = getClippingRect(); - if (_handleScissor) - { - glEnable(GL_SCISSOR_TEST); - } - EGLView::getInstance()->setScissorInPoints(clippingRect.origin.x, clippingRect.origin.y, clippingRect.size.width, clippingRect.size.height); + Renderer* renderer = Director::getInstance()->getRenderer(); + + _beforeVisitCmdScissor.init(0, _vertexZ); + _beforeVisitCmdScissor.func = CC_CALLBACK_0(Layout::onBeforeVisitScissor, this); + renderer->addCommand(&_beforeVisitCmdScissor); + Node::visit(); - if (_handleScissor) - { - glDisable(GL_SCISSOR_TEST); - } + + _afterVisitCmdScissor.init(0, _vertexZ); + _afterVisitCmdScissor.func = CC_CALLBACK_0(Layout::onAfterVisitScissor, this); + renderer->addCommand(&_afterVisitCmdScissor); } void Layout::setClippingEnabled(bool able) @@ -263,15 +347,30 @@ void Layout::setClippingEnabled(bool able) case LAYOUT_CLIPPING_STENCIL: if (able) { - glGetIntegerv(GL_STENCIL_BITS, &g_sStencilBits); + static bool once = true; + if (once) + { + glGetIntegerv(GL_STENCIL_BITS, &g_sStencilBits); + if (g_sStencilBits <= 0) + { + CCLOG("Stencil buffer is not enabled."); + } + once = false; + } _clippingStencil = DrawNode::create(); - _clippingStencil->onEnter(); + if (_running) + { + _clippingStencil->onEnter(); + } _clippingStencil->retain(); setStencilClippingSize(_size); } else { - _clippingStencil->onExit(); + if (_running) + { + _clippingStencil->onExit(); + } _clippingStencil->release(); _clippingStencil = nullptr; } @@ -310,7 +409,6 @@ void Layout::setStencilClippingSize(const Size &size) const Rect& Layout::getClippingRect() { - _handleScissor = true; Point worldPos = convertToWorldSpace(Point::ZERO); AffineTransform t = nodeToWorldTransform(); float scissorWidth = _size.width*t.a; @@ -329,11 +427,6 @@ const Rect& Layout::getClippingRect() { _clippingParent = parent; firstClippingParentFounded = true; - } - - if (parent->_clippingType == LAYOUT_CLIPPING_SCISSOR) - { - _handleScissor = false; break; } } diff --git a/cocos/gui/UILayout.h b/cocos/gui/UILayout.h index 0feff5447e..5b0d3bd202 100644 --- a/cocos/gui/UILayout.h +++ b/cocos/gui/UILayout.h @@ -214,6 +214,9 @@ public: virtual void sortAllChildren() override; void requestDoLayout(); + + virtual void onEnter() override; + virtual void onExit() override; protected: //override "init" method of widget. virtual bool init() override; @@ -235,6 +238,14 @@ protected: void setStencilClippingSize(const Size& size); const Rect& getClippingRect(); virtual void doLayout(); + + //clipping + void onBeforeVisitStencil(); + void onAfterDrawStencil(); + void onAfterVisitStencil(); + + void onBeforeVisitScissor(); + void onAfterVisitScissor(); protected: bool _clippingEnabled; @@ -256,11 +267,35 @@ protected: LayoutType _layoutType; LayoutClippingType _clippingType; DrawNode* _clippingStencil; - bool _handleScissor; bool _scissorRectDirty; Rect _clippingRect; Layout* _clippingParent; bool _doLayoutDirty; + + //clipping + + GLboolean _currentStencilEnabled; + GLuint _currentStencilWriteMask; + GLenum _currentStencilFunc; + GLint _currentStencilRef; + GLuint _currentStencilValueMask; + GLenum _currentStencilFail; + GLenum _currentStencilPassDepthFail; + GLenum _currentStencilPassDepthPass; + GLboolean _currentDepthWriteMask; + + GLboolean _currentAlphaTestEnabled; + GLenum _currentAlphaTestFunc; + GLclampf _currentAlphaTestRef; + + GLint _mask_layer_le; + + GroupCommand _groupCommand; + CustomCommand _beforeVisitCmdStencil; + CustomCommand _afterDrawStencilCmd; + CustomCommand _afterVisitCmdStencil; + CustomCommand _beforeVisitCmdScissor; + CustomCommand _afterVisitCmdScissor; }; }