2012-04-19 14:35:52 +08:00
/****************************************************************************
Copyright ( c ) 2008 - 2010 Ricardo Quesada
2014-01-07 11:25:07 +08:00
Copyright ( c ) 2010 - 2012 cocos2d - x . org
2012-04-19 14:35:52 +08:00
Copyright ( c ) 2011 Zynga Inc .
2016-08-05 09:42:15 +08:00
Copyright ( c ) 2013 - 2016 Chukong Technologies Inc .
2012-04-19 14:35:52 +08:00
http : //www.cocos2d-x.org
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-04-30 08:37:36 +08:00
2014-04-27 01:11:22 +08:00
# include "2d/CCSprite.h"
2014-05-17 05:36:00 +08:00
2014-11-17 01:29:05 +08:00
# include <algorithm>
2014-04-27 01:11:22 +08:00
# include "2d/CCSpriteBatchNode.h"
2014-04-30 08:37:36 +08:00
# include "2d/CCAnimationCache.h"
2014-04-27 01:11:22 +08:00
# include "2d/CCSpriteFrame.h"
# include "2d/CCSpriteFrameCache.h"
2014-05-17 05:36:00 +08:00
# include "renderer/CCTextureCache.h"
# include "renderer/CCTexture2D.h"
2014-05-10 09:39:25 +08:00
# include "renderer/CCRenderer.h"
2014-04-30 08:37:36 +08:00
# include "base/CCDirector.h"
2016-06-15 15:01:26 +08:00
# include "base/ccUTF8.h"
2015-07-30 11:53:23 +08:00
# include "2d/CCCamera.h"
2013-12-19 05:52:10 +08:00
2012-04-19 14:35:52 +08:00
NS_CC_BEGIN
2014-08-30 03:54:24 +08:00
// MARK: create, init, dealloc
2013-07-26 06:53:24 +08:00
Sprite * Sprite : : createWithTexture ( Texture2D * texture )
2012-04-19 14:35:52 +08:00
{
2014-05-06 07:53:37 +08:00
Sprite * sprite = new ( std : : nothrow ) Sprite ( ) ;
if ( sprite & & sprite - > initWithTexture ( texture ) )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
sprite - > autorelease ( ) ;
return sprite ;
2012-04-19 14:35:52 +08:00
}
2013-07-26 06:53:24 +08:00
CC_SAFE_DELETE ( sprite ) ;
2013-12-18 17:47:20 +08:00
return nullptr ;
2012-04-19 14:35:52 +08:00
}
2013-11-14 07:55:36 +08:00
Sprite * Sprite : : createWithTexture ( Texture2D * texture , const Rect & rect , bool rotated )
2012-04-19 14:35:52 +08:00
{
2014-05-06 07:53:37 +08:00
Sprite * sprite = new ( std : : nothrow ) Sprite ( ) ;
if ( sprite & & sprite - > initWithTexture ( texture , rect , rotated ) )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
sprite - > autorelease ( ) ;
return sprite ;
2012-04-19 14:35:52 +08:00
}
2013-07-26 06:53:24 +08:00
CC_SAFE_DELETE ( sprite ) ;
2013-12-18 17:47:20 +08:00
return nullptr ;
2012-04-19 14:35:52 +08:00
}
2013-11-06 11:02:03 +08:00
Sprite * Sprite : : create ( const std : : string & filename )
2012-04-19 14:35:52 +08:00
{
2014-05-06 07:53:37 +08:00
Sprite * sprite = new ( std : : nothrow ) Sprite ( ) ;
if ( sprite & & sprite - > initWithFile ( filename ) )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
sprite - > autorelease ( ) ;
return sprite ;
2012-04-19 14:35:52 +08:00
}
2013-07-26 06:53:24 +08:00
CC_SAFE_DELETE ( sprite ) ;
2013-12-18 17:47:20 +08:00
return nullptr ;
2012-04-19 14:35:52 +08:00
}
2015-06-02 10:10:09 +08:00
Sprite * Sprite : : create ( const PolygonInfo & info )
{
Sprite * sprite = new ( std : : nothrow ) Sprite ( ) ;
if ( sprite & & sprite - > initWithPolygon ( info ) )
{
sprite - > autorelease ( ) ;
return sprite ;
}
CC_SAFE_DELETE ( sprite ) ;
return nullptr ;
}
2013-11-06 11:02:03 +08:00
Sprite * Sprite : : create ( const std : : string & filename , const Rect & rect )
2012-04-19 14:35:52 +08:00
{
2014-05-06 07:53:37 +08:00
Sprite * sprite = new ( std : : nothrow ) Sprite ( ) ;
if ( sprite & & sprite - > initWithFile ( filename , rect ) )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
sprite - > autorelease ( ) ;
return sprite ;
2012-04-19 14:35:52 +08:00
}
2013-07-26 06:53:24 +08:00
CC_SAFE_DELETE ( sprite ) ;
2013-12-18 17:47:20 +08:00
return nullptr ;
2012-04-19 14:35:52 +08:00
}
2013-08-23 08:19:07 +08:00
Sprite * Sprite : : createWithSpriteFrame ( SpriteFrame * spriteFrame )
2012-04-19 14:35:52 +08:00
{
2014-05-06 07:53:37 +08:00
Sprite * sprite = new ( std : : nothrow ) Sprite ( ) ;
if ( sprite & & spriteFrame & & sprite - > initWithSpriteFrame ( spriteFrame ) )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
sprite - > autorelease ( ) ;
return sprite ;
2012-04-19 14:35:52 +08:00
}
2013-07-26 06:53:24 +08:00
CC_SAFE_DELETE ( sprite ) ;
2013-12-18 17:47:20 +08:00
return nullptr ;
2012-04-19 14:35:52 +08:00
}
2013-11-06 11:02:03 +08:00
Sprite * Sprite : : createWithSpriteFrameName ( const std : : string & spriteFrameName )
2012-04-19 14:35:52 +08:00
{
2013-08-23 08:19:07 +08:00
SpriteFrame * frame = SpriteFrameCache : : getInstance ( ) - > getSpriteFrameByName ( spriteFrameName ) ;
2016-11-24 09:59:00 +08:00
2012-09-04 11:16:59 +08:00
# if COCOS2D_DEBUG > 0
2012-04-19 14:35:52 +08:00
char msg [ 256 ] = { 0 } ;
2013-11-06 11:02:03 +08:00
sprintf ( msg , " Invalid spriteFrameName: %s " , spriteFrameName . c_str ( ) ) ;
2013-12-18 17:47:20 +08:00
CCASSERT ( frame ! = nullptr , msg ) ;
2012-09-04 11:16:59 +08:00
# endif
2016-11-24 09:59:00 +08:00
2013-08-23 08:19:07 +08:00
return createWithSpriteFrame ( frame ) ;
2012-04-19 14:35:52 +08:00
}
2013-06-20 14:13:12 +08:00
Sprite * Sprite : : create ( )
2012-04-19 14:35:52 +08:00
{
2014-05-06 07:53:37 +08:00
Sprite * sprite = new ( std : : nothrow ) Sprite ( ) ;
2013-08-23 08:19:07 +08:00
if ( sprite & & sprite - > init ( ) )
2012-04-19 14:35:52 +08:00
{
2013-08-23 08:19:07 +08:00
sprite - > autorelease ( ) ;
return sprite ;
2012-04-19 14:35:52 +08:00
}
2013-08-23 08:19:07 +08:00
CC_SAFE_DELETE ( sprite ) ;
2013-12-18 17:47:20 +08:00
return nullptr ;
2012-04-19 14:35:52 +08:00
}
2015-12-16 11:53:59 +08:00
bool Sprite : : init ( )
2012-04-19 14:35:52 +08:00
{
2015-12-16 11:53:59 +08:00
initWithTexture ( nullptr , Rect : : ZERO ) ;
2016-11-24 09:59:00 +08:00
2015-12-16 11:53:59 +08:00
return true ;
2012-04-19 14:35:52 +08:00
}
2013-07-26 06:53:24 +08:00
bool Sprite : : initWithTexture ( Texture2D * texture )
2012-04-19 14:35:52 +08:00
{
2013-12-18 17:47:20 +08:00
CCASSERT ( texture ! = nullptr , " Invalid texture for sprite " ) ;
2012-04-19 14:35:52 +08:00
2013-07-12 14:47:36 +08:00
Rect rect = Rect : : ZERO ;
2015-12-16 11:53:59 +08:00
if ( texture ) {
rect . size = texture - > getContentSize ( ) ;
}
2013-11-15 07:37:43 +08:00
2015-12-16 11:53:59 +08:00
return initWithTexture ( texture , rect , false ) ;
2012-04-19 14:35:52 +08:00
}
2013-11-15 07:37:43 +08:00
bool Sprite : : initWithTexture ( Texture2D * texture , const Rect & rect )
{
return initWithTexture ( texture , rect , false ) ;
}
2013-11-06 11:02:03 +08:00
bool Sprite : : initWithFile ( const std : : string & filename )
2012-04-19 14:35:52 +08:00
{
2015-11-12 09:49:49 +08:00
if ( filename . empty ( ) )
2015-11-16 11:08:20 +08:00
{
CCLOG ( " Call Sprite::initWithFile with blank resource filename. " ) ;
2015-11-12 09:49:49 +08:00
return false ;
2015-11-16 11:08:20 +08:00
}
2015-11-12 09:49:49 +08:00
_fileName = filename ;
_fileType = 0 ;
2012-04-19 14:35:52 +08:00
2015-12-16 11:53:59 +08:00
Texture2D * texture = _director - > getTextureCache ( ) - > addImage ( filename ) ;
2013-07-26 06:53:24 +08:00
if ( texture )
2012-04-19 14:35:52 +08:00
{
2013-07-12 14:47:36 +08:00
Rect rect = Rect : : ZERO ;
2013-07-26 06:53:24 +08:00
rect . size = texture - > getContentSize ( ) ;
return initWithTexture ( texture , rect ) ;
2012-04-19 14:35:52 +08:00
}
// don't release here.
// when load texture failed, it's better to get a "transparent" sprite then a crashed program
2013-11-15 07:37:43 +08:00
// this->release();
2012-04-19 14:35:52 +08:00
return false ;
}
2013-11-06 11:02:03 +08:00
bool Sprite : : initWithFile ( const std : : string & filename , const Rect & rect )
2012-04-19 14:35:52 +08:00
{
2015-12-16 11:53:59 +08:00
CCASSERT ( ! filename . empty ( ) , " Invalid filename " ) ;
if ( filename . empty ( ) )
{
return false ;
}
2016-11-24 09:59:00 +08:00
2015-11-12 09:49:49 +08:00
_fileName = filename ;
_fileType = 0 ;
2015-12-16 11:53:59 +08:00
Texture2D * texture = _director - > getTextureCache ( ) - > addImage ( filename ) ;
2013-07-26 06:53:24 +08:00
if ( texture )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
return initWithTexture ( texture , rect ) ;
2012-04-19 14:35:52 +08:00
}
// don't release here.
// when load texture failed, it's better to get a "transparent" sprite then a crashed program
2013-11-15 07:37:43 +08:00
// this->release();
2012-04-19 14:35:52 +08:00
return false ;
}
2013-11-15 07:37:43 +08:00
bool Sprite : : initWithSpriteFrameName ( const std : : string & spriteFrameName )
{
2015-12-16 11:53:59 +08:00
CCASSERT ( ! spriteFrameName . empty ( ) , " Invalid spriteFrameName " ) ;
if ( spriteFrameName . empty ( ) )
{
return false ;
}
2016-11-24 09:59:00 +08:00
2015-11-12 09:49:49 +08:00
_fileName = spriteFrameName ;
_fileType = 1 ;
2013-11-15 07:37:43 +08:00
SpriteFrame * frame = SpriteFrameCache : : getInstance ( ) - > getSpriteFrameByName ( spriteFrameName ) ;
return initWithSpriteFrame ( frame ) ;
}
2013-08-23 08:19:07 +08:00
bool Sprite : : initWithSpriteFrame ( SpriteFrame * spriteFrame )
2012-04-19 14:35:52 +08:00
{
2015-07-14 15:28:36 +08:00
CCASSERT ( spriteFrame ! = nullptr , " spriteFrame can't be nullptr! " ) ;
2015-12-16 11:53:59 +08:00
if ( spriteFrame = = nullptr )
{
return false ;
}
2016-11-24 09:59:00 +08:00
2016-11-30 09:26:40 +08:00
bool ret = initWithTexture ( spriteFrame - > getTexture ( ) , spriteFrame - > getRect ( ) , spriteFrame - > isRotated ( ) ) ;
2013-11-15 07:37:43 +08:00
setSpriteFrame ( spriteFrame ) ;
2012-04-19 14:35:52 +08:00
2016-11-30 09:26:40 +08:00
return ret ;
2012-04-19 14:35:52 +08:00
}
2015-06-02 10:10:09 +08:00
bool Sprite : : initWithPolygon ( const cocos2d : : PolygonInfo & info )
{
2015-12-16 11:53:59 +08:00
bool ret = false ;
2016-11-24 09:59:00 +08:00
2016-10-27 09:45:40 +08:00
Texture2D * texture = _director - > getTextureCache ( ) - > addImage ( info . getFilename ( ) ) ;
2015-12-16 11:53:59 +08:00
if ( texture & & initWithTexture ( texture ) )
2015-06-04 15:43:31 +08:00
{
2015-06-04 16:20:00 +08:00
_polyInfo = info ;
2017-01-10 15:28:47 +08:00
_renderMode = RenderMode : : POLYGON ;
2016-10-27 09:45:40 +08:00
Node : : setContentSize ( _polyInfo . getRect ( ) . size / _director - > getContentScaleFactor ( ) ) ;
2015-12-16 11:53:59 +08:00
ret = true ;
2015-06-04 15:43:31 +08:00
}
2016-11-24 09:59:00 +08:00
2015-12-16 11:53:59 +08:00
return ret ;
2015-06-02 10:10:09 +08:00
}
2013-11-15 07:37:43 +08:00
// designated initializer
bool Sprite : : initWithTexture ( Texture2D * texture , const Rect & rect , bool rotated )
2012-04-19 14:35:52 +08:00
{
2015-12-16 11:53:59 +08:00
bool result = false ;
2013-12-06 18:07:16 +08:00
if ( Node : : init ( ) )
2013-11-15 07:37:43 +08:00
{
2013-12-18 17:47:20 +08:00
_batchNode = nullptr ;
2016-11-24 09:59:00 +08:00
2013-11-15 07:37:43 +08:00
_recursiveDirty = false ;
setDirty ( false ) ;
2016-11-24 09:59:00 +08:00
2013-11-15 07:37:43 +08:00
_opacityModifyRGB = true ;
2016-11-24 09:59:00 +08:00
2013-11-15 07:37:43 +08:00
_blendFunc = BlendFunc : : ALPHA_PREMULTIPLIED ;
2016-11-24 09:59:00 +08:00
2013-11-15 07:37:43 +08:00
_flippedX = _flippedY = false ;
2016-11-24 09:59:00 +08:00
2013-11-15 07:37:43 +08:00
// default transform anchor: center
2016-10-27 09:45:40 +08:00
setAnchorPoint ( Vec2 : : ANCHOR_MIDDLE ) ;
2016-11-24 09:59:00 +08:00
2013-11-15 07:37:43 +08:00
// zwoptex default values
2015-04-20 01:40:52 +08:00
_offsetPosition . setZero ( ) ;
2014-01-16 10:37:07 +08:00
2013-11-15 07:37:43 +08:00
// clean the Quad
memset ( & _quad , 0 , sizeof ( _quad ) ) ;
2016-11-24 09:59:00 +08:00
2013-11-15 07:37:43 +08:00
// Atlas: Color
_quad . bl . colors = Color4B : : WHITE ;
_quad . br . colors = Color4B : : WHITE ;
_quad . tl . colors = Color4B : : WHITE ;
_quad . tr . colors = Color4B : : WHITE ;
2014-05-10 09:39:25 +08:00
2013-11-15 07:37:43 +08:00
// update texture (calls updateBlendFunc)
setTexture ( texture ) ;
setTextureRect ( rect , rotated , rect . size ) ;
2016-11-24 09:59:00 +08:00
2013-11-15 07:37:43 +08:00
// by default use "Self Render".
// if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
2013-12-18 17:47:20 +08:00
setBatchNode ( nullptr ) ;
2013-12-23 21:06:37 +08:00
result = true ;
2013-11-15 07:37:43 +08:00
}
2016-11-24 09:59:00 +08:00
2013-12-23 21:06:37 +08:00
_recursiveDirty = true ;
setDirty ( true ) ;
2016-11-24 09:59:00 +08:00
2013-12-23 21:06:37 +08:00
return result ;
2012-04-19 14:35:52 +08:00
}
2013-06-20 14:13:12 +08:00
Sprite : : Sprite ( void )
2014-10-30 22:25:46 +08:00
: _batchNode ( nullptr )
2015-08-05 23:17:38 +08:00
, _textureAtlas ( nullptr )
2014-10-30 22:25:46 +08:00
, _shouldBeHidden ( false )
2013-09-09 16:36:19 +08:00
, _texture ( nullptr )
2014-12-08 21:04:15 +08:00
, _spriteFrame ( nullptr )
2014-03-01 08:10:48 +08:00
, _insideBounds ( true )
2016-10-30 08:52:33 +08:00
, _centerRectNormalized ( 0 , 0 , 1 , 1 )
2017-01-10 15:28:47 +08:00
, _renderMode ( Sprite : : RenderMode : : QUAD )
2017-01-05 09:27:13 +08:00
, _trianglesVertex ( nullptr )
, _trianglesIndex ( nullptr )
2017-01-23 09:25:56 +08:00
, _stretchFactor ( Vec2 : : ONE )
2016-10-27 09:45:40 +08:00
, _originalContentSize ( Size : : ZERO )
2017-01-23 09:25:56 +08:00
, _stretchEnabled ( true )
2012-04-19 14:35:52 +08:00
{
2014-09-11 15:39:56 +08:00
# if CC_SPRITE_DEBUG_DRAW
2015-08-26 18:14:25 +08:00
_debugDrawNode = DrawNode : : create ( ) ;
addChild ( _debugDrawNode ) ;
2014-09-11 15:39:56 +08:00
# endif //CC_SPRITE_DEBUG_DRAW
2012-04-19 14:35:52 +08:00
}
2015-12-24 00:54:00 +08:00
Sprite : : ~ Sprite ( )
2012-04-19 14:35:52 +08:00
{
2017-01-05 09:27:13 +08:00
CC_SAFE_FREE ( _trianglesVertex ) ;
CC_SAFE_FREE ( _trianglesIndex ) ;
2014-12-08 21:04:15 +08:00
CC_SAFE_RELEASE ( _spriteFrame ) ;
2013-06-15 14:03:30 +08:00
CC_SAFE_RELEASE ( _texture ) ;
2012-04-19 14:35:52 +08:00
}
2013-11-15 07:37:43 +08:00
/*
* Texture methods
*/
/*
* This array is the data of a white image with 2 by 2 dimension .
2013-12-18 17:47:20 +08:00
* It ' s used for creating a default texture when sprite ' s texture is set to nullptr .
2013-11-15 07:37:43 +08:00
* Supposing codes as follows :
*
2014-08-28 07:31:57 +08:00
* auto sp = new ( std : : nothrow ) Sprite ( ) ;
2013-12-18 17:47:20 +08:00
* sp - > init ( ) ; // Texture was set to nullptr, in order to make opacity and color to work correctly, we need to create a 2x2 white texture.
2013-11-15 07:37:43 +08:00
*
* The test is in " TestCpp/SpriteTest/Sprite without texture " .
*/
static unsigned char cc_2x2_white_image [ ] = {
// RGBA8888
0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF
} ;
# define CC_2x2_WHITE_IMAGE_KEY " / cc_2x2_white_image"
2013-11-14 07:55:36 +08:00
2014-08-30 03:54:24 +08:00
// MARK: texture
2013-11-14 07:55:36 +08:00
void Sprite : : setTexture ( const std : : string & filename )
{
Texture2D * texture = Director : : getInstance ( ) - > getTextureCache ( ) - > addImage ( filename ) ;
setTexture ( texture ) ;
2015-12-03 14:21:00 +08:00
_unflippedOffsetPositionFromCenter = Vec2 : : ZERO ;
2013-11-15 07:37:43 +08:00
Rect rect = Rect : : ZERO ;
2014-11-27 21:15:09 +08:00
if ( texture )
rect . size = texture - > getContentSize ( ) ;
2013-11-15 07:37:43 +08:00
setTextureRect ( rect ) ;
}
void Sprite : : setTexture ( Texture2D * texture )
{
2016-07-31 22:30:03 +08:00
setGLProgramState ( GLProgramState : : getOrCreateWithGLProgramName ( GLProgram : : SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP , texture ) ) ;
2016-07-25 17:31:54 +08:00
2013-11-15 07:37:43 +08:00
// If batchnode, then texture id should be the same
2015-07-09 09:58:14 +08:00
CCASSERT ( ! _batchNode | | ( texture & & texture - > getName ( ) = = _batchNode - > getTexture ( ) - > getName ( ) ) , " CCSprite: Batched sprites should use the same texture as the batchnode " ) ;
2013-11-15 07:37:43 +08:00
// accept texture==nil as argument
CCASSERT ( ! texture | | dynamic_cast < Texture2D * > ( texture ) , " setTexture expects a Texture2D. Invalid argument " ) ;
if ( texture = = nullptr )
{
// Gets the texture by key firstly.
2015-12-16 11:53:59 +08:00
texture = _director - > getTextureCache ( ) - > getTextureForKey ( CC_2x2_WHITE_IMAGE_KEY ) ;
2013-11-15 07:37:43 +08:00
// If texture wasn't in cache, create it from RAW data.
if ( texture = = nullptr )
{
2014-08-28 07:31:57 +08:00
Image * image = new ( std : : nothrow ) Image ( ) ;
2016-11-16 09:48:37 +08:00
bool CC_UNUSED isOK = image - > initWithRawData ( cc_2x2_white_image , sizeof ( cc_2x2_white_image ) , 2 , 2 , 8 ) ;
2013-11-15 07:37:43 +08:00
CCASSERT ( isOK , " The 2x2 empty texture was created unsuccessfully. " ) ;
2015-12-16 11:53:59 +08:00
texture = _director - > getTextureCache ( ) - > addImage ( image , CC_2x2_WHITE_IMAGE_KEY ) ;
2013-11-15 07:37:43 +08:00
CC_SAFE_RELEASE ( image ) ;
}
}
2017-01-11 21:33:41 +08:00
if ( ( _renderMode ! = RenderMode : : QUAD_BATCHNODE ) & & ( _texture ! = texture ) )
2013-11-15 07:37:43 +08:00
{
CC_SAFE_RETAIN ( texture ) ;
CC_SAFE_RELEASE ( _texture ) ;
_texture = texture ;
updateBlendFunc ( ) ;
}
}
Texture2D * Sprite : : getTexture ( ) const
{
return _texture ;
2013-11-14 07:55:36 +08:00
}
2013-06-20 14:13:12 +08:00
void Sprite : : setTextureRect ( const Rect & rect )
2012-04-19 14:35:52 +08:00
{
setTextureRect ( rect , false , rect . size ) ;
}
2013-06-20 14:13:12 +08:00
void Sprite : : setTextureRect ( const Rect & rect , bool rotated , const Size & untrimmedSize )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
_rectRotated = rotated ;
2012-04-19 14:35:52 +08:00
2016-10-27 09:45:40 +08:00
Node : : setContentSize ( untrimmedSize ) ;
_originalContentSize = untrimmedSize ;
2012-04-19 14:35:52 +08:00
2016-10-27 09:45:40 +08:00
setVertexRect ( rect ) ;
updateStretchFactor ( ) ;
updatePoly ( ) ;
}
2012-04-19 14:35:52 +08:00
2016-10-27 09:45:40 +08:00
void Sprite : : updatePoly ( )
{
2016-11-24 09:59:00 +08:00
// There are 3 cases:
//
2017-01-11 09:31:45 +08:00
// A) a non 9-sliced, non stretched
// contentsize doesn't not affect the stretching, since there is no stretching
2016-11-24 09:59:00 +08:00
// this was the original behavior, and we keep it for backwards compatibility reasons
2017-01-11 09:31:45 +08:00
// When non-stretching is enabled, we have to change the offset in order to "fill the empty" space at the
2016-11-24 09:59:00 +08:00
// left-top of the texture
2017-01-11 09:31:45 +08:00
// B) non 9-sliced, stretched
// the texture is stretched to the content size
// C) 9-sliced, stretched
// the sprite is 9-sliced and stretched.
2017-01-11 21:33:41 +08:00
if ( _renderMode = = RenderMode : : QUAD | | _renderMode = = RenderMode : : QUAD_BATCHNODE ) {
2016-11-24 09:59:00 +08:00
Rect copyRect ;
2017-01-23 09:25:56 +08:00
if ( _stretchEnabled ) {
2016-11-24 09:59:00 +08:00
// case B)
2017-01-23 09:25:56 +08:00
copyRect = Rect ( 0 , 0 , _rect . size . width * _stretchFactor . x , _rect . size . height * _stretchFactor . y ) ;
2016-11-24 09:59:00 +08:00
} else {
// case A)
// modify origin to put the sprite in the correct offset
copyRect = Rect ( ( _contentSize . width - _originalContentSize . width ) / 2.0f ,
( _contentSize . height - _originalContentSize . height ) / 2.0f ,
_rect . size . width ,
_rect . size . height ) ;
}
2017-01-05 09:27:13 +08:00
setTextureCoords ( _rect , & _quad ) ;
2016-11-24 09:59:00 +08:00
setVertexCoords ( copyRect , & _quad ) ;
2016-10-27 09:45:40 +08:00
_polyInfo . setQuad ( & _quad ) ;
2017-01-10 15:28:47 +08:00
} else if ( _renderMode = = RenderMode : : SLICE9 ) {
// case C)
2016-11-24 09:59:00 +08:00
// How the texture is split
//
// u,v: are the texture coordinates
// w,h: are the width and heights
//
// w0 w1 w2
// v2 +----+------+--+
// | | | |
// | | | |
// | 6 | 7 | 8| h2
// | | | |
// v1 +----+------+--|
// | | | |
// | 3 | 4 | 5| h1
// v0 +----+------+--|
// | | | |
// | 0 | 1 | 2| h0
// | | | |
// +----+------+--+
// u0 u1 u2
//
//
// and when the texture is rotated, it will get transformed.
// not only the rects have a different position, but also u,v
// points to the bottom-left and not top-right of the texture
// so some swaping/origin/reordering needs to be done in order
// to support rotated slice-9 correctly
//
// w0 w1 w2
// v2 +------+----+--------+
// | | | |
// | 0 | 3 | 6 | h2
// v1 +------+----+--------+
// | | | |
// | 1 | 4 | 7 | h1
// | | | |
// v0 +------+----+--------+
// | 2 | 5 | 8 | h0
// +------+----+--------+
// u0 u1 u2
2016-10-27 09:45:40 +08:00
// center rect
2016-11-24 09:59:00 +08:00
float cx1 = _centerRectNormalized . origin . x ;
float cy1 = _centerRectNormalized . origin . y ;
float cx2 = _centerRectNormalized . origin . x + _centerRectNormalized . size . width ;
float cy2 = _centerRectNormalized . origin . y + _centerRectNormalized . size . height ;
2016-10-27 09:45:40 +08:00
// "O"riginal rect
const float oox = _rect . origin . x ;
const float ooy = _rect . origin . y ;
2016-11-24 15:35:57 +08:00
float osw = _rect . size . width ;
float osh = _rect . size . height ;
2016-10-27 09:45:40 +08:00
2016-11-24 09:59:00 +08:00
if ( _rectRotated ) {
std : : swap ( cx1 , cy1 ) ;
std : : swap ( cx2 , cy2 ) ;
// when the texture is rotated, then the centerRect starts from the "bottom" (left)
// but when it is not rotated, it starts from the top, so invert it
cy2 = 1 - cy2 ;
cy1 = 1 - cy1 ;
std : : swap ( cy1 , cy2 ) ;
2016-11-24 15:35:57 +08:00
std : : swap ( osw , osh ) ;
2016-11-24 09:59:00 +08:00
}
//
2016-10-27 09:45:40 +08:00
// textCoords Data: Y must be inverted.
2016-11-24 09:59:00 +08:00
//
const float w0 = osw * cx1 ;
const float w1 = osw * ( cx2 - cx1 ) ;
const float w2 = osw * ( 1 - cx2 ) ;
const float h0 = osh * cy1 ;
const float h1 = osh * ( cy2 - cy1 ) ;
const float h2 = osh * ( 1 - cy2 ) ;
2016-11-25 09:27:20 +08:00
const float u0 = oox ;
const float u1 = u0 + w0 ;
const float u2 = u1 + w1 ;
const float v2 = ooy ;
const float v1 = v2 + h2 ;
const float v0 = v1 + h1 ;
2016-11-24 09:59:00 +08:00
const Rect texRects_normal [ 9 ] = {
Rect ( u0 , v0 , w0 , h0 ) , // bottom-left
Rect ( u1 , v0 , w1 , h0 ) , // bottom
Rect ( u2 , v0 , w2 , h0 ) , // bottom-right
Rect ( u0 , v1 , w0 , h1 ) , // left
Rect ( u1 , v1 , w1 , h1 ) , // center
Rect ( u2 , v1 , w2 , h1 ) , // right
Rect ( u0 , v2 , w0 , h2 ) , // top-left
Rect ( u1 , v2 , w1 , h2 ) , // top
Rect ( u2 , v2 , w2 , h2 ) , // top-right
} ;
// swap width and height because setTextureCoords()
// will expects the hight and width to be swapped
const Rect texRects_rotated [ 9 ] = {
Rect ( u0 , v2 , h2 , w0 ) , // top-left
Rect ( u0 , v1 , h1 , w0 ) , // left
Rect ( u0 , v0 , h0 , w0 ) , // bottom-left
2016-10-27 09:45:40 +08:00
2016-11-24 09:59:00 +08:00
Rect ( u1 , v2 , h2 , w1 ) , // top
Rect ( u1 , v1 , h1 , w1 ) , // center
Rect ( u1 , v0 , h0 , w1 ) , // bottom
2016-10-27 09:45:40 +08:00
2016-11-24 09:59:00 +08:00
Rect ( u2 , v2 , h2 , w2 ) , // top-right
Rect ( u2 , v1 , h1 , w2 ) , // right
Rect ( u2 , v0 , h0 , w2 ) , // bottom-right
2016-10-27 09:45:40 +08:00
} ;
2016-11-24 09:59:00 +08:00
const Rect * texRects = _rectRotated ? texRects_rotated : texRects_normal ;
//
2016-10-27 09:45:40 +08:00
// vertex Data.
2016-11-24 09:59:00 +08:00
//
// reset center rect since it is altered when when the texture
// is rotated
cx1 = _centerRectNormalized . origin . x ;
cy1 = _centerRectNormalized . origin . y ;
cx2 = _centerRectNormalized . origin . x + _centerRectNormalized . size . width ;
cy2 = _centerRectNormalized . origin . y + _centerRectNormalized . size . height ;
2016-11-24 15:35:57 +08:00
if ( _rectRotated )
std : : swap ( osw , osh ) ;
2016-10-30 08:52:33 +08:00
// sizes
float x0_s = osw * cx1 ;
2017-01-23 09:25:56 +08:00
float x1_s = osw * ( cx2 - cx1 ) * _stretchFactor . x ;
2016-10-30 08:52:33 +08:00
float x2_s = osw * ( 1 - cx2 ) ;
float y0_s = osh * cy1 ;
2017-01-23 09:25:56 +08:00
float y1_s = osh * ( cy2 - cy1 ) * _stretchFactor . y ;
2016-10-30 08:52:33 +08:00
float y2_s = osh * ( 1 - cy2 ) ;
2016-12-03 23:35:22 +08:00
// avoid negative size:
if ( _contentSize . width < x0_s + x2_s ) {
x2_s = x0_s = _contentSize . width / 2 ;
}
if ( _contentSize . height < y0_s + y2_s ) {
y2_s = y0_s = _contentSize . height / 2 ;
}
2016-11-24 09:59:00 +08:00
// is it flipped?
2016-10-30 08:52:33 +08:00
// swap sizes to calculate offset correctly
if ( _flippedX )
std : : swap ( x0_s , x2_s ) ;
if ( _flippedY )
std : : swap ( y0_s , y2_s ) ;
// origins
float x0 = 0 ;
float x1 = x0 + x0_s ;
float x2 = x1 + x1_s ;
float y0 = 0 ;
float y1 = y0 + y0_s ;
float y2 = y1 + y1_s ;
// swap origin, but restore size to its original value
if ( _flippedX ) {
std : : swap ( x0 , x2 ) ;
std : : swap ( x0_s , x2_s ) ;
}
if ( _flippedY ) {
std : : swap ( y0 , y2 ) ;
std : : swap ( y0_s , y2_s ) ;
}
2016-10-27 09:45:40 +08:00
const Rect verticesRects [ 9 ] = {
2016-10-30 08:52:33 +08:00
Rect ( x0 , y0 , x0_s , y0_s ) , // bottom-left
Rect ( x1 , y0 , x1_s , y0_s ) , // bottom
Rect ( x2 , y0 , x2_s , y0_s ) , // bottom-right
Rect ( x0 , y1 , x0_s , y1_s ) , // left
Rect ( x1 , y1 , x1_s , y1_s ) , // center
Rect ( x2 , y1 , x2_s , y1_s ) , // right
2016-10-27 09:45:40 +08:00
2016-10-30 08:52:33 +08:00
Rect ( x0 , y2 , x0_s , y2_s ) , // top-left
Rect ( x1 , y2 , x1_s , y2_s ) , // top
Rect ( x2 , y2 , x2_s , y2_s ) , // top-right
} ;
2016-10-27 09:45:40 +08:00
2017-01-05 09:27:13 +08:00
// needed in order to get color from "_quad"
V3F_C4B_T2F_Quad tmpQuad = _quad ;
2017-01-10 15:28:47 +08:00
for ( int i = 0 ; i < 9 ; + + i ) {
2017-01-05 09:27:13 +08:00
setTextureCoords ( texRects [ i ] , & tmpQuad ) ;
setVertexCoords ( verticesRects [ i ] , & tmpQuad ) ;
populateTriangle ( i , tmpQuad ) ;
2016-10-27 09:45:40 +08:00
}
2017-01-05 09:27:13 +08:00
TrianglesCommand : : Triangles triangles ;
triangles . verts = _trianglesVertex ;
triangles . vertCount = 16 ;
triangles . indices = _trianglesIndex ;
triangles . indexCount = 6 * 9 ; // 9 quads, each needs 6 vertices
// probably we can update the _trianglesCommand directly
// to avoid memcpy'ing stuff
_polyInfo . setTriangles ( triangles ) ;
2012-04-19 14:35:52 +08:00
}
2016-10-27 09:45:40 +08:00
}
2012-04-19 14:35:52 +08:00
2016-10-30 08:52:33 +08:00
void Sprite : : setCenterRectNormalized ( const cocos2d : : Rect & rectTopLeft )
2016-10-27 09:45:40 +08:00
{
2017-01-16 09:30:08 +08:00
if ( _renderMode ! = RenderMode : : QUAD & & _renderMode ! = RenderMode : : SLICE9 ) {
CCLOGWARN ( " Warning: Sprite::setCenterRectNormalized() only works with QUAD and SLICE9 render modes " ) ;
return ;
}
2017-01-10 15:28:47 +08:00
2016-10-27 09:45:40 +08:00
// FIMXE: Rect is has origin on top-left (like text coordinate).
// but all the logic has been done using bottom-left as origin. So it is easier to invert Y
// here, than in the rest of the places... but it is not as clean.
Rect rect ( rectTopLeft . origin . x , 1 - rectTopLeft . origin . y - rectTopLeft . size . height , rectTopLeft . size . width , rectTopLeft . size . height ) ;
2016-10-30 08:52:33 +08:00
if ( ! _centerRectNormalized . equals ( rect ) ) {
_centerRectNormalized = rect ;
2012-04-19 14:35:52 +08:00
2017-01-10 15:28:47 +08:00
// convert it to 1-slice when the centerRect is not present.
2016-10-27 09:45:40 +08:00
if ( rect . equals ( Rect ( 0 , 0 , 1 , 1 ) ) ) {
2017-01-10 15:28:47 +08:00
_renderMode = RenderMode : : QUAD ;
2017-01-05 09:27:13 +08:00
free ( _trianglesVertex ) ;
free ( _trianglesIndex ) ;
_trianglesVertex = nullptr ;
_trianglesIndex = nullptr ;
2016-10-27 09:45:40 +08:00
}
else
{
// convert it to 9-slice if it isn't already
2017-01-10 15:28:47 +08:00
if ( _renderMode ! = RenderMode : : SLICE9 ) {
_renderMode = RenderMode : : SLICE9 ;
2017-01-05 09:27:13 +08:00
// 9 quads + 7 exterior points = 16
_trianglesVertex = ( V3F_C4B_T2F * ) malloc ( sizeof ( * _trianglesVertex ) * ( 9 + 3 + 4 ) ) ;
// 9 quads, each needs 6 vertices = 54
_trianglesIndex = ( unsigned short * ) malloc ( sizeof ( * _trianglesIndex ) * 6 * 9 ) ;
2016-10-27 09:45:40 +08:00
2017-01-05 09:27:13 +08:00
// populate indices in CCW direction
2016-10-27 09:45:40 +08:00
for ( int i = 0 ; i < 9 ; + + i ) {
2017-01-05 09:27:13 +08:00
_trianglesIndex [ i * 6 + 0 ] = ( i * 4 / 3 ) + 4 ;
_trianglesIndex [ i * 6 + 1 ] = ( i * 4 / 3 ) + 0 ;
_trianglesIndex [ i * 6 + 2 ] = ( i * 4 / 3 ) + 5 ;
_trianglesIndex [ i * 6 + 3 ] = ( i * 4 / 3 ) + 1 ;
_trianglesIndex [ i * 6 + 4 ] = ( i * 4 / 3 ) + 5 ;
_trianglesIndex [ i * 6 + 5 ] = ( i * 4 / 3 ) + 0 ;
2016-10-27 09:45:40 +08:00
}
}
}
updateStretchFactor ( ) ;
updatePoly ( ) ;
2016-12-21 16:17:32 +08:00
updateColor ( ) ;
2012-04-19 14:35:52 +08:00
}
2016-10-27 09:45:40 +08:00
}
2012-04-19 14:35:52 +08:00
2016-10-30 08:52:33 +08:00
void Sprite : : setCenterRect ( const cocos2d : : Rect & rectInPoints )
2016-10-27 09:45:40 +08:00
{
2017-01-16 09:30:08 +08:00
if ( _renderMode ! = RenderMode : : QUAD & & _renderMode ! = RenderMode : : SLICE9 ) {
CCLOGWARN ( " Warning: Sprite::setCenterRect() only works with QUAD and SLICE9 render modes " ) ;
return ;
}
2017-01-10 15:28:47 +08:00
2016-10-27 09:45:40 +08:00
if ( ! _originalContentSize . equals ( Size : : ZERO ) )
{
Rect rect = rectInPoints ;
2016-11-24 09:59:00 +08:00
2016-10-27 09:45:40 +08:00
const float x = rect . origin . x / _rect . size . width ;
const float y = rect . origin . y / _rect . size . height ;
const float w = rect . size . width / _rect . size . width ;
const float h = rect . size . height / _rect . size . height ;
2016-10-30 08:52:33 +08:00
setCenterRectNormalized ( Rect ( x , y , w , h ) ) ;
2012-04-19 14:35:52 +08:00
}
2016-10-27 09:45:40 +08:00
}
2016-10-30 08:52:33 +08:00
Rect Sprite : : getCenterRectNormalized ( ) const
2016-10-27 09:45:40 +08:00
{
2016-10-30 08:52:33 +08:00
// FIXME: _centerRectNormalized is in bottom-left coords, but should converted to top-left
Rect ret ( _centerRectNormalized . origin . x ,
1 - _centerRectNormalized . origin . y - _centerRectNormalized . size . height ,
_centerRectNormalized . size . width ,
_centerRectNormalized . size . height ) ;
2016-10-27 09:45:40 +08:00
return ret ;
}
2016-10-30 08:52:33 +08:00
Rect Sprite : : getCenterRect ( ) const
2016-10-27 09:45:40 +08:00
{
2016-10-30 08:52:33 +08:00
Rect rect = getCenterRectNormalized ( ) ;
2016-10-27 09:45:40 +08:00
rect . origin . x * = _rect . size . width ;
rect . origin . y * = _rect . size . height ;
rect . size . width * = _rect . size . width ;
rect . size . height * = _rect . size . height ;
return rect ;
2012-04-19 14:35:52 +08:00
}
// override this method to generate "double scale" sprites
2013-06-20 14:13:12 +08:00
void Sprite : : setVertexRect ( const Rect & rect )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
_rect = rect ;
2012-04-19 14:35:52 +08:00
}
2016-10-27 09:45:40 +08:00
void Sprite : : setTextureCoords ( const Rect & rectInPoints )
{
setTextureCoords ( rectInPoints , & _quad ) ;
}
void Sprite : : setTextureCoords ( const Rect & rectInPoints , V3F_C4B_T2F_Quad * outQuad )
2012-04-19 14:35:52 +08:00
{
2017-01-11 21:33:41 +08:00
Texture2D * tex = ( _renderMode = = RenderMode : : QUAD_BATCHNODE ) ? _textureAtlas - > getTexture ( ) : _texture ;
2015-12-16 11:53:59 +08:00
if ( tex = = nullptr )
2012-04-19 14:35:52 +08:00
{
return ;
}
2016-10-27 09:45:40 +08:00
2016-11-24 09:59:00 +08:00
const auto rectInPixels = CC_RECT_POINTS_TO_PIXELS ( rectInPoints ) ;
const float atlasWidth = ( float ) tex - > getPixelsWide ( ) ;
const float atlasHeight = ( float ) tex - > getPixelsHigh ( ) ;
2012-04-19 14:35:52 +08:00
2016-11-24 09:59:00 +08:00
float rw = rectInPixels . size . width ;
float rh = rectInPixels . size . height ;
2012-04-19 14:35:52 +08:00
2016-11-24 09:59:00 +08:00
// if the rect is rotated, it means that the frame is rotated 90 degrees (clockwise) and:
// - rectInpoints: origin will be the bottom-left of the frame (and not the top-right)
// - size: represents the unrotated texture size
//
// so what we have to do is:
// - swap texture width and height
// - take into account the origin
// - flip X instead of Y when flipY is enabled
// - flip Y instead of X when flipX is enabled
2012-04-19 14:35:52 +08:00
2013-06-15 14:03:30 +08:00
if ( _rectRotated )
2016-11-24 09:59:00 +08:00
std : : swap ( rw , rh ) ;
2012-04-19 14:35:52 +08:00
# if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
2016-11-24 09:59:00 +08:00
float left = ( 2 * rectInPixels . origin . x + 1 ) / ( 2 * atlasWidth ) ;
float right = left + ( rw * 2 - 2 ) / ( 2 * atlasWidth ) ;
float top = ( 2 * rectInPixels . origin . y + 1 ) / ( 2 * atlasHeight ) ;
float bottom = top + ( rh * 2 - 2 ) / ( 2 * atlasHeight ) ;
2012-04-19 14:35:52 +08:00
# else
2016-11-24 09:59:00 +08:00
float left = rectInPixels . origin . x / atlasWidth ;
float right = ( rectInPixels . origin . x + rw ) / atlasWidth ;
float top = rectInPixels . origin . y / atlasHeight ;
float bottom = ( rectInPixels . origin . y + rh ) / atlasHeight ;
2012-04-19 14:35:52 +08:00
# endif // CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
2017-01-05 09:27:13 +08:00
if ( ( ! _rectRotated & & _flippedX ) | | ( _rectRotated & & _flippedY ) )
2016-11-24 09:59:00 +08:00
{
std : : swap ( left , right ) ;
}
2012-04-19 14:35:52 +08:00
2017-01-05 09:27:13 +08:00
if ( ( ! _rectRotated & & _flippedY ) | | ( _rectRotated & & _flippedX ) )
2016-11-24 09:59:00 +08:00
{
std : : swap ( top , bottom ) ;
}
if ( _rectRotated )
{
2016-10-27 09:45:40 +08:00
outQuad - > bl . texCoords . u = left ;
outQuad - > bl . texCoords . v = top ;
outQuad - > br . texCoords . u = left ;
outQuad - > br . texCoords . v = bottom ;
outQuad - > tl . texCoords . u = right ;
outQuad - > tl . texCoords . v = top ;
outQuad - > tr . texCoords . u = right ;
outQuad - > tr . texCoords . v = bottom ;
2012-04-19 14:35:52 +08:00
}
else
{
2016-10-27 09:45:40 +08:00
outQuad - > bl . texCoords . u = left ;
outQuad - > bl . texCoords . v = bottom ;
outQuad - > br . texCoords . u = right ;
outQuad - > br . texCoords . v = bottom ;
outQuad - > tl . texCoords . u = left ;
outQuad - > tl . texCoords . v = top ;
outQuad - > tr . texCoords . u = right ;
outQuad - > tr . texCoords . v = top ;
2012-04-19 14:35:52 +08:00
}
}
2016-11-24 09:59:00 +08:00
void Sprite : : setVertexCoords ( const Rect & rect , V3F_C4B_T2F_Quad * outQuad )
2016-10-27 09:45:40 +08:00
{
float relativeOffsetX = _unflippedOffsetPositionFromCenter . x ;
float relativeOffsetY = _unflippedOffsetPositionFromCenter . y ;
// issue #732
if ( _flippedX )
{
relativeOffsetX = - relativeOffsetX ;
}
if ( _flippedY )
{
relativeOffsetY = - relativeOffsetY ;
}
2016-11-24 09:59:00 +08:00
_offsetPosition . x = relativeOffsetX + ( _originalContentSize . width - _rect . size . width ) / 2 ;
_offsetPosition . y = relativeOffsetY + ( _originalContentSize . height - _rect . size . height ) / 2 ;
2017-01-18 15:41:18 +08:00
// FIXME: Stretching should be applied to the "offset" as well
2016-11-24 09:59:00 +08:00
// but probably it should be calculated in the caller function. It will be tidier
2017-01-10 15:28:47 +08:00
if ( _renderMode = = RenderMode : : QUAD ) {
2017-01-23 09:25:56 +08:00
_offsetPosition . x * = _stretchFactor . x ;
_offsetPosition . y * = _stretchFactor . y ;
2016-11-24 09:59:00 +08:00
}
2016-10-27 09:45:40 +08:00
// rendering using batch node
2017-01-11 21:33:41 +08:00
if ( _renderMode = = RenderMode : : QUAD_BATCHNODE )
2016-10-27 09:45:40 +08:00
{
// update dirty_, don't update recursiveDirty_
setDirty ( true ) ;
}
else
{
// self rendering
// Atlas: Vertex
const float x1 = 0.0f + _offsetPosition . x + rect . origin . x ;
const float y1 = 0.0f + _offsetPosition . y + rect . origin . y ;
const float x2 = x1 + rect . size . width ;
const float y2 = y1 + rect . size . height ;
// Don't update Z.
outQuad - > bl . vertices . set ( x1 , y1 , 0.0f ) ;
outQuad - > br . vertices . set ( x2 , y1 , 0.0f ) ;
outQuad - > tl . vertices . set ( x1 , y2 , 0.0f ) ;
outQuad - > tr . vertices . set ( x2 , y2 , 0.0f ) ;
}
}
2017-01-05 09:27:13 +08:00
void Sprite : : populateTriangle ( int quadIndex , const V3F_C4B_T2F_Quad & quad )
{
CCASSERT ( quadIndex < 9 , " Invalid quadIndex " ) ;
// convert Quad intro Triangle since it takes less memory
// Triangles are ordered like the following:
// Numbers: Quad Index
// Letters: triangles' vertices
//
// M-----N-----O-----P
// | | | |
// | 6 | 7 | 8 |
// | | | |
// I-----J-----K-----L
// | | | |
// | 3 | 4 | 5 |
// | | | |
// E-----F-----G-----H
// | | | |
// | 0 | 1 | 2 |
// | | | |
// A-----B-----C-----D
//
// So, if QuadIndex == 4, then it should update vertices J,K,F,G
// Optimization: I don't need to copy all the vertices all the time. just the 4 "quads" from the corners.
if ( quadIndex = = 0 | | quadIndex = = 2 | | quadIndex = = 6 | | quadIndex = = 8 )
{
if ( _flippedX ) {
if ( quadIndex % 3 = = 0 )
quadIndex + = 2 ;
else
quadIndex - = 2 ;
}
if ( _flippedY ) {
if ( quadIndex < = 2 )
quadIndex + = 6 ;
else
quadIndex - = 6 ;
}
const int index_bl = quadIndex * 4 / 3 ;
const int index_br = index_bl + 1 ;
const int index_tl = index_bl + 4 ;
const int index_tr = index_bl + 5 ;
_trianglesVertex [ index_tr ] = quad . tr ;
_trianglesVertex [ index_br ] = quad . br ;
_trianglesVertex [ index_tl ] = quad . tl ;
_trianglesVertex [ index_bl ] = quad . bl ;
}
}
2016-10-27 09:45:40 +08:00
2014-08-30 03:54:24 +08:00
// MARK: visit, draw, transform
2013-06-20 14:13:12 +08:00
void Sprite : : updateTransform ( void )
2012-04-19 14:35:52 +08:00
{
2017-01-11 21:33:41 +08:00
CCASSERT ( _renderMode = = RenderMode : : QUAD_BATCHNODE , " updateTransform is only valid when Sprite is being rendered using an SpriteBatchNode " ) ;
2014-02-10 11:39:56 +08:00
2012-09-17 15:02:24 +08:00
// recalculate matrix only if it is dirty
2012-04-19 14:35:52 +08:00
if ( isDirty ( ) ) {
// If it is not visible, or one of its ancestors is not visible, then do nothing:
2013-08-23 08:19:07 +08:00
if ( ! _visible | | ( _parent & & _parent ! = _batchNode & & static_cast < Sprite * > ( _parent ) - > _shouldBeHidden ) )
2012-04-19 14:35:52 +08:00
{
Optimize Vec3
small function Vec3 move to Vec3.inl
Added:
add(float xx, float yy, float zz);
setZero();
Change all code:
_vec3 = Vec3(x, y, z); -> _vec3.set(x, y, z);
Vec3 vec3 = Vec3(x, y, z); -> Vec3 vec3(x, y, z);
_vec3 += Vec3(x, y, z); -> _vec3.add(x, y, z);
_vec3 = Vec3::ZERO; -> _vec3.setZero();
2015-04-05 18:09:50 +08:00
_quad . br . vertices . setZero ( ) ;
_quad . tl . vertices . setZero ( ) ;
_quad . tr . vertices . setZero ( ) ;
_quad . bl . vertices . setZero ( ) ;
2013-06-15 14:03:30 +08:00
_shouldBeHidden = true ;
2012-04-19 14:35:52 +08:00
}
2013-11-26 08:33:05 +08:00
else
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
_shouldBeHidden = false ;
2012-04-19 14:35:52 +08:00
2013-06-15 14:03:30 +08:00
if ( ! _parent | | _parent = = _batchNode )
2012-04-19 14:35:52 +08:00
{
2013-07-17 09:16:04 +08:00
_transformToBatch = getNodeToParentTransform ( ) ;
2012-04-19 14:35:52 +08:00
}
2013-11-27 03:48:37 +08:00
else
2012-04-19 14:35:52 +08:00
{
2013-07-20 13:01:27 +08:00
CCASSERT ( dynamic_cast < Sprite * > ( _parent ) , " Logic error in Sprite. Parent must be a Sprite " ) ;
2014-06-24 14:31:55 +08:00
const Mat4 & nodeToParent = getNodeToParentTransform ( ) ;
Mat4 & parentTransform = static_cast < Sprite * > ( _parent ) - > _transformToBatch ;
2014-04-09 11:28:34 +08:00
_transformToBatch = parentTransform * nodeToParent ;
2012-04-19 14:35:52 +08:00
}
//
// calculate the Quad based on the Affine Matrix
//
2014-06-24 18:23:10 +08:00
Size & size = _rect . size ;
2012-04-19 14:35:52 +08:00
2013-06-15 14:03:30 +08:00
float x1 = _offsetPosition . x ;
float y1 = _offsetPosition . y ;
2012-04-19 14:35:52 +08:00
float x2 = x1 + size . width ;
float y2 = y1 + size . height ;
2016-11-24 09:59:00 +08:00
2014-04-09 11:28:34 +08:00
float x = _transformToBatch . m [ 12 ] ;
float y = _transformToBatch . m [ 13 ] ;
2012-04-19 14:35:52 +08:00
2014-04-09 11:28:34 +08:00
float cr = _transformToBatch . m [ 0 ] ;
float sr = _transformToBatch . m [ 1 ] ;
float cr2 = _transformToBatch . m [ 5 ] ;
float sr2 = - _transformToBatch . m [ 4 ] ;
2012-04-19 14:35:52 +08:00
float ax = x1 * cr - y1 * sr2 + x ;
float ay = x1 * sr + y1 * cr2 + y ;
float bx = x2 * cr - y1 * sr2 + x ;
float by = x2 * sr + y1 * cr2 + y ;
float cx = x2 * cr - y2 * sr2 + x ;
float cy = x2 * sr + y2 * cr2 + y ;
float dx = x1 * cr - y2 * sr2 + x ;
float dy = x1 * sr + y2 * cr2 + y ;
2015-07-08 15:30:34 +08:00
_quad . bl . vertices . set ( SPRITE_RENDER_IN_SUBPIXEL ( ax ) , SPRITE_RENDER_IN_SUBPIXEL ( ay ) , _positionZ ) ;
_quad . br . vertices . set ( SPRITE_RENDER_IN_SUBPIXEL ( bx ) , SPRITE_RENDER_IN_SUBPIXEL ( by ) , _positionZ ) ;
_quad . tl . vertices . set ( SPRITE_RENDER_IN_SUBPIXEL ( dx ) , SPRITE_RENDER_IN_SUBPIXEL ( dy ) , _positionZ ) ;
_quad . tr . vertices . set ( SPRITE_RENDER_IN_SUBPIXEL ( cx ) , SPRITE_RENDER_IN_SUBPIXEL ( cy ) , _positionZ ) ;
2015-12-14 15:35:26 +08:00
setTextureCoords ( _rect ) ;
2012-04-19 14:35:52 +08:00
}
2013-12-18 17:47:20 +08:00
// MARMALADE CHANGE: ADDED CHECK FOR nullptr, TO PERMIT SPRITES WITH NO BATCH NODE / TEXTURE ATLAS
2013-06-15 14:03:30 +08:00
if ( _textureAtlas )
2015-01-08 10:22:45 +08:00
{
2013-06-15 14:03:30 +08:00
_textureAtlas - > updateQuad ( & _quad , _atlasIndex ) ;
2012-11-12 10:20:04 +08:00
}
2013-11-26 08:33:05 +08:00
2013-06-15 14:03:30 +08:00
_recursiveDirty = false ;
2012-04-19 14:35:52 +08:00
setDirty ( false ) ;
}
2012-11-14 18:05:15 +08:00
// MARMALADE CHANGED
// recursively iterate over children
2013-11-27 03:48:37 +08:00
/* if( _hasChildren )
2012-11-14 18:05:15 +08:00
{
2013-06-20 14:13:12 +08:00
// MARMALADE: CHANGED TO USE Node*
// NOTE THAT WE HAVE ALSO DEFINED virtual Node::updateTransform()
arrayMakeObjectsPerformSelector ( _children , updateTransform , Sprite * ) ;
2012-11-14 18:05:15 +08:00
} */
2013-06-20 14:13:12 +08:00
Node : : updateTransform ( ) ;
2012-04-19 14:35:52 +08:00
}
// draw
2014-05-31 07:42:05 +08:00
void Sprite : : draw ( Renderer * renderer , const Mat4 & transform , uint32_t flags )
2012-04-19 14:35:52 +08:00
{
2015-12-16 11:53:59 +08:00
if ( _texture = = nullptr )
{
return ;
}
2016-11-24 09:59:00 +08:00
2015-01-14 10:56:51 +08:00
# if CC_USE_CULLING
2016-07-15 05:58:04 +08:00
// Don't calculate the culling if the transform was not updated
2015-07-30 11:53:23 +08:00
auto visitingCamera = Camera : : getVisitingCamera ( ) ;
auto defaultCamera = Camera : : getDefaultCamera ( ) ;
if ( visitingCamera = = defaultCamera ) {
2016-07-15 05:58:04 +08:00
_insideBounds = ( ( flags & FLAGS_TRANSFORM_DIRTY ) | | visitingCamera - > isViewProjectionUpdated ( ) ) ? renderer - > checkVisibility ( transform , _contentSize ) : _insideBounds ;
2015-07-30 11:53:23 +08:00
}
else
{
2016-07-15 05:58:04 +08:00
// XXX: this always return true since
2015-07-30 11:53:23 +08:00
_insideBounds = renderer - > checkVisibility ( transform , _contentSize ) ;
}
2014-03-01 08:10:48 +08:00
if ( _insideBounds )
2015-01-14 10:56:51 +08:00
# endif
2013-12-19 05:52:10 +08:00
{
2016-11-24 09:59:00 +08:00
_trianglesCommand . init ( _globalZOrder ,
_texture ,
getGLProgramState ( ) ,
_blendFunc ,
_polyInfo . triangles ,
transform ,
flags ) ;
2016-07-25 17:31:54 +08:00
2015-05-22 15:54:56 +08:00
renderer - > addCommand ( & _trianglesCommand ) ;
2016-11-24 09:59:00 +08:00
2015-08-26 18:14:25 +08:00
# if CC_SPRITE_DEBUG_DRAW
_debugDrawNode - > clear ( ) ;
auto count = _polyInfo . triangles . indexCount / 3 ;
auto indices = _polyInfo . triangles . indices ;
auto verts = _polyInfo . triangles . verts ;
for ( ssize_t i = 0 ; i < count ; i + + )
{
//draw 3 lines
Vec3 from = verts [ indices [ i * 3 ] ] . vertices ;
Vec3 to = verts [ indices [ i * 3 + 1 ] ] . vertices ;
_debugDrawNode - > drawLine ( Vec2 ( from . x , from . y ) , Vec2 ( to . x , to . y ) , Color4F : : WHITE ) ;
2016-11-24 09:59:00 +08:00
2015-08-26 18:14:25 +08:00
from = verts [ indices [ i * 3 + 1 ] ] . vertices ;
to = verts [ indices [ i * 3 + 2 ] ] . vertices ;
_debugDrawNode - > drawLine ( Vec2 ( from . x , from . y ) , Vec2 ( to . x , to . y ) , Color4F : : WHITE ) ;
2016-11-24 09:59:00 +08:00
2015-08-26 18:14:25 +08:00
from = verts [ indices [ i * 3 + 2 ] ] . vertices ;
to = verts [ indices [ i * 3 ] ] . vertices ;
_debugDrawNode - > drawLine ( Vec2 ( from . x , from . y ) , Vec2 ( to . x , to . y ) , Color4F : : WHITE ) ;
}
# endif //CC_SPRITE_DEBUG_DRAW
2013-12-19 05:52:10 +08:00
}
2013-11-27 09:13:04 +08:00
}
2012-04-19 14:35:52 +08:00
2014-08-30 03:54:24 +08:00
// MARK: visit, draw, transform
2013-07-26 07:27:24 +08:00
void Sprite : : addChild ( Node * child , int zOrder , int tag )
2012-04-19 14:35:52 +08:00
{
2013-12-18 17:47:20 +08:00
CCASSERT ( child ! = nullptr , " Argument must be non-nullptr " ) ;
2015-12-16 11:53:59 +08:00
if ( child = = nullptr )
{
return ;
}
2016-11-24 09:59:00 +08:00
2017-01-11 21:33:41 +08:00
if ( _renderMode = = RenderMode : : QUAD_BATCHNODE )
2012-04-19 14:35:52 +08:00
{
2013-07-26 07:27:24 +08:00
Sprite * childSprite = dynamic_cast < Sprite * > ( child ) ;
CCASSERT ( childSprite , " CCSprite only supports Sprites as children when using SpriteBatchNode " ) ;
2015-07-14 15:28:36 +08:00
CCASSERT ( childSprite - > getTexture ( ) - > getName ( ) = = _textureAtlas - > getTexture ( ) - > getName ( ) , " childSprite's texture name should be equal to _textureAtlas's texture name! " ) ;
2012-04-19 14:35:52 +08:00
//put it in descendants array of batch node
2013-07-26 07:27:24 +08:00
_batchNode - > appendChild ( childSprite ) ;
2012-04-19 14:35:52 +08:00
2013-06-15 14:03:30 +08:00
if ( ! _reorderChildDirty )
2012-04-19 14:35:52 +08:00
{
setReorderChildDirtyRecursively ( ) ;
}
}
//CCNode already sets isReorderChildDirty_ so this needs to be after batchNode check
2013-07-26 07:27:24 +08:00
Node : : addChild ( child , zOrder , tag ) ;
2012-04-19 14:35:52 +08:00
}
2014-06-25 11:27:48 +08:00
void Sprite : : addChild ( Node * child , int zOrder , const std : : string & name )
{
CCASSERT ( child ! = nullptr , " Argument must be non-nullptr " ) ;
2015-12-16 11:53:59 +08:00
if ( child = = nullptr )
{
return ;
}
2016-11-24 09:59:00 +08:00
2017-01-11 21:33:41 +08:00
if ( _renderMode = = RenderMode : : QUAD_BATCHNODE )
2014-06-25 11:27:48 +08:00
{
Sprite * childSprite = dynamic_cast < Sprite * > ( child ) ;
CCASSERT ( childSprite , " CCSprite only supports Sprites as children when using SpriteBatchNode " ) ;
2015-07-14 15:28:36 +08:00
CCASSERT ( childSprite - > getTexture ( ) - > getName ( ) = = _textureAtlas - > getTexture ( ) - > getName ( ) ,
" childSprite's texture name should be equal to _textureAtlas's texture name. " ) ;
2014-06-25 11:27:48 +08:00
//put it in descendants array of batch node
_batchNode - > appendChild ( childSprite ) ;
2016-11-24 09:59:00 +08:00
2014-06-25 11:27:48 +08:00
if ( ! _reorderChildDirty )
{
setReorderChildDirtyRecursively ( ) ;
}
}
//CCNode already sets isReorderChildDirty_ so this needs to be after batchNode check
Node : : addChild ( child , zOrder , name ) ;
}
2013-07-26 07:27:24 +08:00
void Sprite : : reorderChild ( Node * child , int zOrder )
2012-04-19 14:35:52 +08:00
{
2014-01-19 03:35:27 +08:00
CCASSERT ( child ! = nullptr , " child must be non null " ) ;
CCASSERT ( _children . contains ( child ) , " child does not belong to this " ) ;
2012-04-19 14:35:52 +08:00
2017-01-11 21:33:41 +08:00
if ( ( _renderMode = = RenderMode : : QUAD_BATCHNODE ) & & ! _reorderChildDirty )
2012-04-19 14:35:52 +08:00
{
setReorderChildDirtyRecursively ( ) ;
2013-06-15 14:03:30 +08:00
_batchNode - > reorderBatch ( true ) ;
2012-04-19 14:35:52 +08:00
}
2013-07-26 07:27:24 +08:00
Node : : reorderChild ( child , zOrder ) ;
2012-04-19 14:35:52 +08:00
}
2013-08-23 08:19:07 +08:00
void Sprite : : removeChild ( Node * child , bool cleanup )
2012-04-19 14:35:52 +08:00
{
2017-01-11 21:33:41 +08:00
if ( _renderMode = = RenderMode : : QUAD_BATCHNODE )
2012-04-19 14:35:52 +08:00
{
2013-07-26 07:27:24 +08:00
_batchNode - > removeSpriteFromAtlas ( ( Sprite * ) ( child ) ) ;
2012-04-19 14:35:52 +08:00
}
2013-08-23 08:19:07 +08:00
Node : : removeChild ( child , cleanup ) ;
2012-04-19 14:35:52 +08:00
}
2013-08-23 08:19:07 +08:00
void Sprite : : removeAllChildrenWithCleanup ( bool cleanup )
2012-04-19 14:35:52 +08:00
{
2017-01-11 21:33:41 +08:00
if ( _renderMode = = RenderMode : : QUAD_BATCHNODE )
2012-04-19 14:35:52 +08:00
{
2013-12-19 10:33:04 +08:00
for ( const auto & child : _children ) {
2013-11-28 16:02:03 +08:00
Sprite * sprite = dynamic_cast < Sprite * > ( child ) ;
if ( sprite )
2012-04-19 14:35:52 +08:00
{
2013-11-28 16:02:03 +08:00
_batchNode - > removeSpriteFromAtlas ( sprite ) ;
2012-04-19 14:35:52 +08:00
}
2013-12-19 10:33:04 +08:00
}
2012-04-19 14:35:52 +08:00
}
2013-08-23 08:19:07 +08:00
Node : : removeAllChildrenWithCleanup ( cleanup ) ;
2012-04-19 14:35:52 +08:00
}
2013-06-20 14:13:12 +08:00
void Sprite : : sortAllChildren ( )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
if ( _reorderChildDirty )
2012-04-19 14:35:52 +08:00
{
2016-07-31 22:44:24 +08:00
sortNodes ( _children ) ;
2012-04-19 14:35:52 +08:00
2017-01-11 21:33:41 +08:00
if ( _renderMode = = RenderMode : : QUAD_BATCHNODE )
2012-04-19 14:35:52 +08:00
{
2013-12-19 10:33:04 +08:00
for ( const auto & child : _children )
2013-11-28 16:02:03 +08:00
child - > sortAllChildren ( ) ;
2012-04-19 14:35:52 +08:00
}
2013-06-15 14:03:30 +08:00
_reorderChildDirty = false ;
2012-04-19 14:35:52 +08:00
}
}
//
2013-06-20 14:13:12 +08:00
// Node property overloads
// used only when parent is SpriteBatchNode
2012-04-19 14:35:52 +08:00
//
2013-06-20 14:13:12 +08:00
void Sprite : : setReorderChildDirtyRecursively ( void )
2012-04-19 14:35:52 +08:00
{
//only set parents flag the first time
2013-06-15 14:03:30 +08:00
if ( ! _reorderChildDirty )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
_reorderChildDirty = true ;
2013-08-23 08:19:07 +08:00
Node * node = static_cast < Node * > ( _parent ) ;
while ( node & & node ! = _batchNode )
2012-04-19 14:35:52 +08:00
{
2013-08-23 08:19:07 +08:00
static_cast < Sprite * > ( node ) - > setReorderChildDirtyRecursively ( ) ;
node = node - > getParent ( ) ;
2012-04-19 14:35:52 +08:00
}
}
}
2013-06-20 14:13:12 +08:00
void Sprite : : setDirtyRecursively ( bool bValue )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
_recursiveDirty = bValue ;
2012-04-19 14:35:52 +08:00
setDirty ( bValue ) ;
2014-01-16 10:37:07 +08:00
for ( const auto & child : _children ) {
Sprite * sp = dynamic_cast < Sprite * > ( child ) ;
if ( sp )
{
sp - > setDirtyRecursively ( true ) ;
2013-12-19 10:33:04 +08:00
}
2012-04-19 14:35:52 +08:00
}
}
2014-08-30 03:54:24 +08:00
// FIXME: HACK: optimization
2014-01-16 10:37:07 +08:00
# define SET_DIRTY_RECURSIVELY() { \
if ( ! _recursiveDirty ) { \
_recursiveDirty = true ; \
setDirty ( true ) ; \
if ( ! _children . empty ( ) ) \
setDirtyRecursively ( true ) ; \
} \
2012-04-19 14:35:52 +08:00
}
2014-05-15 01:07:09 +08:00
void Sprite : : setPosition ( const Vec2 & pos )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
Node : : setPosition ( pos ) ;
2012-04-19 14:35:52 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2013-11-05 01:14:22 +08:00
void Sprite : : setPosition ( float x , float y )
{
Node : : setPosition ( x , y ) ;
SET_DIRTY_RECURSIVELY ( ) ;
}
2013-09-16 21:22:22 +08:00
void Sprite : : setRotation ( float rotation )
2012-04-19 14:35:52 +08:00
{
2013-09-16 21:22:22 +08:00
Node : : setRotation ( rotation ) ;
2016-11-24 09:59:00 +08:00
2012-04-19 14:35:52 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2014-02-23 17:09:52 +08:00
void Sprite : : setRotationSkewX ( float fRotationX )
2012-11-14 18:05:15 +08:00
{
2014-02-23 17:09:52 +08:00
Node : : setRotationSkewX ( fRotationX ) ;
2012-11-14 18:05:15 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2014-02-23 17:09:52 +08:00
void Sprite : : setRotationSkewY ( float fRotationY )
2012-11-14 18:05:15 +08:00
{
2014-02-23 17:09:52 +08:00
Node : : setRotationSkewY ( fRotationY ) ;
2012-11-14 18:05:15 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2013-06-20 14:13:12 +08:00
void Sprite : : setSkewX ( float sx )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
Node : : setSkewX ( sx ) ;
2012-04-19 14:35:52 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2013-06-20 14:13:12 +08:00
void Sprite : : setSkewY ( float sy )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
Node : : setSkewY ( sy ) ;
2012-04-19 14:35:52 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2013-07-27 21:44:49 +08:00
void Sprite : : setScaleX ( float scaleX )
2012-04-19 14:35:52 +08:00
{
2013-07-27 21:44:49 +08:00
Node : : setScaleX ( scaleX ) ;
2012-04-19 14:35:52 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2013-07-27 21:44:49 +08:00
void Sprite : : setScaleY ( float scaleY )
2012-04-19 14:35:52 +08:00
{
2013-07-27 21:44:49 +08:00
Node : : setScaleY ( scaleY ) ;
2012-04-19 14:35:52 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2013-06-20 14:13:12 +08:00
void Sprite : : setScale ( float fScale )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
Node : : setScale ( fScale ) ;
2012-04-19 14:35:52 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2013-11-06 21:42:31 +08:00
void Sprite : : setScale ( float scaleX , float scaleY )
{
Node : : setScale ( scaleX , scaleY ) ;
SET_DIRTY_RECURSIVELY ( ) ;
}
2014-02-23 17:09:52 +08:00
void Sprite : : setPositionZ ( float fVertexZ )
2012-04-19 14:35:52 +08:00
{
2014-02-23 17:09:52 +08:00
Node : : setPositionZ ( fVertexZ ) ;
2012-04-19 14:35:52 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2014-05-15 01:07:09 +08:00
void Sprite : : setAnchorPoint ( const Vec2 & anchor )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
Node : : setAnchorPoint ( anchor ) ;
2012-04-19 14:35:52 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2016-04-22 20:36:02 +08:00
void Sprite : : setIgnoreAnchorPointForPosition ( bool value )
2012-04-19 14:35:52 +08:00
{
2017-01-11 21:33:41 +08:00
CCASSERT ( _renderMode ! = RenderMode : : QUAD_BATCHNODE , " setIgnoreAnchorPointForPosition is invalid in Sprite " ) ;
2016-04-22 20:36:02 +08:00
Node : : setIgnoreAnchorPointForPosition ( value ) ;
2012-04-19 14:35:52 +08:00
}
2013-06-20 14:13:12 +08:00
void Sprite : : setVisible ( bool bVisible )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
Node : : setVisible ( bVisible ) ;
2012-04-19 14:35:52 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2016-10-27 09:45:40 +08:00
void Sprite : : setContentSize ( const Size & size )
{
2017-01-11 21:33:41 +08:00
if ( _renderMode = = RenderMode : : QUAD_BATCHNODE | | _renderMode = = RenderMode : : POLYGON )
2017-01-18 15:41:18 +08:00
CCLOGWARN ( " Sprite::setContentSize() doesn't stretch the sprite when using QUAD_BATCHNODE or POLYGON render modes " ) ;
2017-01-10 15:28:47 +08:00
2016-10-27 09:45:40 +08:00
Node : : setContentSize ( size ) ;
updateStretchFactor ( ) ;
updatePoly ( ) ;
}
2017-01-23 09:25:56 +08:00
void Sprite : : setStretchEnabled ( bool enabled )
2016-11-24 09:59:00 +08:00
{
2017-01-23 09:25:56 +08:00
if ( _stretchEnabled ! = enabled ) {
_stretchEnabled = enabled ;
2016-11-24 09:59:00 +08:00
// disabled centerrect / number of slices if disabled
if ( ! enabled )
setCenterRectNormalized ( Rect ( 0 , 0 , 1 , 1 ) ) ;
updateStretchFactor ( ) ;
updatePoly ( ) ;
}
}
2017-01-23 09:25:56 +08:00
void Sprite : : setStrechEnabled ( bool enabled )
{
setStretchEnabled ( enabled ) ;
}
bool Sprite : : isStretchEnabled ( ) const
{
return _stretchEnabled ;
}
2016-11-24 09:59:00 +08:00
bool Sprite : : isStrechEnabled ( ) const
{
2017-01-23 09:25:56 +08:00
return isStretchEnabled ( ) ;
2016-11-24 09:59:00 +08:00
}
2016-10-27 09:45:40 +08:00
void Sprite : : updateStretchFactor ( )
{
const Size size = getContentSize ( ) ;
2017-01-10 15:28:47 +08:00
if ( _renderMode = = RenderMode : : QUAD )
2016-10-27 09:45:40 +08:00
{
2017-01-11 09:31:45 +08:00
// If stretch is disabled, calculate the stretch anyway
2016-11-24 09:59:00 +08:00
// since it is needed to calculate the offset
2017-01-10 15:28:47 +08:00
const float x_factor = size . width / _originalContentSize . width ;
const float y_factor = size . height / _originalContentSize . height ;
2017-01-23 09:25:56 +08:00
_stretchFactor = Vec2 ( std : : max ( 0.0f , x_factor ) ,
std : : max ( 0.0f , y_factor ) ) ;
2016-10-27 09:45:40 +08:00
}
2017-01-10 15:28:47 +08:00
else if ( _renderMode = = RenderMode : : SLICE9 )
2016-10-27 09:45:40 +08:00
{
2016-10-30 08:52:33 +08:00
const float x1 = _rect . size . width * _centerRectNormalized . origin . x ;
const float x2 = _rect . size . width * _centerRectNormalized . size . width ;
const float x3 = _rect . size . width * ( 1 - _centerRectNormalized . origin . x - _centerRectNormalized . size . width ) ;
2016-10-27 09:45:40 +08:00
2016-10-30 08:52:33 +08:00
const float y1 = _rect . size . height * _centerRectNormalized . origin . y ;
const float y2 = _rect . size . height * _centerRectNormalized . size . height ;
const float y3 = _rect . size . height * ( 1 - _centerRectNormalized . origin . y - _centerRectNormalized . size . height ) ;
2016-10-27 09:45:40 +08:00
2016-11-24 09:59:00 +08:00
// adjustedSize = the new _rect size
const float adjustedWidth = size . width - ( _originalContentSize . width - _rect . size . width ) ;
const float adjustedHeight = size . height - ( _originalContentSize . height - _rect . size . height ) ;
2017-01-10 15:28:47 +08:00
const float x_factor = ( adjustedWidth - x1 - x3 ) / x2 ;
const float y_factor = ( adjustedHeight - y1 - y3 ) / y2 ;
2016-10-27 09:45:40 +08:00
2017-01-23 09:25:56 +08:00
_stretchFactor = Vec2 ( std : : max ( 0.0f , x_factor ) ,
std : : max ( 0.0f , y_factor ) ) ;
2016-10-27 09:45:40 +08:00
}
2016-12-03 23:35:22 +08:00
2017-01-10 15:28:47 +08:00
// else:
// Do nothing if renderMode is Polygon
2016-10-27 09:45:40 +08:00
}
2013-09-13 11:41:20 +08:00
void Sprite : : setFlippedX ( bool flippedX )
2012-04-19 14:35:52 +08:00
{
2013-09-13 11:41:20 +08:00
if ( _flippedX ! = flippedX )
2012-04-19 14:35:52 +08:00
{
2013-09-13 11:41:20 +08:00
_flippedX = flippedX ;
2016-10-30 08:52:33 +08:00
2017-01-11 21:33:41 +08:00
if ( _renderMode = = RenderMode : : QUAD_BATCHNODE )
2017-01-10 15:28:47 +08:00
{
2015-08-05 23:17:38 +08:00
setDirty ( true ) ;
2017-01-10 15:28:47 +08:00
}
else if ( _renderMode = = RenderMode : : POLYGON )
{
for ( ssize_t i = 0 ; i < _polyInfo . triangles . vertCount ; i + + ) {
auto & v = _polyInfo . triangles . verts [ i ] . vertices ;
v . x = _contentSize . width - v . x ;
}
}
else
{
// RenderMode:: Quad or Slice9
2016-11-24 09:59:00 +08:00
updatePoly ( ) ;
2015-08-05 23:17:38 +08:00
}
2012-04-19 14:35:52 +08:00
}
}
2013-09-13 11:41:20 +08:00
bool Sprite : : isFlippedX ( void ) const
2012-04-19 14:35:52 +08:00
{
2013-09-13 11:41:20 +08:00
return _flippedX ;
2012-04-19 14:35:52 +08:00
}
2013-09-13 11:41:20 +08:00
void Sprite : : setFlippedY ( bool flippedY )
2012-04-19 14:35:52 +08:00
{
2013-09-13 11:41:20 +08:00
if ( _flippedY ! = flippedY )
2012-04-19 14:35:52 +08:00
{
2013-09-13 11:41:20 +08:00
_flippedY = flippedY ;
2016-10-30 08:52:33 +08:00
2017-01-11 21:33:41 +08:00
if ( _renderMode = = RenderMode : : QUAD_BATCHNODE )
2017-01-10 15:28:47 +08:00
{
2015-08-05 23:17:38 +08:00
setDirty ( true ) ;
2017-01-10 15:28:47 +08:00
}
else if ( _renderMode = = RenderMode : : POLYGON )
{
for ( ssize_t i = 0 ; i < _polyInfo . triangles . vertCount ; i + + ) {
auto & v = _polyInfo . triangles . verts [ i ] . vertices ;
v . y = _contentSize . height - v . y ;
}
}
else
{
// RenderMode:: Quad or Slice9
2016-11-24 09:59:00 +08:00
updatePoly ( ) ;
2015-08-05 23:17:38 +08:00
}
2012-04-19 14:35:52 +08:00
}
}
2013-09-13 11:41:20 +08:00
bool Sprite : : isFlippedY ( void ) const
2012-04-19 14:35:52 +08:00
{
2013-09-13 11:41:20 +08:00
return _flippedY ;
2012-04-19 14:35:52 +08:00
}
//
2014-08-30 03:54:24 +08:00
// MARK: RGBA protocol
2012-04-19 14:35:52 +08:00
//
2013-06-20 14:13:12 +08:00
void Sprite : : updateColor ( void )
2012-04-19 14:35:52 +08:00
{
2013-07-07 21:08:14 +08:00
Color4B color4 ( _displayedColor . r , _displayedColor . g , _displayedColor . b , _displayedOpacity ) ;
2016-11-24 09:59:00 +08:00
2013-02-27 15:30:49 +08:00
// special opacity for premultiplied textures
2015-01-08 10:22:45 +08:00
if ( _opacityModifyRGB )
2013-02-27 15:30:49 +08:00
{
2015-01-08 10:22:45 +08:00
color4 . r * = _displayedOpacity / 255.0f ;
color4 . g * = _displayedOpacity / 255.0f ;
color4 . b * = _displayedOpacity / 255.0f ;
2013-02-27 15:30:49 +08:00
}
2012-04-19 14:35:52 +08:00
2015-07-15 16:27:29 +08:00
for ( ssize_t i = 0 ; i < _polyInfo . triangles . vertCount ; i + + ) {
_polyInfo . triangles . verts [ i ] . colors = color4 ;
}
2012-04-19 14:35:52 +08:00
2017-01-10 15:28:47 +08:00
// related to issue #17116
// when switching from Quad to Slice9, the color will be obtained from _quad
// so it is important to update _quad colors as well.
_quad . bl . colors = _quad . tl . colors = _quad . br . colors = _quad . tr . colors = color4 ;
2012-04-19 14:35:52 +08:00
// renders using batch node
2017-01-11 21:33:41 +08:00
if ( _renderMode = = RenderMode : : QUAD_BATCHNODE )
2012-04-19 14:35:52 +08:00
{
2013-09-01 01:38:10 +08:00
if ( _atlasIndex ! = INDEX_NOT_INITIALIZED )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
_textureAtlas - > updateQuad ( & _quad , _atlasIndex ) ;
2012-04-19 14:35:52 +08:00
}
else
{
// no need to set it recursively
// update dirty_, don't update recursiveDirty_
setDirty ( true ) ;
}
}
// self render
// do nothing
}
2013-06-20 14:13:12 +08:00
void Sprite : : setOpacityModifyRGB ( bool modify )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
if ( _opacityModifyRGB ! = modify )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
_opacityModifyRGB = modify ;
2013-02-27 15:30:49 +08:00
updateColor ( ) ;
2012-04-19 14:35:52 +08:00
}
2013-02-27 15:30:49 +08:00
}
2012-04-19 14:35:52 +08:00
2013-07-04 08:22:15 +08:00
bool Sprite : : isOpacityModifyRGB ( void ) const
2013-02-27 15:30:49 +08:00
{
2013-06-15 14:03:30 +08:00
return _opacityModifyRGB ;
2012-04-19 14:35:52 +08:00
}
2014-08-30 03:54:24 +08:00
// MARK: Frames
2012-04-19 14:35:52 +08:00
2013-11-14 07:55:36 +08:00
void Sprite : : setSpriteFrame ( const std : : string & spriteFrameName )
{
2015-12-16 11:53:59 +08:00
CCASSERT ( ! spriteFrameName . empty ( ) , " spriteFrameName must not be empty " ) ;
if ( spriteFrameName . empty ( ) )
{
return ;
}
2016-11-24 09:59:00 +08:00
2013-11-14 07:55:36 +08:00
SpriteFrameCache * cache = SpriteFrameCache : : getInstance ( ) ;
SpriteFrame * spriteFrame = cache - > getSpriteFrameByName ( spriteFrameName ) ;
2014-12-04 19:18:54 +08:00
CCASSERT ( spriteFrame , std : : string ( " Invalid spriteFrameName : " ) . append ( spriteFrameName ) . c_str ( ) ) ;
2013-11-14 07:55:36 +08:00
setSpriteFrame ( spriteFrame ) ;
}
2013-11-15 07:37:43 +08:00
void Sprite : : setSpriteFrame ( SpriteFrame * spriteFrame )
2012-04-19 14:35:52 +08:00
{
2014-12-08 21:04:15 +08:00
// retain the sprite frame
// do not removed by SpriteFrameCache::removeUnusedSpriteFrames
if ( _spriteFrame ! = spriteFrame )
{
CC_SAFE_RELEASE ( _spriteFrame ) ;
_spriteFrame = spriteFrame ;
spriteFrame - > retain ( ) ;
}
2013-11-15 07:37:43 +08:00
_unflippedOffsetPositionFromCenter = spriteFrame - > getOffset ( ) ;
2012-04-19 14:35:52 +08:00
2013-11-15 07:37:43 +08:00
Texture2D * texture = spriteFrame - > getTexture ( ) ;
2012-04-19 14:35:52 +08:00
// update texture before updating texture rect
2013-11-15 07:37:43 +08:00
if ( texture ! = _texture )
2012-04-19 14:35:52 +08:00
{
2013-11-15 07:37:43 +08:00
setTexture ( texture ) ;
2012-04-19 14:35:52 +08:00
}
// update rect
2013-11-15 07:37:43 +08:00
_rectRotated = spriteFrame - > isRotated ( ) ;
setTextureRect ( spriteFrame - > getRect ( ) , _rectRotated , spriteFrame - > getOriginalSize ( ) ) ;
2016-11-24 09:59:00 +08:00
2016-10-27 09:45:40 +08:00
if ( spriteFrame - > hasPolygonInfo ( ) )
2015-09-29 21:42:04 +08:00
{
_polyInfo = spriteFrame - > getPolygonInfo ( ) ;
2017-01-10 15:28:47 +08:00
_renderMode = RenderMode : : POLYGON ;
2015-09-29 21:42:04 +08:00
}
2015-12-14 22:42:18 +08:00
if ( spriteFrame - > hasAnchorPoint ( ) )
{
setAnchorPoint ( spriteFrame - > getAnchorPoint ( ) ) ;
}
2016-10-27 09:45:40 +08:00
if ( spriteFrame - > hasCenterRect ( ) )
{
2016-10-30 08:52:33 +08:00
setCenterRect ( spriteFrame - > getCenterRect ( ) ) ;
2016-10-27 09:45:40 +08:00
}
2012-04-19 14:35:52 +08:00
}
2013-12-12 12:07:20 +08:00
void Sprite : : setDisplayFrameWithAnimationName ( const std : : string & animationName , ssize_t frameIndex )
2012-04-19 14:35:52 +08:00
{
2015-12-16 11:53:59 +08:00
CCASSERT ( ! animationName . empty ( ) , " CCSprite#setDisplayFrameWithAnimationName. animationName must not be nullptr " ) ;
if ( animationName . empty ( ) )
{
return ;
}
2016-11-24 09:59:00 +08:00
2013-09-16 20:38:03 +08:00
Animation * a = AnimationCache : : getInstance ( ) - > getAnimation ( animationName ) ;
2012-04-19 14:35:52 +08:00
2013-07-20 13:01:27 +08:00
CCASSERT ( a , " CCSprite#setDisplayFrameWithAnimationName: Frame not found " ) ;
2012-04-19 14:35:52 +08:00
2013-12-05 10:35:10 +08:00
AnimationFrame * frame = a - > getFrames ( ) . at ( frameIndex ) ;
2012-04-19 14:35:52 +08:00
2013-07-20 13:01:27 +08:00
CCASSERT ( frame , " CCSprite#setDisplayFrame. Invalid frame " ) ;
2012-04-19 14:35:52 +08:00
2013-11-15 07:37:43 +08:00
setSpriteFrame ( frame - > getSpriteFrame ( ) ) ;
2012-04-19 14:35:52 +08:00
}
2013-08-23 08:19:07 +08:00
bool Sprite : : isFrameDisplayed ( SpriteFrame * frame ) const
2012-04-19 14:35:52 +08:00
{
2013-08-23 08:19:07 +08:00
Rect r = frame - > getRect ( ) ;
2012-04-19 14:35:52 +08:00
2013-06-15 14:03:30 +08:00
return ( r . equals ( _rect ) & &
2013-08-23 08:19:07 +08:00
frame - > getTexture ( ) - > getName ( ) = = _texture - > getName ( ) & &
frame - > getOffset ( ) . equals ( _unflippedOffsetPositionFromCenter ) ) ;
2012-04-19 14:35:52 +08:00
}
2013-11-15 07:37:43 +08:00
SpriteFrame * Sprite : : getSpriteFrame ( ) const
2012-04-19 14:35:52 +08:00
{
2015-05-21 16:04:37 +08:00
if ( nullptr ! = this - > _spriteFrame )
{
return this - > _spriteFrame ;
}
2013-06-20 14:13:12 +08:00
return SpriteFrame : : createWithTexture ( _texture ,
2016-10-27 09:45:40 +08:00
CC_RECT_POINTS_TO_PIXELS ( _rect ) ,
_rectRotated ,
CC_POINT_POINTS_TO_PIXELS ( _unflippedOffsetPositionFromCenter ) ,
CC_SIZE_POINTS_TO_PIXELS ( _originalContentSize ) ) ;
2012-04-19 14:35:52 +08:00
}
2014-11-26 09:53:52 +08:00
SpriteBatchNode * Sprite : : getBatchNode ( ) const
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
return _batchNode ;
2012-04-19 14:35:52 +08:00
}
2013-07-26 06:53:24 +08:00
void Sprite : : setBatchNode ( SpriteBatchNode * spriteBatchNode )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
_batchNode = spriteBatchNode ; // weak reference
2012-04-19 14:35:52 +08:00
// self render
2013-06-15 14:03:30 +08:00
if ( ! _batchNode ) {
2017-01-10 15:28:47 +08:00
_renderMode = RenderMode : : QUAD ;
2013-09-01 01:38:10 +08:00
_atlasIndex = INDEX_NOT_INITIALIZED ;
2013-12-18 17:47:20 +08:00
setTextureAtlas ( nullptr ) ;
2013-06-15 14:03:30 +08:00
_recursiveDirty = false ;
2012-04-19 14:35:52 +08:00
setDirty ( false ) ;
2013-06-15 14:03:30 +08:00
float x1 = _offsetPosition . x ;
float y1 = _offsetPosition . y ;
float x2 = x1 + _rect . size . width ;
float y2 = y1 + _rect . size . height ;
Optimize Vec3
small function Vec3 move to Vec3.inl
Added:
add(float xx, float yy, float zz);
setZero();
Change all code:
_vec3 = Vec3(x, y, z); -> _vec3.set(x, y, z);
Vec3 vec3 = Vec3(x, y, z); -> Vec3 vec3(x, y, z);
_vec3 += Vec3(x, y, z); -> _vec3.add(x, y, z);
_vec3 = Vec3::ZERO; -> _vec3.setZero();
2015-04-05 18:09:50 +08:00
_quad . bl . vertices . set ( x1 , y1 , 0 ) ;
_quad . br . vertices . set ( x2 , y1 , 0 ) ;
_quad . tl . vertices . set ( x1 , y2 , 0 ) ;
_quad . tr . vertices . set ( x2 , y2 , 0 ) ;
2012-04-19 14:35:52 +08:00
} else {
// using batch
2017-01-11 21:33:41 +08:00
_renderMode = RenderMode : : QUAD_BATCHNODE ;
2014-05-15 01:07:09 +08:00
_transformToBatch = Mat4 : : IDENTITY ;
2013-06-15 14:03:30 +08:00
setTextureAtlas ( _batchNode - > getTextureAtlas ( ) ) ; // weak ref
2012-04-19 14:35:52 +08:00
}
}
2014-08-30 03:54:24 +08:00
// MARK: Texture protocol
2012-04-19 14:35:52 +08:00
2013-06-20 14:13:12 +08:00
void Sprite : : updateBlendFunc ( void )
2012-04-19 14:35:52 +08:00
{
2017-01-11 21:33:41 +08:00
CCASSERT ( _renderMode ! = RenderMode : : QUAD_BATCHNODE , " CCSprite: updateBlendFunc doesn't work when the sprite is rendered using a SpriteBatchNode " ) ;
2012-04-19 14:35:52 +08:00
2015-09-09 11:37:41 +08:00
// it is possible to have an untextured sprite
2013-06-15 14:03:30 +08:00
if ( ! _texture | | ! _texture - > hasPremultipliedAlpha ( ) )
2012-04-19 14:35:52 +08:00
{
2013-07-26 04:36:19 +08:00
_blendFunc = BlendFunc : : ALPHA_NON_PREMULTIPLIED ;
2012-06-15 15:10:40 +08:00
setOpacityModifyRGB ( false ) ;
2012-04-19 14:35:52 +08:00
}
else
{
2013-07-26 04:36:19 +08:00
_blendFunc = BlendFunc : : ALPHA_PREMULTIPLIED ;
2012-06-15 15:10:40 +08:00
setOpacityModifyRGB ( true ) ;
2012-04-19 14:35:52 +08:00
}
}
2013-12-13 06:30:22 +08:00
std : : string Sprite : : getDescription ( ) const
{
int texture_id = - 1 ;
2017-01-11 21:33:41 +08:00
if ( _renderMode = = RenderMode : : QUAD_BATCHNODE )
2013-12-13 06:30:22 +08:00
texture_id = _batchNode - > getTextureAtlas ( ) - > getTexture ( ) - > getName ( ) ;
else
texture_id = _texture - > getName ( ) ;
return StringUtils : : format ( " <Sprite | Tag = %d, TextureID = %d> " , _tag , texture_id ) ;
}
2016-05-25 07:57:40 +08:00
const PolygonInfo & Sprite : : getPolygonInfo ( ) const
2015-06-04 15:43:31 +08:00
{
2015-06-04 16:20:00 +08:00
return _polyInfo ;
2015-06-04 15:43:31 +08:00
}
void Sprite : : setPolygonInfo ( const PolygonInfo & info )
{
2015-06-04 16:20:00 +08:00
_polyInfo = info ;
2017-01-10 15:28:47 +08:00
_renderMode = RenderMode : : POLYGON ;
2015-06-04 15:43:31 +08:00
}
2012-04-19 14:35:52 +08:00
NS_CC_END