mirror of https://github.com/axmolengine/axmol.git
Fix for CCRenderTexture on Android sleep/resume
When an android app goes into the background, all gl context is lost, including any frame buffer objects that are required for rendering to a texture. When the android app returns to focus, a new FBO is generated for each render texture allowing rendering to the texture to continue.
This commit is contained in:
parent
c53cfe88a7
commit
132a76d801
|
@ -59,12 +59,19 @@ CCRenderTexture::CCRenderTexture()
|
||||||
, m_nClearStencil(0)
|
, m_nClearStencil(0)
|
||||||
, m_bAutoDraw(false)
|
, m_bAutoDraw(false)
|
||||||
{
|
{
|
||||||
|
#if CC_ENABLE_CACHE_TEXTURE_DATA
|
||||||
// Listen this event to save render texture before come to background.
|
// Listen this event to save render texture before come to background.
|
||||||
// Then it can be restored after coming to foreground on Android.
|
// Then it can be restored after coming to foreground on Android.
|
||||||
CCNotificationCenter::sharedNotificationCenter()->addObserver(this,
|
CCNotificationCenter::sharedNotificationCenter()->addObserver(this,
|
||||||
callfuncO_selector(CCRenderTexture::listenToBackground),
|
callfuncO_selector(CCRenderTexture::listenToBackground),
|
||||||
EVENT_COME_TO_BACKGROUND,
|
EVENT_COME_TO_BACKGROUND,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
CCNotificationCenter::sharedNotificationCenter()->addObserver(this,
|
||||||
|
callfuncO_selector(CCRenderTexture::listenToForeground),
|
||||||
|
EVNET_COME_TO_FOREGROUND, // this is misspelt
|
||||||
|
NULL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CCRenderTexture::~CCRenderTexture()
|
CCRenderTexture::~CCRenderTexture()
|
||||||
|
@ -78,29 +85,59 @@ CCRenderTexture::~CCRenderTexture()
|
||||||
glDeleteRenderbuffers(1, &m_uDepthRenderBufffer);
|
glDeleteRenderbuffers(1, &m_uDepthRenderBufffer);
|
||||||
}
|
}
|
||||||
CC_SAFE_DELETE(m_pUITextureImage);
|
CC_SAFE_DELETE(m_pUITextureImage);
|
||||||
|
|
||||||
|
#if CC_ENABLE_CACHE_TEXTURE_DATA
|
||||||
CCNotificationCenter::sharedNotificationCenter()->removeObserver(this, EVENT_COME_TO_BACKGROUND);
|
CCNotificationCenter::sharedNotificationCenter()->removeObserver(this, EVENT_COME_TO_BACKGROUND);
|
||||||
|
CCNotificationCenter::sharedNotificationCenter()->removeObserver(this, EVNET_COME_TO_FOREGROUND);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCRenderTexture::listenToBackground(cocos2d::CCObject *obj)
|
void CCRenderTexture::listenToBackground(cocos2d::CCObject *obj)
|
||||||
{
|
{
|
||||||
#if CC_ENABLE_CACHE_TEXTURE_DATA
|
#if CC_ENABLE_CACHE_TEXTURE_DATA
|
||||||
|
|
||||||
CC_SAFE_DELETE(m_pUITextureImage);
|
CC_SAFE_DELETE(m_pUITextureImage);
|
||||||
|
|
||||||
// to get the rendered texture data
|
// to get the rendered texture data
|
||||||
m_pUITextureImage = newCCImage();
|
m_pUITextureImage = newCCImage(false);
|
||||||
|
|
||||||
|
|
||||||
if (m_pUITextureImage)
|
if (m_pUITextureImage)
|
||||||
{
|
{
|
||||||
const CCSize& s = m_pTexture->getContentSizeInPixels();
|
const CCSize& s = m_pTexture->getContentSizeInPixels();
|
||||||
VolatileTexture::addDataTexture(m_pTexture, m_pUITextureImage->getData(), kTexture2DPixelFormat_RGBA8888, s);
|
VolatileTexture::addDataTexture(m_pTexture, m_pUITextureImage->getData(), kTexture2DPixelFormat_RGBA8888, s);
|
||||||
}
|
|
||||||
|
if ( m_pTextureCopy )
|
||||||
|
{
|
||||||
|
VolatileTexture::addDataTexture(m_pTextureCopy, m_pUITextureImage->getData(), kTexture2DPixelFormat_RGBA8888, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CCLOG("Cache rendertexture failed!");
|
CCLOG("Cache rendertexture failed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glDeleteFramebuffers(1, &m_uFBO);
|
||||||
|
m_uFBO = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCRenderTexture::listenToForeground(cocos2d::CCObject *obj)
|
||||||
|
{
|
||||||
|
#if CC_ENABLE_CACHE_TEXTURE_DATA
|
||||||
|
// -- regenerate frame buffer object and attach the texture
|
||||||
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_nOldFBO);
|
||||||
|
|
||||||
|
glGenFramebuffers(1, &m_uFBO);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, m_uFBO);
|
||||||
|
|
||||||
|
m_pTexture->setAliasTexParameters();
|
||||||
|
|
||||||
|
if ( m_pTextureCopy )
|
||||||
|
{
|
||||||
|
m_pTextureCopy->setAliasTexParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_pTexture->getName(), 0);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, m_nOldFBO);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,7 +627,7 @@ bool CCRenderTexture::saveToFile(const char *szFilePath)
|
||||||
{
|
{
|
||||||
bool bRet = false;
|
bool bRet = false;
|
||||||
|
|
||||||
CCImage *pImage = newCCImage();
|
CCImage *pImage = newCCImage(true);
|
||||||
if (pImage)
|
if (pImage)
|
||||||
{
|
{
|
||||||
bRet = pImage->saveToFile(szFilePath, kCCImageFormatJPEG);
|
bRet = pImage->saveToFile(szFilePath, kCCImageFormatJPEG);
|
||||||
|
@ -605,7 +642,7 @@ bool CCRenderTexture::saveToFile(const char *fileName, tCCImageFormat format)
|
||||||
CCAssert(format == kCCImageFormatJPEG || 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 = newCCImage();
|
CCImage *pImage = newCCImage(true);
|
||||||
if (pImage)
|
if (pImage)
|
||||||
{
|
{
|
||||||
std::string fullpath = CCFileUtils::sharedFileUtils()->getWriteablePath() + fileName;
|
std::string fullpath = CCFileUtils::sharedFileUtils()->getWriteablePath() + fileName;
|
||||||
|
@ -619,7 +656,7 @@ bool CCRenderTexture::saveToFile(const char *fileName, tCCImageFormat format)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get buffer as CCImage */
|
/* get buffer as CCImage */
|
||||||
CCImage* CCRenderTexture::newCCImage()
|
CCImage* CCRenderTexture::newCCImage(bool flipImage)
|
||||||
{
|
{
|
||||||
CCAssert(m_ePixelFormat == kCCTexture2DPixelFormat_RGBA8888, "only RGBA8888 can be saved as image");
|
CCAssert(m_ePixelFormat == kCCTexture2DPixelFormat_RGBA8888, "only RGBA8888 can be saved as image");
|
||||||
|
|
||||||
|
@ -656,16 +693,24 @@ CCImage* CCRenderTexture::newCCImage()
|
||||||
glReadPixels(0,0,nSavedBufferWidth, nSavedBufferHeight,GL_RGBA,GL_UNSIGNED_BYTE, pTempData);
|
glReadPixels(0,0,nSavedBufferWidth, nSavedBufferHeight,GL_RGBA,GL_UNSIGNED_BYTE, pTempData);
|
||||||
this->end();
|
this->end();
|
||||||
|
|
||||||
// to get the actual texture data
|
if ( flipImage ) // -- flip is only required when saving image to file
|
||||||
// #640 the image read from rendertexture is dirty
|
|
||||||
for (int i = 0; i < nSavedBufferHeight; ++i)
|
|
||||||
{
|
{
|
||||||
memcpy(&pBuffer[i * nSavedBufferWidth * 4],
|
// to get the actual texture data
|
||||||
&pTempData[(nSavedBufferHeight - i - 1) * nSavedBufferWidth * 4],
|
// #640 the image read from rendertexture is dirty
|
||||||
nSavedBufferWidth * 4);
|
for (int i = 0; i < nSavedBufferHeight; ++i)
|
||||||
}
|
{
|
||||||
|
memcpy(&pBuffer[i * nSavedBufferWidth * 4],
|
||||||
|
&pTempData[(nSavedBufferHeight - i - 1) * nSavedBufferWidth * 4],
|
||||||
|
nSavedBufferWidth * 4);
|
||||||
|
}
|
||||||
|
|
||||||
pImage->initWithImageData(pBuffer, nSavedBufferWidth * nSavedBufferHeight * 4, CCImage::kFmtRawData, nSavedBufferWidth, nSavedBufferHeight, 8);
|
pImage->initWithImageData(pBuffer, nSavedBufferWidth * nSavedBufferHeight * 4, CCImage::kFmtRawData, nSavedBufferWidth, nSavedBufferHeight, 8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pImage->initWithImageData(pTempData, nSavedBufferWidth * nSavedBufferHeight * 4, CCImage::kFmtRawData, nSavedBufferWidth, nSavedBufferHeight, 8);
|
||||||
|
}
|
||||||
|
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
CC_SAFE_DELETE_ARRAY(pBuffer);
|
CC_SAFE_DELETE_ARRAY(pBuffer);
|
||||||
|
|
|
@ -128,7 +128,7 @@ public:
|
||||||
/* creates a new CCImage from with the texture's data.
|
/* creates a new CCImage from with the texture's data.
|
||||||
Caller is responsible for releasing it by calling delete.
|
Caller is responsible for releasing it by calling delete.
|
||||||
*/
|
*/
|
||||||
CCImage* newCCImage();
|
CCImage* newCCImage(bool flipImage = true);
|
||||||
|
|
||||||
/** saves the texture into a file using JPEG format. The file will be saved in the Documents folder.
|
/** saves the texture into a file using JPEG format. The file will be saved in the Documents folder.
|
||||||
Returns YES if the operation is successful.
|
Returns YES if the operation is successful.
|
||||||
|
@ -145,6 +145,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void listenToBackground(CCObject *obj);
|
void listenToBackground(CCObject *obj);
|
||||||
|
|
||||||
|
/** Listen "come to foreground" message and restore the frame buffer object
|
||||||
|
It only has effect on Android.
|
||||||
|
*/
|
||||||
|
void listenToForeground(CCObject *obj);
|
||||||
|
|
||||||
/** Valid flags: GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT. They can be OR'ed. Valid when "autoDraw is YES. */
|
/** Valid flags: GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT. They can be OR'ed. Valid when "autoDraw is YES. */
|
||||||
unsigned int getClearFlags() const;
|
unsigned int getClearFlags() const;
|
||||||
void setClearFlags(unsigned int uClearFlags);
|
void setClearFlags(unsigned int uClearFlags);
|
||||||
|
|
Loading…
Reference in New Issue