Advertisement
Guest User

PNG Alpha Fix

a guest
Mar 4th, 2015
405
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.38 KB | None | 0 0
  1.  
  2. #include "RenderTextureAlpha.h"
  3.  
  4. RenderTextureAlpha * RenderTextureAlpha::create(int w, int h, Texture2D::PixelFormat eFormat)
  5. {
  6.     RenderTextureAlpha *ret = new (std::nothrow) RenderTextureAlpha();
  7.  
  8.     if(ret && ret->initWithWidthAndHeight(w, h, eFormat))
  9.     {
  10.         ret->autorelease();
  11.         return ret;
  12.     }
  13.     CC_SAFE_DELETE(ret);
  14.     return nullptr;
  15. }
  16.  
  17. bool RenderTextureAlpha::saveToFile(const std::string& fileName, Image::Format format, bool isRGBA, std::function<void (RenderTexture*, const std::string&)> callback)
  18. {
  19.     CCASSERT(format == Image::Format::JPG || format == Image::Format::PNG,
  20.              "the image can only be saved as JPG or PNG format");
  21.     if (isRGBA && format == Image::Format::JPG) CCLOG("RGBA is not supported for JPG format");
  22.    
  23.     _saveFileCallback = callback;
  24.    
  25.     std::string fullpath = FileUtils::getInstance()->getWritablePath() + fileName;
  26.     _saveToFileCommand.init(_globalZOrder);
  27.     _saveToFileCommand.func = CC_CALLBACK_0(RenderTextureAlpha::onSaveToFile, this, fullpath, isRGBA);
  28.    
  29.     Director::getInstance()->getRenderer()->addCommand(&_saveToFileCommand);
  30.     return true;
  31. }
  32.  
  33. void RenderTextureAlpha::onSaveToFile(const std::string& filename, bool isRGBA)
  34. {
  35.     Image *image = newImage(true);
  36.     if (image)
  37.     {
  38.         image->saveToFile(filename.c_str(), !isRGBA);
  39.     }
  40.     if(_saveFileCallback)
  41.     {
  42.         _saveFileCallback(this, filename);
  43.     }
  44.     CC_SAFE_DELETE(image);
  45. }
  46.  
  47. /* get buffer as Image */
  48. Image* RenderTextureAlpha::newImage(bool fliimage)
  49. {
  50.     CCASSERT(_pixelFormat == Texture2D::PixelFormat::RGBA8888, "only RGBA8888 can be saved as image");
  51.  
  52.     if (nullptr == _texture)
  53.     {
  54.         return nullptr;
  55.     }
  56.  
  57.     const Size& s = _texture->getContentSizeInPixels();
  58.  
  59.     // to get the image size to save
  60.     //        if the saving image domain exceeds the buffer texture domain,
  61.     //        it should be cut
  62.     int savedBufferWidth = (int)s.width;
  63.     int savedBufferHeight = (int)s.height;
  64.  
  65.     GLubyte *buffer = nullptr;
  66.     GLubyte *tempData = nullptr;
  67.     Image *image = new (std::nothrow) Image();
  68.  
  69.     do
  70.     {
  71.         CC_BREAK_IF(! (buffer = new (std::nothrow) GLubyte[savedBufferWidth * savedBufferHeight * 4]));
  72.  
  73.         if(! (tempData = new (std::nothrow) GLubyte[savedBufferWidth * savedBufferHeight * 4]))
  74.         {
  75.             delete[] buffer;
  76.             buffer = nullptr;
  77.             break;
  78.         }
  79.  
  80.         glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_oldFBO);
  81.         glBindFramebuffer(GL_FRAMEBUFFER, _FBO);
  82.  
  83.         // TODO: move this to configration, so we don't check it every time
  84.         /*  Certain Qualcomm Andreno gpu's will retain data in memory after a frame buffer switch which corrupts the render to the texture. The solution is to clear the frame buffer before rendering to the texture. However, calling glClear has the unintended result of clearing the current texture. Create a temporary texture to overcome this. At the end of RenderTexture::begin(), switch the attached texture to the second one, call glClear, and then switch back to the original texture. This solution is unnecessary for other devices as they don't have the same issue with switching frame buffers.
  85.         */
  86.         if (Configuration::getInstance()->checkForGLExtension("GL_QCOM"))
  87.         {
  88.             // -- bind a temporary texture so we can clear the render buffer without losing our texture
  89.             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _textureCopy->getName(), 0);
  90.             CHECK_GL_ERROR_DEBUG();
  91.             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  92.             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture->getName(), 0);
  93.         }
  94.         glPixelStorei(GL_PACK_ALIGNMENT, 1);
  95.         glReadPixels(0,0,savedBufferWidth, savedBufferHeight,GL_RGBA,GL_UNSIGNED_BYTE, tempData);
  96.         glBindFramebuffer(GL_FRAMEBUFFER, _oldFBO);
  97.  
  98.         // FIX BEGIN
  99.         for (int i = 0; i < savedBufferHeight; ++i)
  100.         {
  101.             for (int j = 0; j < savedBufferWidth; ++j)
  102.             {
  103.                 GLfloat Rs = (GLfloat)(tempData[(i * savedBufferWidth + j) * 4]) / 255.0;
  104.                 GLfloat Gs = (GLfloat)(tempData[(i * savedBufferWidth + j) * 4 + 1]) / 255.0;
  105.                 GLfloat Bs = (GLfloat)(tempData[(i * savedBufferWidth + j) * 4 + 2]) / 255.0;
  106.                 GLfloat As = (GLfloat)(tempData[(i * savedBufferWidth + j) * 4 + 3]) / 255.0;
  107.  
  108.                 const float backgroundAlpha = 0.f;
  109.                 GLfloat Rd = Rs/As + (backgroundAlpha * (1-As));
  110.                 GLfloat Gd = Gs/As + (backgroundAlpha * (1-As));
  111.                 GLfloat Bd = Bs/As + (backgroundAlpha * (1-As));
  112.  
  113.                 GLubyte nRd = (GLubyte)(Rd * 255.0);
  114.                 GLubyte nGd = (GLubyte)(Gd * 255.0);
  115.                 GLubyte nBd = (GLubyte)(Bd * 255.0);
  116.  
  117.                 tempData[(i * savedBufferWidth + j) * 4] = nRd;
  118.                 tempData[(i * savedBufferWidth + j) * 4 + 1] = nGd;
  119.                 tempData[(i * savedBufferWidth + j) * 4 + 2] = nBd;
  120.             }
  121.         }
  122.         // FIX END
  123.  
  124.         if ( fliimage ) // -- flip is only required when saving image to file
  125.         {
  126.             // to get the actual texture data
  127.             // #640 the image read from rendertexture is dirty
  128.             for (int i = 0; i < savedBufferHeight; ++i)
  129.             {
  130.                 memcpy(&buffer[i * savedBufferWidth * 4],
  131.                     &tempData[(savedBufferHeight - i - 1) * savedBufferWidth * 4],
  132.                     savedBufferWidth * 4);
  133.             }
  134.  
  135.             image->initWithRawData(buffer, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8);
  136.         }
  137.         else
  138.         {
  139.             image->initWithRawData(tempData, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8);
  140.         }
  141.  
  142.     } while (0);
  143.  
  144.     CC_SAFE_DELETE_ARRAY(buffer);
  145.     CC_SAFE_DELETE_ARRAY(tempData);
  146.  
  147.     return image;
  148. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement