issue #1506: RenderTextureTest

This commit is contained in:
minggo 2012-03-22 16:36:03 +08:00
parent 6b7716770e
commit 39ba6b4618
4 changed files with 83 additions and 195 deletions

View File

@ -34,10 +34,9 @@ NS_CC_BEGIN
typedef enum eImageFormat typedef enum eImageFormat
{ {
kCCImageFormatJPG = 0, kCCImageFormatJPEG = 0,
kCCImageFormatPNG = 1, kCCImageFormatPNG = 1,
kCCImageFormatRawData = 2 } tCCImageFormat;
} tImageFormat;
/** /**
@brief CCRenderTexture is a generic rendering target. To render things into it, @brief CCRenderTexture is a generic rendering target. To render things into it,
simply construct a render target, call begin on it, call visit on any cocos simply construct a render target, call begin on it, call visit on any cocos
@ -86,31 +85,20 @@ public:
/** clears the texture with a color */ /** clears the texture with a color */
void clear(float r, float g, float b, float a); void clear(float r, float g, float b, float a);
/** saves the texture into a file */ /* creates a new CCImage from with the texture's data.
// para szFilePath the absolute path to save Caller is responsible for releasing it by calling delete.
// para x,y the lower left corner coordinates of the buffer to save */
// pare nWidth,nHeight the size of the buffer to save CCImage* newCCImage();
// when nWidth = 0 and nHeight = 0, the image size to save equals to buffer texture size
bool saveBuffer(const char *szFilePath, int x = 0, int y = 0, int nWidth = 0, int nHeight = 0);
/** saves the texture into a file. put format at the first argument, or ti will be overloaded with /** saves the texture into a file using JPEG format. The file will be saved in the Documents folder.
* saveBuffer(const char *szFilePath, int x = 0, int y = 0, int nWidth = 0, int nHeight = 0) */ Returns YES if the operation is successful.
// para name the file name to save */
// para format the image format to save, here it supports kCCImageFormatPNG and kCCImageFormatJPG */ bool saveToFile(const char *szFilePath);
// para x,y the lower left corner coordinates of the buffer to save
// pare nWidth,nHeight the size of the buffer to save
// when nWidth = 0 and nHeight = 0, the image size to save equals to buffer texture size
bool saveBuffer(int format, const char *name, int x = 0, int y = 0, int nWidth = 0, int nHeight = 0);
/* get buffer as UIImage, can only save a render buffer which has a RGBA8888 pixel format */ /** saves the texture into a file. The format could be JPG or PNG. The file will be saved in the Documents folder.
CCData *getUIImageAsDataFromBuffer(int format); Returns YES if the operation is successful.
*/
/** save the buffer data to a CCImage */ bool saveToFile(const char *name, tCCImageFormat format);
// para pImage the CCImage to save
// para x,y the lower left corner coordinates of the buffer to save
// pare nWidth,nHeight the size of the buffer to save
// when nWidth = 0 and nHeight = 0, the image size to save equals to buffer texture size
bool getUIImageFromBuffer(CCImage *pImage, int x = 0, int y = 0, int nWidth = 0, int nHeight = 0);
protected: protected:
GLuint m_uFBO; GLuint m_uFBO;

View File

