#include "CCConfiguration.h" #include "RenderTextureTest.h" // Test #1 by Jason Booth (slipster216) // Test #3 by David Deaco (ddeaco) static int sceneIdx = -1; #define MAX_LAYER 4 CCLayer* createTestCase(int nIndex) { switch(nIndex) { case 0: return new RenderTextureSave(); case 1: return new RenderTextureIssue937(); case 2: return new RenderTextureZbuffer(); case 3: return new RenderTextureTestDepthStencil(); } return NULL; } CCLayer* nextTestCase() { sceneIdx++; sceneIdx = sceneIdx % MAX_LAYER; CCLayer* pLayer = createTestCase(sceneIdx); pLayer->autorelease(); return pLayer; } CCLayer* backTestCase() { sceneIdx--; int total = MAX_LAYER; if( sceneIdx < 0 ) sceneIdx += total; CCLayer* pLayer = createTestCase(sceneIdx); pLayer->autorelease(); return pLayer; } CCLayer* restartTestCase() { CCLayer* pLayer = createTestCase(sceneIdx); pLayer->autorelease(); return pLayer; } void RenderTextureTest::onEnter() { CCLayer::onEnter(); CCSize s = CCDirector::sharedDirector()->getWinSize(); CCLabelTTF* label = CCLabelTTF::create(title().c_str(), "Arial", 26); addChild(label, 1); label->setPosition( ccp(s.width/2, s.height-50) ); std::string strSubtitle = subtitle(); if( ! strSubtitle.empty() ) { CCLabelTTF* l = CCLabelTTF::create(strSubtitle.c_str(), "Thonburi", 16); addChild(l, 1); l->setPosition( ccp(s.width/2, s.height-80) ); } CCMenuItemImage *item1 = CCMenuItemImage::create("Images/b1.png", "Images/b2.png", this, menu_selector(RenderTextureTest::backCallback) ); CCMenuItemImage *item2 = CCMenuItemImage::create("Images/r1.png","Images/r2.png", this, menu_selector(RenderTextureTest::restartCallback) ); CCMenuItemImage *item3 = CCMenuItemImage::create("Images/f1.png", "Images/f2.png", this, menu_selector(RenderTextureTest::nextCallback) ); CCMenu *menu = CCMenu::create(item1, item2, item3, NULL); menu->setPosition( CCPointZero ); item1->setPosition( ccp( s.width/2 - item2->getContentSize().width*2, item2->getContentSize().height/2) ); item2->setPosition( ccp( s.width/2, item2->getContentSize().height/2) ); item3->setPosition( ccp( s.width/2 + item2->getContentSize().width*2, item2->getContentSize().height/2) ); addChild(menu, 1); } void RenderTextureTest::restartCallback(CCObject* pSender) { CCScene* s = new RenderTextureScene(); s->addChild(restartTestCase()); CCDirector::sharedDirector()->replaceScene(s); s->release(); } void RenderTextureTest::nextCallback(CCObject* pSender) { CCScene* s = new RenderTextureScene(); s->addChild( nextTestCase() ); CCDirector::sharedDirector()->replaceScene(s); s->release(); } void RenderTextureTest::backCallback(CCObject* pSender) { CCScene* s = new RenderTextureScene(); s->addChild( backTestCase() ); CCDirector::sharedDirector()->replaceScene(s); s->release(); } std::string RenderTextureTest::title() { return "No title"; } std::string RenderTextureTest::subtitle() { return ""; } /** * Impelmentation of RenderTextureSave */ RenderTextureSave::RenderTextureSave() { CCSize s = CCDirector::sharedDirector()->getWinSize(); // create a render texture, this is what we are going to draw into m_pTarget = CCRenderTexture::create(s.width, s.height, kCCTexture2DPixelFormat_RGBA8888); m_pTarget->retain(); m_pTarget->setPosition(ccp(s.width / 2, s.height / 2)); // note that the render texture is a CCNode, and contains a sprite of its texture for convience, // so we can just parent it to the scene like any other CCNode this->addChild(m_pTarget, -1); // create a brush image to draw into the texture with m_pBrush = CCSprite::create("Images/fire.png"); m_pBrush->retain(); m_pBrush->setColor(ccRED); m_pBrush->setOpacity(20); this->setTouchEnabled(true); // Save Image menu CCMenuItemFont::setFontSize(16); CCMenuItem *item1 = CCMenuItemFont::create("Save Image", this, menu_selector(RenderTextureSave::saveImage)); CCMenuItem *item2 = CCMenuItemFont::create("Clear", this, menu_selector(RenderTextureSave::clearImage)); CCMenu *menu = CCMenu::create(item1, item2, NULL); this->addChild(menu); menu->alignItemsVertically(); menu->setPosition(ccp(s.width - 80, s.height - 30)); } string RenderTextureSave::title() { return "Touch the screen"; } string RenderTextureSave::subtitle() { return "Press 'Save Image' to create an snapshot of the render texture"; } void RenderTextureSave::clearImage(cocos2d::CCObject *pSender) { m_pTarget->clear(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1()); } void RenderTextureSave::saveImage(cocos2d::CCObject *pSender) { static int counter = 0; char png[20]; sprintf(png, "image-%d.png", counter); char jpg[20]; sprintf(jpg, "image-%d.jpg", counter); m_pTarget->saveToFile(png, kCCImageFormatPNG); m_pTarget->saveToFile(jpg, kCCImageFormatJPEG); CCImage *pImage = m_pTarget->newCCImage(); CCTexture2D *tex = CCTextureCache::sharedTextureCache()->addUIImage(pImage, png); CC_SAFE_DELETE(pImage); CCSprite *sprite = CCSprite::createWithTexture(tex); sprite->setScale(0.3f); addChild(sprite); sprite->setPosition(ccp(40, 40)); sprite->setRotation(counter * 3); CCLOG("Image saved %s and %s", png, jpg); counter++; } RenderTextureSave::~RenderTextureSave() { m_pBrush->release(); m_pTarget->release(); CCTextureCache::sharedTextureCache()->removeUnusedTextures(); } void RenderTextureSave::ccTouchesMoved(CCSet* touches, CCEvent* event) { CCTouch *touch = (CCTouch *)touches->anyObject(); CCPoint start = touch->getLocation(); CCPoint end = touch->getPreviousLocation(); // begin drawing to the render texture m_pTarget->begin(); // for extra points, we'll draw this smoothly from the last position and vary the sprite's // scale/rotation/offset float distance = ccpDistance(start, end); if (distance > 1) { int d = (int)distance; for (int i = 0; i < d; i++) { float difx = end.x - start.x; float dify = end.y - start.y; float delta = (float)i / distance; m_pBrush->setPosition(ccp(start.x + (difx * delta), start.y + (dify * delta))); m_pBrush->setRotation(rand() % 360); float r = (float)(rand() % 50 / 50.f) + 0.25f; m_pBrush->setScale(r); /*m_pBrush->setColor(ccc3(CCRANDOM_0_1() * 127 + 128, 255, 255));*/ // Use CCRANDOM_0_1() will cause error when loading libtests.so on android, I don't know why. m_pBrush->setColor(ccc3(rand() % 127 + 128, 255, 255)); // Call visit to draw the brush, don't call draw.. m_pBrush->visit(); } } // finish drawing and return context back to the screen m_pTarget->end(); } /** * Impelmentation of RenderTextureIssue937 */ RenderTextureIssue937::RenderTextureIssue937() { /* * 1 2 * A: A1 A2 * * B: B1 B2 * * A1: premulti sprite * A2: premulti render * * B1: non-premulti sprite * B2: non-premulti render */ CCLayerColor *background = CCLayerColor::create(ccc4(200,200,200,255)); addChild(background); CCSprite *spr_premulti = CCSprite::create("Images/fire.png"); spr_premulti->setPosition(ccp(16,48)); CCSprite *spr_nonpremulti = CCSprite::create("Images/fire.png"); spr_nonpremulti->setPosition(ccp(16,16)); /* A2 & B2 setup */ CCRenderTexture *rend = CCRenderTexture::create(32, 64, kCCTexture2DPixelFormat_RGBA8888); if (NULL == rend) { return; } // It's possible to modify the RenderTexture blending function by // [[rend sprite] setBlendFunc:(ccBlendFunc) {GL_ONE, GL_ONE_MINUS_SRC_ALPHA}]; rend->begin(); spr_premulti->visit(); spr_nonpremulti->visit(); rend->end(); CCSize s = CCDirector::sharedDirector()->getWinSize(); /* A1: setup */ spr_premulti->setPosition(ccp(s.width/2-16, s.height/2+16)); /* B1: setup */ spr_nonpremulti->setPosition(ccp(s.width/2-16, s.height/2-16)); rend->setPosition(ccp(s.width/2+16, s.height/2)); addChild(spr_nonpremulti); addChild(spr_premulti); addChild(rend); } std::string RenderTextureIssue937::title() { return "Testing issue #937"; } std::string RenderTextureIssue937::subtitle() { return "All images should be equal..."; } void RenderTextureScene::runThisTest() { CCLayer* pLayer = nextTestCase(); addChild(pLayer); CCDirector::sharedDirector()->replaceScene(this); } /** * Impelmentation of RenderTextureZbuffer */ RenderTextureZbuffer::RenderTextureZbuffer() { this->setTouchEnabled(true); CCSize size = CCDirector::sharedDirector()->getWinSize(); CCLabelTTF *label = CCLabelTTF::create("vertexZ = 50", "Marker Felt", 64); label->setPosition(ccp(size.width / 2, size.height * 0.25f)); this->addChild(label); CCLabelTTF *label2 = CCLabelTTF::create("vertexZ = 0", "Marker Felt", 64); label2->setPosition(ccp(size.width / 2, size.height * 0.5f)); this->addChild(label2); CCLabelTTF *label3 = CCLabelTTF::create("vertexZ = -50", "Marker Felt", 64); label3->setPosition(ccp(size.width / 2, size.height * 0.75f)); this->addChild(label3); label->setVertexZ(50); label2->setVertexZ(0); label3->setVertexZ(-50); CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("Images/bugs/circle.plist"); mgr = CCSpriteBatchNode::create("Images/bugs/circle.png", 9); this->addChild(mgr); sp1 = CCSprite::createWithSpriteFrameName("circle.png"); sp2 = CCSprite::createWithSpriteFrameName("circle.png"); sp3 = CCSprite::createWithSpriteFrameName("circle.png"); sp4 = CCSprite::createWithSpriteFrameName("circle.png"); sp5 = CCSprite::createWithSpriteFrameName("circle.png"); sp6 = CCSprite::createWithSpriteFrameName("circle.png"); sp7 = CCSprite::createWithSpriteFrameName("circle.png"); sp8 = CCSprite::createWithSpriteFrameName("circle.png"); sp9 = CCSprite::createWithSpriteFrameName("circle.png"); mgr->addChild(sp1, 9); mgr->addChild(sp2, 8); mgr->addChild(sp3, 7); mgr->addChild(sp4, 6); mgr->addChild(sp5, 5); mgr->addChild(sp6, 4); mgr->addChild(sp7, 3); mgr->addChild(sp8, 2); mgr->addChild(sp9, 1); sp1->setVertexZ(400); sp2->setVertexZ(300); sp3->setVertexZ(200); sp4->setVertexZ(100); sp5->setVertexZ(0); sp6->setVertexZ(-100); sp7->setVertexZ(-200); sp8->setVertexZ(-300); sp9->setVertexZ(-400); sp9->setScale(2); sp9->setColor(ccYELLOW); } string RenderTextureZbuffer::title() { return "Testing Z Buffer in Render Texture"; } string RenderTextureZbuffer::subtitle() { return "Touch screen. It should be green"; } void RenderTextureZbuffer::ccTouchesBegan(cocos2d::CCSet *touches, cocos2d::CCEvent *event) { CCSetIterator iter; CCTouch *touch; for (iter = touches->begin(); iter != touches->end(); ++iter) { touch = (CCTouch *)(*iter); CCPoint location = touch->getLocation(); sp1->setPosition(location); sp2->setPosition(location); sp3->setPosition(location); sp4->setPosition(location); sp5->setPosition(location); sp6->setPosition(location); sp7->setPosition(location); sp8->setPosition(location); sp9->setPosition(location); } } void RenderTextureZbuffer::ccTouchesMoved(CCSet* touches, CCEvent* event) { CCSetIterator iter; CCTouch *touch; for (iter = touches->begin(); iter != touches->end(); ++iter) { touch = (CCTouch *)(*iter); CCPoint location = touch->getLocation(); sp1->setPosition(location); sp2->setPosition(location); sp3->setPosition(location); sp4->setPosition(location); sp5->setPosition(location); sp6->setPosition(location); sp7->setPosition(location); sp8->setPosition(location); sp9->setPosition(location); } } void RenderTextureZbuffer::ccTouchesEnded(CCSet* touches, CCEvent* event) { this->renderScreenShot(); } void RenderTextureZbuffer::renderScreenShot() { CCRenderTexture *texture = CCRenderTexture::create(512, 512); if (NULL == texture) { return; } texture->setAnchorPoint(ccp(0, 0)); texture->begin(); this->visit(); texture->end(); CCSprite *sprite = CCSprite::createWithTexture(texture->getSprite()->getTexture()); sprite->setPosition(ccp(256, 256)); sprite->setOpacity(182); sprite->setFlipY(1); this->addChild(sprite, 999999); sprite->setColor(ccGREEN); sprite->runAction(CCSequence::create(CCFadeTo::create(2, 0), CCHide::create(), NULL)); } // RenderTextureTestDepthStencil RenderTextureTestDepthStencil::RenderTextureTestDepthStencil() { CCSize s = CCDirector::sharedDirector()->getWinSize(); CCSprite *sprite = CCSprite::create("Images/fire.png"); sprite->setPosition(ccp(s.width * 0.25f, 0)); sprite->setScale(10); CCRenderTexture *rend = CCRenderTexture::create(s.width, s.height, kCCTexture2DPixelFormat_RGBA4444, CC_GL_DEPTH24_STENCIL8); glStencilMask(0xFF); rend->beginWithClear(0, 0, 0, 0, 0, 0); //! mark sprite quad into stencil buffer glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glColorMask(0, 0, 0, 1); sprite->visit(); //! move sprite half width and height, and draw only where not marked sprite->setPosition(ccpAdd(sprite->getPosition(), ccpMult(ccp(sprite->getContentSize().width * sprite->getScale(), sprite->getContentSize().height * sprite->getScale()), 0.5))); glStencilFunc(GL_NOTEQUAL, 1, 0xFF); glColorMask(1, 1, 1, 1); sprite->visit(); rend->end(); glDisable(GL_STENCIL_TEST); rend->setPosition(ccp(s.width * 0.5f, s.height * 0.5f)); this->addChild(rend); } std::string RenderTextureTestDepthStencil::title() { return "Testing depthStencil attachment"; } std::string RenderTextureTestDepthStencil::subtitle() { return "Circle should be missing 1/4 of its region"; }