2019-11-23 20:27:39 +08:00
/****************************************************************************
Copyright ( c ) 2009 Jason Booth
Copyright ( c ) 2010 - 2012 cocos2d - x . org
Copyright ( c ) 2013 - 2016 Chukong Technologies Inc .
Copyright ( c ) 2017 - 2018 Xiamen Yaji Software Co . , Ltd .
2022-12-12 19:41:07 +08:00
Copyright ( c ) 2022 Bytedance Inc .
2019-11-23 20:27:39 +08:00
2022-10-01 16:24:52 +08:00
https : //axmolengine.github.io/
2019-11-23 20:27:39 +08:00
Permission is hereby granted , free of charge , to any person obtaining a copy
of this software and associated documentation files ( the " Software " ) , to deal
in the Software without restriction , including without limitation the rights
to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
copies of the Software , and to permit persons to whom the Software is
furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2023-06-11 13:08:08 +08:00
# include "2d/RenderTexture.h"
2019-11-23 20:27:39 +08:00
2023-06-11 13:08:08 +08:00
# include "base/Utils.h"
# include "platform/FileUtils.h"
# include "base/EventType.h"
# include "base/Configuration.h"
# include "base/Director.h"
# include "base/EventListenerCustom.h"
# include "base/EventDispatcher.h"
# include "renderer/Renderer.h"
# include "2d/Camera.h"
# include "renderer/TextureCache.h"
2019-11-23 20:27:39 +08:00
# include "renderer/backend/Device.h"
# include "renderer/backend/Texture.h"
2020-09-21 22:10:50 +08:00
# include "renderer/backend/RenderTarget.h"
2019-11-23 20:27:39 +08:00
2022-07-11 17:50:21 +08:00
NS_AX_BEGIN
2019-11-23 20:27:39 +08:00
// implementation RenderTexture
RenderTexture : : RenderTexture ( )
{
2022-07-16 10:43:05 +08:00
# if AX_ENABLE_CACHE_TEXTURE_DATA
2019-11-23 20:27:39 +08:00
// Listen this event to save render texture before come to background.
// Then it can be restored after coming to foreground on Android.
2021-12-25 10:04:45 +08:00
auto toBackgroundListener =
2022-07-16 10:43:05 +08:00
EventListenerCustom : : create ( EVENT_COME_TO_BACKGROUND , AX_CALLBACK_1 ( RenderTexture : : listenToBackground , this ) ) ;
2019-11-23 20:27:39 +08:00
_eventDispatcher - > addEventListenerWithSceneGraphPriority ( toBackgroundListener , this ) ;
2021-12-25 10:04:45 +08:00
auto toForegroundListener =
2022-07-16 10:43:05 +08:00
EventListenerCustom : : create ( EVENT_COME_TO_FOREGROUND , AX_CALLBACK_1 ( RenderTexture : : listenToForeground , this ) ) ;
2019-11-23 20:27:39 +08:00
_eventDispatcher - > addEventListenerWithSceneGraphPriority ( toForegroundListener , this ) ;
# endif
}
RenderTexture : : ~ RenderTexture ( )
{
2022-07-16 10:43:05 +08:00
AX_SAFE_RELEASE ( _renderTarget ) ;
AX_SAFE_RELEASE ( _sprite ) ;
AX_SAFE_RELEASE ( _depthStencilTexture ) ;
AX_SAFE_RELEASE ( _UITextureImage ) ;
2019-11-23 20:27:39 +08:00
}
void RenderTexture : : listenToBackground ( EventCustom * /*event*/ )
{
// We have not found a way to dispatch the enter background message before the texture data are destroyed.
// So we disable this pair of message handler at present.
2022-07-16 10:43:05 +08:00
# if AX_ENABLE_CACHE_TEXTURE_DATA
2019-11-23 20:27:39 +08:00
// to get the rendered texture data
2021-12-25 10:04:45 +08:00
auto func = [ & ] ( Image * uiTextureImage ) {
2019-11-23 20:27:39 +08:00
if ( uiTextureImage )
{
2022-07-16 10:43:05 +08:00
AX_SAFE_RELEASE ( _UITextureImage ) ;
2019-11-23 20:27:39 +08:00
_UITextureImage = uiTextureImage ;
2022-07-16 10:43:05 +08:00
AX_SAFE_RETAIN ( _UITextureImage ) ;
2021-10-23 23:27:14 +08:00
const Vec2 & s = _texture2D - > getContentSizeInPixels ( ) ;
2021-12-25 10:04:45 +08:00
VolatileTextureMgr : : addDataTexture ( _texture2D , uiTextureImage - > getData ( ) , s . width * s . height * 4 ,
backend : : PixelFormat : : RGBA8 , s ) ;
2019-11-23 20:27:39 +08:00
}
else
{
2022-07-16 10:43:05 +08:00
AXLOG ( " Cache rendertexture failed! " ) ;
2019-11-23 20:27:39 +08:00
}
2022-07-16 10:43:05 +08:00
AX_SAFE_RELEASE ( uiTextureImage ) ;
2019-11-23 20:27:39 +08:00
} ;
auto callback = std : : bind ( func , std : : placeholders : : _1 ) ;
newImage ( callback , false ) ;
# endif
}
void RenderTexture : : listenToForeground ( EventCustom * /*event*/ )
{
2022-07-16 10:43:05 +08:00
# if AX_ENABLE_CACHE_TEXTURE_DATA
2021-10-23 23:27:14 +08:00
const Vec2 & s = _texture2D - > getContentSizeInPixels ( ) ;
2021-12-25 10:04:45 +08:00
// TODO new-renderer: field _depthAndStencilFormat removal
// if (_depthAndStencilFormat != 0)
// {
// setupDepthAndStencil(s.width, s.height);
// }
2019-11-23 20:27:39 +08:00
_texture2D - > setAntiAliasTexParameters ( ) ;
# endif
}
2022-06-28 17:33:00 +08:00
RenderTexture * RenderTexture : : create ( int w , int h , backend : : PixelFormat eFormat , bool sharedRenderTarget )
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
RenderTexture * ret = new RenderTexture ( ) ;
2019-11-23 20:27:39 +08:00
2022-06-28 17:33:00 +08:00
if ( ret - > initWithWidthAndHeight ( w , h , eFormat , sharedRenderTarget ) )
2019-11-23 20:27:39 +08:00
{
ret - > autorelease ( ) ;
return ret ;
}
2022-07-16 10:43:05 +08:00
AX_SAFE_DELETE ( ret ) ;
2019-11-23 20:27:39 +08:00
return nullptr ;
}
2022-06-28 17:33:00 +08:00
RenderTexture * RenderTexture : : create ( int w , int h , backend : : PixelFormat eFormat , PixelFormat uDepthStencilFormat , bool sharedRenderTarget )
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
RenderTexture * ret = new RenderTexture ( ) ;
2019-11-23 20:27:39 +08:00
2022-06-28 17:33:00 +08:00
if ( ret - > initWithWidthAndHeight ( w , h , eFormat , uDepthStencilFormat , sharedRenderTarget ) )
2019-11-23 20:27:39 +08:00
{
ret - > autorelease ( ) ;
return ret ;
}
2022-07-16 10:43:05 +08:00
AX_SAFE_DELETE ( ret ) ;
2019-11-23 20:27:39 +08:00
return nullptr ;
}
2022-06-28 17:33:00 +08:00
RenderTexture * RenderTexture : : create ( int w , int h , bool sharedRenderTarget )
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
RenderTexture * ret = new RenderTexture ( ) ;
2019-11-23 20:27:39 +08:00
2022-06-28 17:33:00 +08:00
if ( ret - > initWithWidthAndHeight ( w , h , backend : : PixelFormat : : RGBA8 , PixelFormat : : NONE , sharedRenderTarget ) )
2019-11-23 20:27:39 +08:00
{
ret - > autorelease ( ) ;
return ret ;
}
2022-07-16 10:43:05 +08:00
AX_SAFE_DELETE ( ret ) ;
2019-11-23 20:27:39 +08:00
return nullptr ;
}
2022-06-28 17:33:00 +08:00
bool RenderTexture : : initWithWidthAndHeight ( int w , int h , backend : : PixelFormat eFormat , bool sharedRenderTarget )
2019-11-23 20:27:39 +08:00
{
2022-06-28 17:33:00 +08:00
return initWithWidthAndHeight ( w , h , eFormat , PixelFormat : : NONE , sharedRenderTarget ) ;
2019-11-23 20:27:39 +08:00
}
2022-06-28 17:33:00 +08:00
bool RenderTexture : : initWithWidthAndHeight ( int w ,
int h ,
backend : : PixelFormat format ,
PixelFormat depthStencilFormat ,
bool sharedRenderTarget )
2019-11-23 20:27:39 +08:00
{
2023-09-01 03:35:30 +08:00
AXASSERT ( format = = backend : : PixelFormat : : RGBA8 | | format = = PixelFormat : : RGB8 | | format = = PixelFormat : : RGBA4 , " only RGB and RGBA formats are valid for a render texture " ) ;
2019-11-23 20:27:39 +08:00
bool ret = false ;
do
{
2021-12-25 10:04:45 +08:00
_fullRect = _rtTextureRect = Rect ( 0 , 0 , w , h ) ;
2022-07-16 10:43:05 +08:00
w = ( int ) ( w * AX_CONTENT_SCALE_FACTOR ( ) ) ;
h = ( int ) ( h * AX_CONTENT_SCALE_FACTOR ( ) ) ;
2021-12-25 10:04:45 +08:00
_fullviewPort = Rect ( 0 , 0 , w , h ) ;
2019-11-23 20:27:39 +08:00
// textures must be power of two squared
int powW = 0 ;
int powH = 0 ;
if ( Configuration : : getInstance ( ) - > supportsNPOT ( ) )
{
powW = w ;
powH = h ;
}
else
{
powW = ccNextPOT ( w ) ;
powH = ccNextPOT ( h ) ;
}
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
backend : : TextureDescriptor descriptor ;
2021-12-25 10:04:45 +08:00
descriptor . width = powW ;
descriptor . height = powH ;
descriptor . textureUsage = TextureUsage : : RENDER_TARGET ;
2020-09-25 11:07:56 +08:00
descriptor . textureFormat = PixelFormat : : RGBA8 ;
2021-12-25 10:04:45 +08:00
_texture2D = new Texture2D ( ) ;
2022-07-16 10:43:05 +08:00
_texture2D - > updateTextureDescriptor ( descriptor , ! ! AX_ENABLE_PREMULTIPLIED_ALPHA ) ;
2019-11-23 20:27:39 +08:00
_renderTargetFlags = RenderTargetFlag : : COLOR ;
2022-12-12 19:41:07 +08:00
if ( PixelFormat : : D24S8 = = depthStencilFormat | | sharedRenderTarget )
2019-11-23 20:27:39 +08:00
{
2021-12-25 10:04:45 +08:00
_renderTargetFlags = RenderTargetFlag : : ALL ;
2022-12-12 19:41:07 +08:00
descriptor . textureFormat = PixelFormat : : D24S8 ;
2019-11-23 20:27:39 +08:00
2023-04-28 14:54:57 +08:00
AX_SAFE_RELEASE ( _depthStencilTexture ) ;
2021-12-08 00:11:53 +08:00
_depthStencilTexture = new Texture2D ( ) ;
2020-09-25 15:04:55 +08:00
_depthStencilTexture - > updateTextureDescriptor ( descriptor ) ;
2019-11-23 20:27:39 +08:00
}
2022-07-16 10:43:05 +08:00
AX_SAFE_RELEASE ( _renderTarget ) ;
2022-06-28 17:33:00 +08:00
if ( sharedRenderTarget )
{
_renderTarget = _director - > getRenderer ( ) - > getOffscreenRenderTarget ( ) ;
_renderTarget - > retain ( ) ;
}
else
{
_renderTarget = backend : : Device : : getInstance ( ) - > newRenderTarget (
_renderTargetFlags , _texture2D ? _texture2D - > getBackendTexture ( ) : nullptr ,
_depthStencilTexture ? _depthStencilTexture - > getBackendTexture ( ) : nullptr ,
_depthStencilTexture ? _depthStencilTexture - > getBackendTexture ( ) : nullptr ) ;
}
2022-06-24 14:18:48 +08:00
_renderTarget - > setColorAttachment ( _texture2D ? _texture2D - > getBackendTexture ( ) : nullptr ) ;
auto depthStencilTexture = _depthStencilTexture ? _depthStencilTexture - > getBackendTexture ( ) : nullptr ;
_renderTarget - > setDepthAttachment ( depthStencilTexture ) ;
_renderTarget - > setStencilAttachment ( depthStencilTexture ) ;
2020-09-21 22:10:50 +08:00
clearColorAttachment ( ) ;
2019-11-23 20:27:39 +08:00
_texture2D - > setAntiAliasTexParameters ( ) ;
// retained
setSprite ( Sprite : : createWithTexture ( _texture2D ) ) ;
2022-11-10 21:22:55 +08:00
# if defined(AX_USE_GL)
2019-11-23 20:27:39 +08:00
_sprite - > setFlippedY ( true ) ;
# endif
2021-12-25 10:04:45 +08:00
if ( _texture2D - > hasPremultipliedAlpha ( ) )
{
2020-11-16 12:21:27 +08:00
_sprite - > setBlendFunc ( BlendFunc : : ALPHA_PREMULTIPLIED ) ;
_sprite - > setOpacityModifyRGB ( true ) ;
}
2021-12-25 10:04:45 +08:00
else
{
2020-11-16 12:21:27 +08:00
_sprite - > setBlendFunc ( BlendFunc : : ALPHA_NON_PREMULTIPLIED ) ;
_sprite - > setOpacityModifyRGB ( false ) ;
}
_texture2D - > release ( ) ;
2019-11-23 20:27:39 +08:00
// Disabled by default.
_autoDraw = false ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
// add sprite for backward compatibility
addChild ( _sprite ) ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
ret = true ;
} while ( 0 ) ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
return ret ;
}
void RenderTexture : : setSprite ( Sprite * sprite )
{
2022-07-16 10:43:05 +08:00
# if AX_ENABLE_GC_FOR_NATIVE_OBJECTS
2019-11-23 20:27:39 +08:00
auto sEngine = ScriptEngineManager : : getInstance ( ) - > getScriptEngine ( ) ;
if ( sEngine )
{
if ( sprite )
sEngine - > retainScriptObject ( this , sprite ) ;
if ( _sprite )
sEngine - > releaseScriptObject ( this , _sprite ) ;
}
2022-07-16 10:43:05 +08:00
# endif // AX_ENABLE_GC_FOR_NATIVE_OBJECTS
2023-04-28 14:54:57 +08:00
if ( _sprite )
{
_sprite - > removeFromParent ( ) ;
_sprite - > release ( ) ;
}
2022-07-16 10:43:05 +08:00
AX_SAFE_RETAIN ( sprite ) ;
2019-11-23 20:27:39 +08:00
_sprite = sprite ;
}
void RenderTexture : : setVirtualViewport ( const Vec2 & rtBegin , const Rect & fullRect , const Rect & fullViewport )
{
_rtTextureRect . origin . x = rtBegin . x ;
_rtTextureRect . origin . y = rtBegin . y ;
_fullRect = fullRect ;
_fullviewPort = fullViewport ;
}
2022-06-28 17:33:00 +08:00
bool RenderTexture : : isSharedRenderTarget ( ) const
{
return _renderTarget = = _director - > getRenderer ( ) - > getOffscreenRenderTarget ( ) ;
}
2019-11-23 20:27:39 +08:00
void RenderTexture : : beginWithClear ( float r , float g , float b , float a )
{
beginWithClear ( r , g , b , a , 0 , 0 , ClearFlag : : COLOR ) ;
}
void RenderTexture : : beginWithClear ( float r , float g , float b , float a , float depthValue )
{
beginWithClear ( r , g , b , a , depthValue , 0 , ClearFlag : : COLOR | ClearFlag : : DEPTH ) ;
}
void RenderTexture : : beginWithClear ( float r , float g , float b , float a , float depthValue , int stencilValue )
{
beginWithClear ( r , g , b , a , depthValue , stencilValue , ClearFlag : : ALL ) ;
}
2021-12-25 10:04:45 +08:00
void RenderTexture : : beginWithClear ( float r ,
float g ,
float b ,
float a ,
float depthValue ,
int stencilValue ,
ClearFlag flags )
2019-11-23 20:27:39 +08:00
{
setClearColor ( Color4F ( r , g , b , a ) ) ;
setClearDepth ( depthValue ) ;
setClearStencil ( stencilValue ) ;
setClearFlags ( flags ) ;
begin ( ) ;
2020-09-13 19:16:59 +08:00
_director - > getRenderer ( ) - > clear ( _clearFlags , _clearColor , _clearDepth , _clearStencil , _globalZOrder ) ;
2019-11-23 20:27:39 +08:00
}
void RenderTexture : : clear ( float r , float g , float b , float a )
{
this - > beginWithClear ( r , g , b , a ) ;
this - > end ( ) ;
}
void RenderTexture : : clearDepth ( float depthValue )
{
setClearDepth ( depthValue ) ;
}
void RenderTexture : : clearStencil ( int stencilValue )
{
setClearStencil ( stencilValue ) ;
}
2021-12-25 10:04:45 +08:00
void RenderTexture : : visit ( Renderer * renderer , const Mat4 & parentTransform , uint32_t parentFlags )
2019-11-23 20:27:39 +08:00
{
// override visit.
// Don't call visit on its children
if ( ! _visible )
{
return ;
}
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
uint32_t flags = processParentFlags ( parentTransform , parentFlags ) ;
// IMPORTANT:
// To ease the migration to v3.0, we still support the Mat4 stack,
// but it is deprecated and your code should not rely on it
2020-09-13 19:16:59 +08:00
_director - > pushMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_MODELVIEW ) ;
_director - > loadMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_MODELVIEW , _modelViewTransform ) ;
2019-11-23 20:27:39 +08:00
_sprite - > visit ( renderer , _modelViewTransform , flags ) ;
if ( isVisitableByVisitingCamera ( ) )
{
draw ( renderer , _modelViewTransform , flags ) ;
}
2021-12-25 10:04:45 +08:00
2020-09-13 19:16:59 +08:00
_director - > popMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_MODELVIEW ) ;
2019-11-23 20:27:39 +08:00
// FIX ME: Why need to set _orderOfArrival to 0??
// Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920
// setOrderOfArrival(0);
}
2021-12-31 12:12:40 +08:00
bool RenderTexture : : saveToFileAsNonPMA ( std : : string_view filename , bool isRGBA , SaveFileCallbackType callback )
2019-11-23 20:27:39 +08:00
{
std : : string basename ( filename ) ;
std : : transform ( basename . begin ( ) , basename . end ( ) , basename . begin ( ) , : : tolower ) ;
if ( basename . find ( " .png " ) ! = std : : string : : npos )
{
return saveToFileAsNonPMA ( filename , Image : : Format : : PNG , isRGBA , callback ) ;
}
else if ( basename . find ( " .jpg " ) ! = std : : string : : npos )
{
2021-12-25 10:04:45 +08:00
if ( isRGBA )
2022-07-16 10:43:05 +08:00
AXLOG ( " RGBA is not supported for JPG format. " ) ;
2019-11-23 20:27:39 +08:00
return saveToFileAsNonPMA ( filename , Image : : Format : : JPG , false , callback ) ;
}
else
{
2022-07-16 10:43:05 +08:00
AXLOG ( " Only PNG and JPG format are supported now! " ) ;
2019-11-23 20:27:39 +08:00
}
return saveToFileAsNonPMA ( filename , Image : : Format : : JPG , false , callback ) ;
2021-12-25 10:04:45 +08:00
}
2021-12-31 12:12:40 +08:00
bool RenderTexture : : saveToFile ( std : : string_view filename , bool isRGBA , SaveFileCallbackType callback )
2019-11-23 20:27:39 +08:00
{
std : : string basename ( filename ) ;
std : : transform ( basename . begin ( ) , basename . end ( ) , basename . begin ( ) , : : tolower ) ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
if ( basename . find ( " .png " ) ! = std : : string : : npos )
{
return saveToFile ( filename , Image : : Format : : PNG , isRGBA , callback ) ;
}
else if ( basename . find ( " .jpg " ) ! = std : : string : : npos )
{
2021-12-25 10:04:45 +08:00
if ( isRGBA )
2022-07-16 10:43:05 +08:00
AXLOG ( " RGBA is not supported for JPG format. " ) ;
2019-11-23 20:27:39 +08:00
return saveToFile ( filename , Image : : Format : : JPG , false , callback ) ;
}
else
{
2022-07-16 10:43:05 +08:00
AXLOG ( " Only PNG and JPG format are supported now! " ) ;
2019-11-23 20:27:39 +08:00
}
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
return saveToFile ( filename , Image : : Format : : JPG , false , callback ) ;
}
2021-12-31 12:12:40 +08:00
bool RenderTexture : : saveToFileAsNonPMA ( std : : string_view fileName ,
2021-12-25 10:04:45 +08:00
Image : : Format format ,
bool isRGBA ,
2021-12-31 12:12:40 +08:00
SaveFileCallbackType callback )
2019-11-23 20:27:39 +08:00
{
2022-07-16 10:43:05 +08:00
AXASSERT ( format = = Image : : Format : : JPG | | format = = Image : : Format : : PNG ,
2021-12-25 10:04:45 +08:00
" the image can only be saved as JPG or PNG format " ) ;
if ( isRGBA & & format = = Image : : Format : : JPG )
2022-07-16 10:43:05 +08:00
AXLOG ( " RGBA is not supported for JPG format " ) ;
2019-11-23 20:27:39 +08:00
_saveFileCallback = callback ;
2021-12-31 12:12:40 +08:00
std : : string fullpath = FileUtils : : getInstance ( ) - > getWritablePath ( ) . append ( fileName ) ;
2019-11-23 20:27:39 +08:00
2022-06-24 14:18:48 +08:00
auto renderer = _director - > getRenderer ( ) ;
auto saveToFileCommand = renderer - > nextCallbackCommand ( ) ;
saveToFileCommand - > init ( _globalZOrder ) ;
2023-01-03 23:02:17 +08:00
saveToFileCommand - > func = AX_CALLBACK_0 ( RenderTexture : : onSaveToFile , this , std : : move ( fullpath ) , isRGBA , true ) ;
2022-06-24 14:18:48 +08:00
renderer - > addCommand ( saveToFileCommand ) ;
2019-11-23 20:27:39 +08:00
return true ;
}
2021-12-31 12:12:40 +08:00
bool RenderTexture : : saveToFile ( std : : string_view fileName ,
2021-12-25 10:04:45 +08:00
Image : : Format format ,
bool isRGBA ,
2022-06-24 14:18:48 +08:00
SaveFileCallbackType callback )
2019-11-23 20:27:39 +08:00
{
2022-07-16 10:43:05 +08:00
AXASSERT ( format = = Image : : Format : : JPG | | format = = Image : : Format : : PNG ,
2019-11-23 20:27:39 +08:00
" the image can only be saved as JPG or PNG format " ) ;
2021-12-25 10:04:45 +08:00
if ( isRGBA & & format = = Image : : Format : : JPG )
2022-07-16 10:43:05 +08:00
AXLOG ( " RGBA is not supported for JPG format " ) ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
_saveFileCallback = callback ;
2021-12-25 10:04:45 +08:00
2021-12-31 12:12:40 +08:00
std : : string fullpath = FileUtils : : getInstance ( ) - > getWritablePath ( ) . append ( fileName ) ;
2021-12-25 10:04:45 +08:00
2022-06-24 14:18:48 +08:00
auto renderer = _director - > getRenderer ( ) ;
auto saveToFileCommand = renderer - > nextCallbackCommand ( ) ;
saveToFileCommand - > init ( _globalZOrder ) ;
2023-01-03 23:02:17 +08:00
saveToFileCommand - > func = AX_CALLBACK_0 ( RenderTexture : : onSaveToFile , this , std : : move ( fullpath ) , isRGBA , false ) ;
2022-06-24 14:18:48 +08:00
_director - > getRenderer ( ) - > addCommand ( saveToFileCommand ) ;
2019-11-23 20:27:39 +08:00
return true ;
}
2023-01-03 23:02:17 +08:00
void RenderTexture : : onSaveToFile ( std : : string filename , bool isRGBA , bool forceNonPMA )
2019-11-23 20:27:39 +08:00
{
2023-01-03 23:02:17 +08:00
auto callbackFunc = [ this , _filename = std : : move ( filename ) , isRGBA , forceNonPMA ] ( RefPtr < Image > image ) {
2019-11-23 20:27:39 +08:00
if ( image )
{
if ( forceNonPMA & & image - > hasPremultipliedAlpha ( ) )
{
image - > reversePremultipliedAlpha ( ) ;
}
2023-01-03 23:02:17 +08:00
image - > saveToFile ( _filename , ! isRGBA ) ;
2019-11-23 20:27:39 +08:00
}
2021-12-25 10:04:45 +08:00
if ( _saveFileCallback )
2019-11-23 20:27:39 +08:00
{
2023-01-03 23:02:17 +08:00
_saveFileCallback ( this , _filename ) ;
2019-11-23 20:27:39 +08:00
}
} ;
newImage ( callbackFunc ) ;
}
/* get buffer as Image */
2020-09-11 11:57:55 +08:00
void RenderTexture : : newImage ( std : : function < void ( RefPtr < Image > ) > imageCallback , bool flipImage )
2019-11-23 20:27:39 +08:00
{
2022-07-16 10:43:05 +08:00
AXASSERT ( _pixelFormat = = backend : : PixelFormat : : RGBA8 , " only RGBA8888 can be saved as image " ) ;
2019-11-23 20:27:39 +08:00
if ( ( nullptr = = _texture2D ) )
{
2021-12-25 10:04:45 +08:00
return ;
2019-11-23 20:27:39 +08:00
}
2021-10-23 23:27:14 +08:00
const Vec2 & s = _texture2D - > getContentSizeInPixels ( ) ;
2019-11-23 20:27:39 +08:00
// to get the image size to save
// if the saving image domain exceeds the buffer texture domain,
// it should be cut
2021-12-25 10:04:45 +08:00
int savedBufferWidth = ( int ) s . width ;
int savedBufferHeight = ( int ) s . height ;
2020-06-12 11:24:10 +08:00
bool hasPremultipliedAlpha = _texture2D - > hasPremultipliedAlpha ( ) ;
2021-12-25 10:04:45 +08:00
2020-09-21 22:10:50 +08:00
_director - > getRenderer ( ) - > readPixels ( _renderTarget , [ = ] ( const backend : : PixelBufferDescriptor & pbd ) {
2021-12-25 10:04:45 +08:00
if ( pbd )
{
auto image = utils : : makeInstance < Image > ( & Image : : initWithRawData , pbd . _data . getBytes ( ) , pbd . _data . getSize ( ) ,
pbd . _width , pbd . _height , 8 , hasPremultipliedAlpha ) ;
2020-06-12 11:24:10 +08:00
imageCallback ( image ) ;
2020-09-10 21:14:28 +08:00
}
2021-12-25 10:04:45 +08:00
else
imageCallback ( nullptr ) ;
2020-09-13 13:27:50 +08:00
} ) ;
2019-11-23 20:27:39 +08:00
}
2021-12-25 10:04:45 +08:00
void RenderTexture : : draw ( Renderer * renderer , const Mat4 & transform , uint32_t flags )
2019-11-23 20:27:39 +08:00
{
if ( _autoDraw )
{
2021-12-25 10:04:45 +08:00
// Begin will create a render group using new render target
2019-11-23 20:27:39 +08:00
begin ( ) ;
2021-12-25 10:04:45 +08:00
// clear screen
2021-04-22 22:01:47 +08:00
_director - > getRenderer ( ) - > clear ( _clearFlags , _clearColor , _clearDepth , _clearStencil , _globalZOrder ) ;
2019-11-23 20:27:39 +08:00
//! make sure all children are drawn
sortAllChildren ( ) ;
2021-12-25 10:04:45 +08:00
for ( const auto & child : _children )
2019-11-23 20:27:39 +08:00
{
if ( child ! = _sprite )
child - > visit ( renderer , transform , flags ) ;
}
2021-12-25 10:04:45 +08:00
// End will pop the current render group
2019-11-23 20:27:39 +08:00
end ( ) ;
}
}
void RenderTexture : : onBegin ( )
{
2021-04-22 22:01:47 +08:00
_oldProjMatrix = _director - > getMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_PROJECTION ) ;
_director - > loadMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_PROJECTION , _projectionMatrix ) ;
2019-11-23 20:27:39 +08:00
2021-04-22 22:01:47 +08:00
_oldTransMatrix = _director - > getMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_MODELVIEW ) ;
_director - > loadMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_MODELVIEW , _transformMatrix ) ;
2019-11-23 20:27:39 +08:00
2021-12-25 10:04:45 +08:00
if ( ! _keepMatrix )
2019-11-23 20:27:39 +08:00
{
2021-04-22 22:01:47 +08:00
_director - > setProjection ( _director - > getProjection ( ) ) ;
2021-10-23 23:27:14 +08:00
const Vec2 & texSize = _texture2D - > getContentSizeInPixels ( ) ;
2019-11-23 20:27:39 +08:00
// Calculate the adjustment ratios based on the old and new projections
2021-12-25 10:04:45 +08:00
Vec2 size = _director - > getWinSizeInPixels ( ) ;
float widthRatio = size . width / texSize . width ;
2019-11-23 20:27:39 +08:00
float heightRatio = size . height / texSize . height ;
Mat4 orthoMatrix ;
2021-12-25 10:04:45 +08:00
Mat4 : : createOrthographicOffCenter ( ( float ) - 1.0 / widthRatio , ( float ) 1.0 / widthRatio , ( float ) - 1.0 / heightRatio ,
( float ) 1.0 / heightRatio , - 1 , 1 , & orthoMatrix ) ;
2021-04-22 22:01:47 +08:00
_director - > multiplyMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_PROJECTION , orthoMatrix ) ;
2019-11-23 20:27:39 +08:00
}
Rect viewport ;
2021-12-25 10:04:45 +08:00
viewport . size . width = _fullviewPort . size . width ;
viewport . size . height = _fullviewPort . size . height ;
float viewPortRectWidthRatio = float ( viewport . size . width ) / _fullRect . size . width ;
float viewPortRectHeightRatio = float ( viewport . size . height ) / _fullRect . size . height ;
viewport . origin . x = ( _fullRect . origin . x - _rtTextureRect . origin . x ) * viewPortRectWidthRatio ;
viewport . origin . y = ( _fullRect . origin . y - _rtTextureRect . origin . y ) * viewPortRectHeightRatio ;
Renderer * renderer = _director - > getRenderer ( ) ;
2019-11-23 20:27:39 +08:00
_oldViewport = renderer - > getViewport ( ) ;
renderer - > setViewPort ( viewport . origin . x , viewport . origin . y , viewport . size . width , viewport . size . height ) ;
2020-09-21 22:10:50 +08:00
_oldRenderTarget = renderer - > getRenderTarget ( ) ;
renderer - > setRenderTarget ( _renderTarget ) ;
2019-11-23 20:27:39 +08:00
}
void RenderTexture : : onEnd ( )
{
2021-04-22 22:01:47 +08:00
_director - > loadMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_PROJECTION , _oldProjMatrix ) ;
_director - > loadMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_MODELVIEW , _oldTransMatrix ) ;
2021-12-25 10:04:45 +08:00
Renderer * renderer = _director - > getRenderer ( ) ;
2023-09-01 03:35:30 +08:00
renderer - > setViewPort ( _oldViewport . x , _oldViewport . y , _oldViewport . width , _oldViewport . height ) ;
2020-09-21 22:10:50 +08:00
renderer - > setRenderTarget ( _oldRenderTarget ) ;
2019-11-23 20:27:39 +08:00
}
void RenderTexture : : begin ( )
{
2020-09-13 19:16:59 +08:00
_director - > pushMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_PROJECTION ) ;
_projectionMatrix = _director - > getMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_PROJECTION ) ;
2021-12-25 10:04:45 +08:00
2020-09-13 19:16:59 +08:00
_director - > pushMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_MODELVIEW ) ;
_transformMatrix = _director - > getMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_MODELVIEW ) ;
2021-12-25 10:04:45 +08:00
if ( ! _keepMatrix )
2019-11-23 20:27:39 +08:00
{
2020-09-13 19:16:59 +08:00
_director - > setProjection ( _director - > getProjection ( ) ) ;
2021-12-25 10:04:45 +08:00
2021-10-23 23:27:14 +08:00
const Vec2 & texSize = _texture2D - > getContentSizeInPixels ( ) ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
// Calculate the adjustment ratios based on the old and new projections
2021-10-23 23:27:14 +08:00
Vec2 size = _director - > getWinSizeInPixels ( ) ;
2021-12-25 10:04:45 +08:00
float widthRatio = size . width / texSize . width ;
2019-11-23 20:27:39 +08:00
float heightRatio = size . height / texSize . height ;
2021-12-25 10:04:45 +08:00
2019-11-23 20:27:39 +08:00
Mat4 orthoMatrix ;
2021-12-25 10:04:45 +08:00
Mat4 : : createOrthographicOffCenter ( ( float ) - 1.0 / widthRatio , ( float ) 1.0 / widthRatio , ( float ) - 1.0 / heightRatio ,
( float ) 1.0 / heightRatio , - 1 , 1 , & orthoMatrix ) ;
2020-09-13 19:16:59 +08:00
_director - > multiplyMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_PROJECTION , orthoMatrix ) ;
2019-11-23 20:27:39 +08:00
}
2021-12-25 10:04:45 +08:00
Renderer * renderer = _director - > getRenderer ( ) ;
2022-11-28 08:37:22 +08:00
auto * groupCommand = renderer - > getNextGroupCommand ( ) ;
groupCommand - > init ( _globalZOrder ) ;
renderer - > addCommand ( groupCommand ) ;
renderer - > pushGroup ( groupCommand - > getRenderQueueID ( ) ) ;
2019-11-23 20:27:39 +08:00
2022-06-24 14:18:48 +08:00
auto beginCommand = renderer - > nextCallbackCommand ( ) ;
beginCommand - > init ( _globalZOrder ) ;
2022-07-16 10:43:05 +08:00
beginCommand - > func = AX_CALLBACK_0 ( RenderTexture : : onBegin , this ) ;
2022-06-24 14:18:48 +08:00
renderer - > addCommand ( beginCommand ) ;
2019-11-23 20:27:39 +08:00
}
void RenderTexture : : end ( )
{
2021-12-25 10:04:45 +08:00
Renderer * renderer = _director - > getRenderer ( ) ;
2022-06-24 14:18:48 +08:00
auto endCommand = renderer - > nextCallbackCommand ( ) ;
endCommand - > init ( _globalZOrder ) ;
2022-07-16 10:43:05 +08:00
endCommand - > func = AX_CALLBACK_0 ( RenderTexture : : onEnd , this ) ;
2022-06-24 14:18:48 +08:00
renderer - > addCommand ( endCommand ) ;
2019-11-23 20:27:39 +08:00
renderer - > popGroup ( ) ;
2020-09-13 19:16:59 +08:00
_director - > popMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_PROJECTION ) ;
_director - > popMatrix ( MATRIX_STACK_TYPE : : MATRIX_STACK_MODELVIEW ) ;
2019-11-23 20:27:39 +08:00
}
void RenderTexture : : setClearFlags ( ClearFlag clearFlags )
{
_clearFlags = clearFlags ;
2021-12-25 10:04:45 +08:00
if ( _clearFlags ! = ClearFlag : : NONE & & ! _depthStencilTexture )
2019-11-23 20:27:39 +08:00
{
_clearFlags = ClearFlag : : COLOR ;
}
}
void RenderTexture : : clearColorAttachment ( )
{
2022-06-24 14:18:48 +08:00
auto renderer = _director - > getRenderer ( ) ;
auto beforeClearAttachmentCommand = renderer - > nextCallbackCommand ( ) ;
beforeClearAttachmentCommand - > init ( 0 ) ;
2023-03-08 08:34:17 +08:00
beforeClearAttachmentCommand - > func = [ this , renderer ] ( ) - > void {
2020-10-16 16:25:10 +08:00
_oldRenderTarget = renderer - > getRenderTarget ( ) ;
renderer - > setRenderTarget ( _renderTarget ) ;
} ;
2022-06-24 14:18:48 +08:00
renderer - > addCommand ( beforeClearAttachmentCommand ) ;
2020-10-16 16:25:10 +08:00
Color4F color ( 0.f , 0.f , 0.f , 0.f ) ;
renderer - > clear ( ClearFlag : : COLOR , color , 1 , 0 , _globalZOrder ) ;
2022-06-24 14:18:48 +08:00
// auto renderer = _director->getRenderer();
auto afterClearAttachmentCommand = renderer - > nextCallbackCommand ( ) ;
afterClearAttachmentCommand - > init ( 0 ) ;
2023-03-08 08:34:17 +08:00
afterClearAttachmentCommand - > func = [ this , renderer ] ( ) - > void { renderer - > setRenderTarget ( _oldRenderTarget ) ; } ;
2022-06-24 14:18:48 +08:00
renderer - > addCommand ( afterClearAttachmentCommand ) ;
2019-11-23 20:27:39 +08:00
}
2022-07-11 17:50:21 +08:00
NS_AX_END