@ -103,6 +103,8 @@ bool CCRenderTexture::initWithWidthAndHeight(int w, int h, CCTexture2DPixelForma
return false; return false;
} }
CCAssert(m_ePixelFormat != kCCTexture2DPixelFormat_A8, "only RGB and RGBA formats are valid for a render texture");
bool bRet = false; bool bRet = false;
do do
{ {
@ -143,13 +145,7 @@ bool CCRenderTexture::initWithWidthAndHeight(int w, int h, CCTexture2DPixelForma
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_pTexture->getName(), 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_pTexture->getName(), 0);
// check if it worked (probably worth doing :) ) // check if it worked (probably worth doing :) )
GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER); CCAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Could not attach texture to framebuffer");
if (status != GL_FRAMEBUFFER_COMPLETE)
{
CCAssert(0, "Render Texture : Could not attach texture to framebuffer");
CC_SAFE_DELETE(m_pTexture);
break;
}
m_pTexture->setAliasTexParameters(); m_pTexture->setAliasTexParameters();
@ -183,11 +179,13 @@ void CCRenderTexture::begin()
float heightRatio = size.height / texSize.height; float heightRatio = size.height / texSize.height;
// Adjust the orthographic projection and viewport // Adjust the orthographic projection and viewport
glViewport(0, 0, texSize.width * CC_CONTENT_SCALE_FACTOR(), texSize.height * CC_CONTENT_SCALE_FACTOR() ); glViewport(0, 0, (GLsizei)(texSize.width * CC_CONTENT_SCALE_FACTOR()), (GLsizei)(texSize.height * CC_CONTENT_SCALE_FACTOR()));
// special viewport for 3d projection + retina display // special viewport for 3d projection + retina display
if ( director->getProjection() == kCCDirectorProjection3D && CC_CONTENT_SCALE_FACTOR() != 1 ) if ( director->getProjection() == kCCDirectorProjection3D && CC_CONTENT_SCALE_FACTOR() != 1 )
glViewport(-texSize.width/2, -texSize.height/2, texSize.width * CC_CONTENT_SCALE_FACTOR(), texSize.height * CC_CONTENT_SCALE_FACTOR() ); {
glViewport((GLsizei)(-texSize.width/2), (GLsizei)(-texSize.height/2), (GLsizei)(texSize.width * CC_CONTENT_SCALE_FACTOR()), (GLsizei)(texSize.height * CC_CONTENT_SCALE_FACTOR()));
}
kmMat4 orthoMatrix; kmMat4 orthoMatrix;
kmMat4OrthographicProjection(&orthoMatrix, (float)-1.0 / widthRatio, (float)1.0 / widthRatio, kmMat4OrthographicProjection(&orthoMatrix, (float)-1.0 / widthRatio, (float)1.0 / widthRatio,
@ -223,11 +221,13 @@ void CCRenderTexture::end(bool bIsTOCacheTexture)
CCSize size = director->getWinSizeInPixels(); CCSize size = director->getWinSizeInPixels();
// restore viewport // restore viewport
glViewport(0, 0, size.width * CC_CONTENT_SCALE_FACTOR(), size.height * CC_CONTENT_SCALE_FACTOR() ); glViewport(0, 0, GLsizei(size.width * CC_CONTENT_SCALE_FACTOR()), GLsizei(size.height * CC_CONTENT_SCALE_FACTOR()));
// special viewport for 3d projection + retina display // special viewport for 3d projection + retina display
if ( director->getProjection() == kCCDirectorProjection3D && CC_CONTENT_SCALE_FACTOR() != 1 ) if ( director->getProjection() == kCCDirectorProjection3D && CC_CONTENT_SCALE_FACTOR() != 1 )
glViewport(-size.width/2, -size.height/2, size.width * CC_CONTENT_SCALE_FACTOR(), size.height * CC_CONTENT_SCALE_FACTOR() ); {
glViewport((GLsizei)(-size.width/2), (GLsizei)(-size.height/2), (GLsizei)(size.width * CC_CONTENT_SCALE_FACTOR()), (GLsizei)(size.height * CC_CONTENT_SCALE_FACTOR()));
}
//TODO: Does this line take effect? director->setProjection(director->getProjection()); //TODO: Does this line take effect? director->setProjection(director->getProjection());
@ -241,7 +241,7 @@ void CCRenderTexture::end(bool bIsTOCacheTexture)
int tx = (int)s.width; int tx = (int)s.width;
int ty = (int)s.height; int ty = (int)s.height;
m_pUITextureImage = new CCImage; m_pUITextureImage = new CCImage;
if (true == getUIImageFromBuffer(m_pUITextureImage, 0, 0, tx, ty)) if (m_pUITextureImage == newCCImage())
{ {
VolatileTexture::addDataTexture(m_pTexture, m_pUITextureImage->getData(), kTexture2DPixelFormat_RGBA8888, s); VolatileTexture::addDataTexture(m_pTexture, m_pUITextureImage->getData(), kTexture2DPixelFormat_RGBA8888, s);
} }
@ -259,31 +259,31 @@ void CCRenderTexture::clear(float r, float g, float b, float a)
this->end(); this->end();
} }
bool CCRenderTexture::saveBuffer(const char *szFilePath, int x, int y, int nWidth, int nHeight) bool CCRenderTexture::saveToFile(const char *szFilePath)
{ {
bool bRet = false; bool bRet = false;
CCImage *pImage = new CCImage(); CCImage *pImage = newCCImage();
if (pImage != NULL && getUIImageFromBuffer(pImage, x, y, nWidth, nHeight)) if (pImage)
{ {
bRet = pImage->saveToFile(szFilePath); bRet = pImage->saveToFile(szFilePath, kCCImageFormatJPEG);
} }
CC_SAFE_DELETE(pImage); CC_SAFE_DELETE(pImage);
return bRet; return bRet;
} }
bool CCRenderTexture::saveBuffer(int format, const char *fileName, int x, int y, int nWidth, int nHeight) bool CCRenderTexture::saveToFile(const char *fileName, tCCImageFormat format)
{ {
bool bRet = false; bool bRet = false;
CCAssert(format == kCCImageFormatJPG || format == kCCImageFormatPNG, CCAssert(format == kCCImageFormatJPEG || format == kCCImageFormatPNG,
"the image can only be saved as JPG or PNG format"); "the image can only be saved as JPG or PNG format");
CCImage *pImage = new CCImage(); CCImage *pImage = newCCImage();
if (pImage != NULL && getUIImageFromBuffer(pImage, x, y, nWidth, nHeight)) if (pImage)
{ {
std::string fullpath = CCFileUtils::getWriteablePath() + fileName; std::string fullpath = CCFileUtils::getWriteablePath() + fileName;
bRet = pImage->saveToFile(fullpath.c_str()); bRet = pImage->saveToFile(fullpath.c_str(), true);
} }
CC_SAFE_DELETE(pImage); CC_SAFE_DELETE(pImage);
@ -291,75 +291,43 @@ bool CCRenderTexture::saveBuffer(int format, const char *fileName, int x, int y,
return bRet; return bRet;
} }
/* get buffer as UIImage */ /* get buffer as CCImage */
bool CCRenderTexture::getUIImageFromBuffer(CCImage *pImage, int x, int y, int nWidth, int nHeight) CCImage* CCRenderTexture::newCCImage()
{ {
if (NULL == pImage || NULL == m_pTexture) CCAssert(m_ePixelFormat == kCCTexture2DPixelFormat_RGBA8888, "only RGBA8888 can be saved as image");
if (NULL == m_pTexture)
{ {
return false; return NULL;
} }
const CCSize& s = m_pTexture->getContentSizeInPixels(); const CCSize& s = m_pTexture->getContentSizeInPixels();
int tx = (int)s.width;
int ty = (int)s.height;
if (x < 0 || x >= tx || y < 0 || y >= ty)
{
return false;
}
if (nWidth < 0
|| nHeight < 0
|| (0 == nWidth && 0 != nHeight)
|| (0 == nHeight && 0 != nWidth))
{
return false;
}
// to get the image size to save // to get the image size to save
// if the saving image domain exeeds the buffer texture domain, // if the saving image domain exeeds the buffer texture domain,
// it should be cut // it should be cut
int nSavedBufferWidth = nWidth; int nSavedBufferWidth = (int)s.width;
int nSavedBufferHeight = nHeight; int nSavedBufferHeight = (int)s.height;
if (0 == nWidth)
{
nSavedBufferWidth = tx;
}
if (0 == nHeight)
{
nSavedBufferHeight = ty;
}
nSavedBufferWidth = x + nSavedBufferWidth > tx ? (tx - x): nSavedBufferWidth;
nSavedBufferHeight = y + nSavedBufferHeight > ty ? (ty - y): nSavedBufferHeight;
GLubyte *pBuffer = NULL; GLubyte *pBuffer = NULL;
GLubyte *pTempData = NULL; GLubyte *pTempData = NULL;
bool bRet = false; CCImage *pImage = new CCImage();
do do
{ {
CCAssert(m_ePixelFormat == kCCTexture2DPixelFormat_RGBA8888, "only RGBA8888 can be saved as image");
CC_BREAK_IF(! (pBuffer = new GLubyte[nSavedBufferWidth * nSavedBufferHeight * 4])); CC_BREAK_IF(! (pBuffer = new GLubyte[nSavedBufferWidth * nSavedBufferHeight * 4]));
// On some machines, like Samsung i9000, Motorola Defy,
// the dimension need to be a power of 2
int nReadBufferWidth = 0;
int nReadBufferHeight = 0;
int nMaxTextureSize = 0;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &nMaxTextureSize);
nReadBufferWidth = ccNextPOT(tx); if(! (pTempData = new GLubyte[nSavedBufferWidth * nSavedBufferHeight * 4]))
nReadBufferHeight = ccNextPOT(ty); {
delete[] pBuffer;
CC_BREAK_IF(0 == nReadBufferWidth || 0 == nReadBufferHeight); pBuffer = NULL;
CC_BREAK_IF(nReadBufferWidth > nMaxTextureSize || nReadBufferHeight > nMaxTextureSize); break;
}
CC_BREAK_IF(! (pTempData = new GLubyte[nReadBufferWidth * nReadBufferHeight * 4]));
this->begin(); this->begin();
glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0,0,nReadBufferWidth,nReadBufferHeight,GL_RGBA,GL_UNSIGNED_BYTE, pTempData); glReadPixels(0,0,nSavedBufferWidth, nSavedBufferHeight,GL_RGBA,GL_UNSIGNED_BYTE, pTempData);
this->end(false); this->end(false);
// to get the actual texture data // to get the actual texture data
@ -367,105 +335,17 @@ bool CCRenderTexture::getUIImageFromBuffer(CCImage *pImage, int x, int y, int nW
for (int i = 0; i < nSavedBufferHeight; ++i) for (int i = 0; i < nSavedBufferHeight; ++i)
{ {
memcpy(&pBuffer[i * nSavedBufferWidth * 4], memcpy(&pBuffer[i * nSavedBufferWidth * 4],
&pTempData[(y + nSavedBufferHeight - i - 1) * nReadBufferWidth * 4 + x * 4], &pTempData[(nSavedBufferHeight - i - 1) * nSavedBufferWidth * 4],
nSavedBufferWidth * 4); nSavedBufferWidth * 4);
} }
bRet = pImage->initWithImageData(pBuffer, nSavedBufferWidth * nSavedBufferHeight * 4, CCImage::kFmtRawData, nSavedBufferWidth, nSavedBufferHeight, 8); pImage->initWithImageData(pBuffer, nSavedBufferWidth * nSavedBufferHeight * 4, CCImage::kFmtRawData, nSavedBufferWidth, nSavedBufferHeight, 8);
} while (0); } while (0);
CC_SAFE_DELETE_ARRAY(pBuffer); CC_SAFE_DELETE_ARRAY(pBuffer);
CC_SAFE_DELETE_ARRAY(pTempData); CC_SAFE_DELETE_ARRAY(pTempData);
return bRet; return pImage;
}
CCData * CCRenderTexture::getUIImageAsDataFromBuffer(int format)
{
CC_UNUSED_PARAM(format);
CCData * pData = NULL;
//@ todo CCRenderTexture::getUIImageAsDataFromBuffer
// #include "Availability.h"
// #include "UIKit.h"
// GLubyte * pBuffer = NULL;
// GLubyte * pPixels = NULL;
// do
// {
// CC_BREAK_IF(! m_pTexture);
//
// CCAssert(m_ePixelFormat == kCCTexture2DPixelFormat_RGBA8888, "only RGBA8888 can be saved as image");
//
// const CCSize& s = m_pTexture->getContentSizeInPixels();
// int tx = s.width;
// int ty = s.height;
//
// int bitsPerComponent = 8;
// int bitsPerPixel = 32;
//
// int bytesPerRow = (bitsPerPixel / 8) * tx;
// int myDataLength = bytesPerRow * ty;
//
// CC_BREAK_IF(! (pBuffer = new GLubyte[tx * ty * 4]));
// CC_BREAK_IF(! (pPixels = new GLubyte[tx * ty * 4]));
//
// this->begin();
// glReadPixels(0,0,tx,ty,GL_RGBA,GL_UNSIGNED_BYTE, pBuffer);
// this->end();
//
// int x,y;
//
// for(y = 0; y <ty; y++) {
// for(x = 0; x <tx * 4; x++) {
// pPixels[((ty - 1 - y) * tx * 4 + x)] = pBuffer[(y * 4 * tx + x)];
// }
// }
//
// if (format == kCCImageFormatRawData)
// {
// pData = CCData::dataWithBytesNoCopy(pPixels, myDataLength);
// break;
// }
//@ todo impliment save to jpg or png
/*
CGImageCreate(size_t width, size_t height,
size_t bitsPerComponent, size_t bitsPerPixel, size_t bytesPerRow,
CGColorSpaceRef space, CGBitmapInfo bitmapInfo, CGDataProviderRef provider,
const CGFloat decode[], bool shouldInterpolate,
CGColorRenderingIntent intent)
*/
// make data provider with data.
// CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault;
// CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, myDataLength, NULL);
// CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
// CGImageRef iref = CGImageCreate(tx, ty,
// bitsPerComponent, bitsPerPixel, bytesPerRow,
// colorSpaceRef, bitmapInfo, provider,
// NULL, false,
// kCGRenderingIntentDefault);
//
// UIImage* image = [[UIImage alloc] initWithCGImage:iref];
//
// CGImageRelease(iref);
// CGColorSpaceRelease(colorSpaceRef);
// CGDataProviderRelease(provider);
//
//
//
// if (format == kCCImageFormatPNG)
// data = UIImagePNGRepresentation(image);
// else
// data = UIImageJPEGRepresentation(image, 1.0f);
//
// [image release];
// } while (0);
//
// CC_SAFE_DELETE_ARRAY(pBuffer);
// CC_SAFE_DELETE_ARRAY(pPixels);
return pData;
} }
NS_CC_END NS_CC_END

View File

@ -22,8 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
****************************************************************************/ ****************************************************************************/
#ifndef __CC_IMAGE_H_YANGWS_20110115__ #ifndef __CC_IMAGE_H__
#define __CC_IMAGE_H_YANGWS_20110115__ #define __CC_IMAGE__
#include "CCCommon.h" #include "CCCommon.h"
@ -147,4 +147,4 @@ private:
NS_CC_END; NS_CC_END;
#endif // __CC_IMAGE_H_YANGWS_20110115__ #endif // __CC_IMAGE_H__

View File

@ -235,7 +235,7 @@ RenderTextureSave::RenderTextureSave()
CCSize s = CCDirector::sharedDirector()->getWinSize(); CCSize s = CCDirector::sharedDirector()->getWinSize();
// create a render texture, this is what we are going to draw into // create a render texture, this is what we are going to draw into
m_pTarget = CCRenderTexture::renderTextureWithWidthAndHeight(s.width, s.height); m_pTarget = CCRenderTexture::renderTextureWithWidthAndHeight(s.width, s.height, kCCTexture2DPixelFormat_RGBA8888);
m_pTarget->retain(); m_pTarget->retain();
m_pTarget->setPosition(ccp(s.width / 2, s.height / 2)); m_pTarget->setPosition(ccp(s.width / 2, s.height / 2));
@ -246,6 +246,7 @@ RenderTextureSave::RenderTextureSave()
// create a brush image to draw into the texture with // create a brush image to draw into the texture with
m_pBrush = CCSprite::spriteWithFile("Images/fire.png"); m_pBrush = CCSprite::spriteWithFile("Images/fire.png");
m_pBrush->retain(); m_pBrush->retain();
m_pBrush->setColor(ccRED);
m_pBrush->setOpacity(20); m_pBrush->setOpacity(20);
this->setIsTouchEnabled(true); this->setIsTouchEnabled(true);
@ -278,10 +279,29 @@ void RenderTextureSave::saveImage(cocos2d::CCObject *pSender)
{ {
static int counter = 0; static int counter = 0;
char str[20]; char png[20];
sprintf(str, "image-%d.png", counter); sprintf(png, "image-%d.png", counter);
m_pTarget->saveBuffer(kCCImageFormatPNG, str); char jpg[20];
CCLOG("Image saved %s", str); 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::spriteWithTexture(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++; counter++;
} }
@ -359,7 +379,7 @@ RenderTextureIssue937::RenderTextureIssue937()
/* A2 & B2 setup */ /* A2 & B2 setup */
CCRenderTexture *rend = CCRenderTexture::renderTextureWithWidthAndHeight(32, 64); CCRenderTexture *rend = CCRenderTexture::renderTextureWithWidthAndHeight(32, 64, kCCTexture2DPixelFormat_RGBA4444);
if (NULL == rend) if (NULL == rend)
{ {