Fix Clipping Node

This commit is contained in:
Nite Luo 2013-11-18 14:58:41 -08:00
parent e5ebcb2845
commit c288e5ef9c
6 changed files with 80 additions and 31 deletions

View File

@ -4,6 +4,7 @@
#include "CCNewDrawNode.h" #include "CCNewDrawNode.h"
#include "QuadCommand.h"
NS_CC_BEGIN NS_CC_BEGIN
@ -39,7 +40,9 @@ bool NewDrawNode::init()
void NewDrawNode::draw() void NewDrawNode::draw()
{ {
updateTransform();
// QuadCommand* quadCommand = new QuadCommand(0, _vertexZ, 0, _shaderProgram, _blendFunc, )
} }
NS_CC_END NS_CC_END

View File

@ -114,7 +114,7 @@ void NewSprite::draw(void)
{ {
updateTransform(); updateTransform();
//TODO implement z order //TODO implement z order
QuadCommand* renderCommand = new QuadCommand(0, _vertexZ,_texture->getName(), _shaderProgram, _blendFunc, &_quad, 1); QuadCommand* renderCommand = new QuadCommand(0, _vertexZ, _texture->getName(), _shaderProgram, _blendFunc, &_quad, 1);
Renderer::getInstance()->addCommand(renderCommand); Renderer::getInstance()->addCommand(renderCommand);
} }

View File

@ -72,7 +72,11 @@ NewClippingNode::NewClippingNode()
currentStencilFail = GL_KEEP; currentStencilFail = GL_KEEP;
currentStencilPassDepthFail = GL_KEEP; currentStencilPassDepthFail = GL_KEEP;
currentStencilPassDepthPass = GL_KEEP; currentStencilPassDepthPass = GL_KEEP;
GLboolean currentDepthWriteMask = GL_TRUE; currentDepthWriteMask = GL_TRUE;
currentAlphaTestEnabled = GL_FALSE;
currentAlphaTestFunc = GL_ALWAYS;
currentAlphaTestRef = 1;
} }
void NewClippingNode::visit() void NewClippingNode::visit()
@ -104,11 +108,6 @@ void NewClippingNode::visit()
void NewClippingNode::beforeVisit() void NewClippingNode::beforeVisit()
{ {
// store the current stencil layer (position in the stencil buffer),
// this will allow nesting up to n ClippingNode,
// where n is the number of bits of the stencil buffer.
static GLint layer = -1;
/////////////////////////////////// ///////////////////////////////////
// INIT // INIT
@ -182,22 +181,60 @@ void NewClippingNode::beforeVisit()
glStencilFunc(GL_NEVER, mask_layer, mask_layer); glStencilFunc(GL_NEVER, mask_layer, mask_layer);
glStencilOp(!_inverted ? GL_REPLACE : GL_ZERO, GL_KEEP, GL_KEEP); glStencilOp(!_inverted ? GL_REPLACE : GL_ZERO, GL_KEEP, GL_KEEP);
// since glAlphaTest do not exists in OES, use a shader that writes // enable alpha test only if the alpha threshold < 1,
// pixel only if greater than an alpha threshold // indeed if alpha threshold == 1, every pixel will be drawn anyways
GLProgram *program = ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_ALPHA_TEST); #if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WINDOWS || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
GLint alphaValueLocation = glGetUniformLocation(program->getProgram(), GLProgram::UNIFORM_NAME_ALPHA_TEST_VALUE); // GLboolean currentAlphaTestEnabled = GL_FALSE;
// set our alphaThreshold // GLenum currentAlphaTestFunc = GL_ALWAYS;
program->use(); // GLclampf currentAlphaTestRef = 1;
program->setUniformLocationWith1f(alphaValueLocation, _alphaThreshold); #endif
// we need to recursively apply this shader to all the nodes in the stencil node if (_alphaThreshold < 1) {
// XXX: we should have a way to apply shader to all nodes without having to do this #if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WINDOWS || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
setProgram(_stencil, program); // manually save the alpha test state
currentAlphaTestEnabled = glIsEnabled(GL_ALPHA_TEST);
glGetIntegerv(GL_ALPHA_TEST_FUNC, (GLint *)&currentAlphaTestFunc);
glGetFloatv(GL_ALPHA_TEST_REF, &currentAlphaTestRef);
// enable alpha testing
glEnable(GL_ALPHA_TEST);
// check for OpenGL error while enabling alpha test
CHECK_GL_ERROR_DEBUG();
// pixel will be drawn only if greater than an alpha threshold
glAlphaFunc(GL_GREATER, _alphaThreshold);
#else
// since glAlphaTest do not exists in OES, use a shader that writes
// pixel only if greater than an alpha threshold
GLProgram *program = ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_ALPHA_TEST);
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
// XXX: we should have a way to apply shader to all nodes without having to do this
setProgram(_stencil, program);
#endif
}
//Draw _stencil //Draw _stencil
} }
void NewClippingNode::afterDrawStencil() void NewClippingNode::afterDrawStencil()
{ {
// restore alpha test state
if (_alphaThreshold < 1)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WINDOWS || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
// manually restore the alpha test state
glAlphaFunc(currentAlphaTestFunc, currentAlphaTestRef);
if (!currentAlphaTestEnabled)
{
glDisable(GL_ALPHA_TEST);
}
#else
// XXX: we need to find a way to restore the shaders of the stencil node and its childs
#endif
}
// restore the depth test state // restore the depth test state
glDepthMask(currentDepthWriteMask); glDepthMask(currentDepthWriteMask);
//if (currentDepthTestEnabled) { //if (currentDepthTestEnabled) {

View File

@ -21,7 +21,7 @@ public:
virtual ~NewClippingNode(); virtual ~NewClippingNode();
void visit(); virtual void visit() override;
protected: protected:
NewClippingNode(); NewClippingNode();
@ -41,6 +41,10 @@ protected:
GLenum currentStencilPassDepthPass; GLenum currentStencilPassDepthPass;
GLboolean currentDepthWriteMask; GLboolean currentDepthWriteMask;
GLboolean currentAlphaTestEnabled;
GLenum currentAlphaTestFunc;
GLclampf currentAlphaTestRef;
GLint mask_layer_le; GLint mask_layer_le;
}; };

View File

@ -171,7 +171,7 @@ void Renderer::render()
{ {
memcpy(_quads + _numQuads, cmd->getQuad(), sizeof(V3F_C4B_T2F_Quad) * cmd->getQuadCount()); memcpy(_quads + _numQuads, cmd->getQuad(), sizeof(V3F_C4B_T2F_Quad) * cmd->getQuadCount());
_numQuads += cmd->getQuadCount(); _numQuads += cmd->getQuadCount();
_renderStack.top().currentIndex = _lastCommand = i; _lastCommand = i;
} }
else else
{ {
@ -202,11 +202,15 @@ void Renderer::render()
{ {
flush(); flush();
} }
_renderStack.top().currentIndex = i;
} }
//Draw the batched quads //Draw the batched quads
drawBatchedQuads(); drawBatchedQuads();
currRenderQueue = _renderGroups[_renderStack.top().renderQueueID];
len = currRenderQueue.size();
//If pop the render stack if we already processed all the commands //If pop the render stack if we already processed all the commands
if(_renderStack.top().currentIndex + 1 >= len) if(_renderStack.top().currentIndex + 1 >= len)
{ {

View File

@ -271,20 +271,21 @@ NewClippingNodeTest::NewClippingNodeTest()
clipper->runAction(RepeatForever::create(RotateBy::create(1, 45))); clipper->runAction(RepeatForever::create(RotateBy::create(1, 45)));
this->addChild(clipper); this->addChild(clipper);
auto stencil = NewDrawNode::create(); // auto stencil = NewDrawNode::create();
Point rectangle[4]; // Point rectangle[4];
rectangle[0] = Point(0, 0); // rectangle[0] = Point(0, 0);
rectangle[1] = Point(clipper->getContentSize().width, 0); // rectangle[1] = Point(clipper->getContentSize().width, 0);
rectangle[2] = Point(clipper->getContentSize().width, clipper->getContentSize().height); // rectangle[2] = Point(clipper->getContentSize().width, clipper->getContentSize().height);
rectangle[3] = Point(0, clipper->getContentSize().height); // rectangle[3] = Point(0, clipper->getContentSize().height);
//
Color4F white(1, 1, 1, 1); // Color4F white(1, 1, 1, 1);
stencil->drawPolygon(rectangle, 4, white, 1, white); // stencil->drawPolygon(rectangle, 4, white, 1, white);
clipper->setStencil(stencil);
// auto stencil = NewSprite::create("Images/background2.png");
// clipper->setStencil(stencil); // clipper->setStencil(stencil);
auto stencil = NewSprite::create("Images/grossini.png");
stencil->setPosition(s.width/2, s.height/2);
clipper->setStencil(stencil);
auto content = NewSprite::create("Images/background2.png"); auto content = NewSprite::create("Images/background2.png");
content->setTag( kTagContentNode ); content->setTag( kTagContentNode );
content->setAnchorPoint( Point(0.5, 0.5) ); content->setAnchorPoint( Point(0.5, 0.5) );