2012-04-19 14:35:52 +08:00
/****************************************************************************
2012-06-08 14:11:48 +08:00
Copyright ( c ) 2010 - 2012 cocos2d - x . org
2012-04-19 14:35:52 +08:00
Copyright ( c ) 2008 - 2010 Ricardo Quesada
Copyright ( c ) 2011 Zynga Inc .
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "CCSpriteBatchNode.h"
2013-09-01 22:41:11 +08:00
# include <string.h>
# include <algorithm>
2012-04-19 14:35:52 +08:00
# include "CCAnimation.h"
# include "CCAnimationCache.h"
# include "ccConfig.h"
# include "CCSprite.h"
# include "CCSpriteFrame.h"
# include "CCSpriteFrameCache.h"
2012-06-19 16:20:46 +08:00
# include "textures/CCTextureCache.h"
2012-11-16 14:23:14 +08:00
# include "draw_nodes/CCDrawingPrimitives.h"
2012-06-19 16:20:46 +08:00
# include "shaders/CCShaderCache.h"
# include "shaders/ccGLStateCache.h"
# include "shaders/CCGLProgram.h"
2012-04-19 14:35:52 +08:00
# include "CCDirector.h"
2012-06-19 16:20:46 +08:00
# include "cocoa/CCGeometry.h"
# include "textures/CCTexture2D.h"
# include "cocoa/CCAffineTransform.h"
2012-04-19 14:35:52 +08:00
# include "support/TransformUtils.h"
# include "support/CCProfiling.h"
// external
# include "kazmath/GL/matrix.h"
2013-09-01 22:41:11 +08:00
2012-04-19 14:35:52 +08:00
using namespace std ;
NS_CC_BEGIN
# if CC_SPRITEBATCHNODE_RENDER_SUBPIXEL
# define RENDER_IN_SUBPIXEL
# else
2012-11-14 18:05:15 +08:00
# define RENDER_IN_SUBPIXEL(__ARGS__) (ceil(__ARGS__))
2012-04-19 14:35:52 +08:00
# endif
2013-07-26 06:53:24 +08:00
Sprite * Sprite : : createWithTexture ( Texture2D * texture )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
Sprite * sprite = new 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 ) ;
2012-04-19 14:35:52 +08:00
return NULL ;
}
2013-07-26 06:53:24 +08:00
Sprite * Sprite : : createWithTexture ( Texture2D * texture , const Rect & rect )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
Sprite * sprite = new Sprite ( ) ;
if ( sprite & & sprite - > initWithTexture ( texture , 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 ) ;
2012-04-19 14:35:52 +08:00
return NULL ;
}
2013-07-26 06:53:24 +08:00
Sprite * Sprite : : create ( const char * filename )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
Sprite * sprite = new 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 ) ;
2012-04-19 14:35:52 +08:00
return NULL ;
}
2013-07-26 06:53:24 +08:00
Sprite * Sprite : : create ( const char * filename , const Rect & rect )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
Sprite * sprite = new 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 ) ;
2012-04-19 14:35:52 +08:00
return NULL ;
}
2013-08-23 08:19:07 +08:00
Sprite * Sprite : : createWithSpriteFrame ( SpriteFrame * spriteFrame )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
Sprite * sprite = new Sprite ( ) ;
2013-08-23 08:19:07 +08:00
if ( spriteFrame & & sprite & & 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 ) ;
2012-04-19 14:35:52 +08:00
return NULL ;
}
2013-07-26 06:53:24 +08:00
Sprite * Sprite : : createWithSpriteFrameName ( const char * spriteFrameName )
2012-04-19 14:35:52 +08:00
{
2013-08-23 08:19:07 +08:00
SpriteFrame * frame = SpriteFrameCache : : getInstance ( ) - > getSpriteFrameByName ( spriteFrameName ) ;
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-07-26 06:53:24 +08:00
sprintf ( msg , " Invalid spriteFrameName: %s " , spriteFrameName ) ;
2013-08-23 08:19:07 +08:00
CCASSERT ( frame ! = NULL , msg ) ;
2012-09-04 11:16:59 +08:00
# endif
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
{
2013-08-23 08:19:07 +08:00
Sprite * sprite = new Sprite ( ) ;
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 ) ;
2012-06-02 06:11:42 +08:00
return NULL ;
2012-04-19 14:35:52 +08:00
}
2013-06-20 14:13:12 +08:00
bool Sprite : : init ( void )
2012-04-19 14:35:52 +08:00
{
2013-07-12 14:47:36 +08:00
return initWithTexture ( NULL , Rect : : ZERO ) ;
2012-04-19 14:35:52 +08:00
}
// designated initializer
2013-07-26 06:53:24 +08:00
bool Sprite : : initWithTexture ( Texture2D * texture , const Rect & rect , bool rotated )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
if ( NodeRGBA : : init ( ) )
2013-02-27 15:30:49 +08:00
{
2013-06-15 14:03:30 +08:00
_batchNode = NULL ;
2013-02-27 15:30:49 +08:00
2013-06-15 14:03:30 +08:00
_recursiveDirty = false ;
2013-02-27 15:30:49 +08:00
setDirty ( false ) ;
2013-06-15 14:03:30 +08:00
_opacityModifyRGB = true ;
2013-02-27 15:30:49 +08:00
2013-07-26 08:47:42 +08:00
_blendFunc = BlendFunc : : ALPHA_PREMULTIPLIED ;
2013-02-27 15:30:49 +08:00
2013-06-15 14:03:30 +08:00
_flipX = _flipY = false ;
2013-02-27 15:30:49 +08:00
// default transform anchor: center
2013-07-12 14:11:55 +08:00
setAnchorPoint ( Point ( 0.5f , 0.5f ) ) ;
2013-02-27 15:30:49 +08:00
// zwoptex default values
2013-07-12 14:47:36 +08:00
_offsetPosition = Point : : ZERO ;
2013-02-27 15:30:49 +08:00
2013-06-15 14:03:30 +08:00
_hasChildren = false ;
2013-02-27 15:30:49 +08:00
// clean the Quad
2013-06-15 14:03:30 +08:00
memset ( & _quad , 0 , sizeof ( _quad ) ) ;
2013-02-27 15:30:49 +08:00
// Atlas: Color
2013-08-23 08:19:07 +08:00
_quad . bl . colors = Color4B : : WHITE ;
_quad . br . colors = Color4B : : WHITE ;
_quad . tl . colors = Color4B : : WHITE ;
_quad . tr . colors = Color4B : : WHITE ;
2013-02-27 15:30:49 +08:00
2013-07-03 16:16:30 +08:00
// shader program
2013-07-25 17:48:22 +08:00
setShaderProgram ( ShaderCache : : getInstance ( ) - > programForKey ( GLProgram : : SHADER_NAME_POSITION_TEXTURE_COLOR ) ) ;
2013-07-03 16:16:30 +08:00
2013-02-27 15:30:49 +08:00
// update texture (calls updateBlendFunc)
2013-07-26 06:53:24 +08:00
setTexture ( texture ) ;
2013-02-27 15:30:49 +08:00
setTextureRect ( rect , rotated , rect . size ) ;
// by default use "Self Render".
// if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
setBatchNode ( NULL ) ;
return true ;
}
else
{
return false ;
}
2012-04-19 14:35:52 +08:00
}
2013-07-26 06:53:24 +08:00
bool Sprite : : initWithTexture ( Texture2D * texture , const Rect & rect )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
return initWithTexture ( texture , rect , false ) ;
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-07-26 06:53:24 +08:00
CCASSERT ( texture ! = NULL , " Invalid texture for sprite " ) ;
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 ( ) ;
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
}
2013-07-26 06:53:24 +08:00
bool Sprite : : initWithFile ( const char * filename )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
CCASSERT ( filename ! = NULL , " Invalid filename for sprite " ) ;
2012-04-19 14:35:52 +08:00
2013-07-26 06:53:24 +08:00
Texture2D * texture = TextureCache : : getInstance ( ) - > addImage ( filename ) ;
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
// this->release();
return false ;
}
2013-07-26 06:53:24 +08:00
bool Sprite : : initWithFile ( const char * filename , const Rect & rect )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
CCASSERT ( filename ! = NULL , " " ) ;
2012-04-19 14:35:52 +08:00
2013-07-26 06:53:24 +08:00
Texture2D * texture = TextureCache : : getInstance ( ) - > addImage ( filename ) ;
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
// this->release();
return false ;
}
2013-08-23 08:19:07 +08:00
bool Sprite : : initWithSpriteFrame ( SpriteFrame * spriteFrame )
2012-04-19 14:35:52 +08:00
{
2013-08-23 08:19:07 +08:00
CCASSERT ( spriteFrame ! = NULL , " " ) ;
2012-04-19 14:35:52 +08:00
2013-08-23 08:19:07 +08:00
bool bRet = initWithTexture ( spriteFrame - > getTexture ( ) , spriteFrame - > getRect ( ) ) ;
setDisplayFrame ( spriteFrame ) ;
2012-04-19 14:35:52 +08:00
return bRet ;
}
2013-07-26 06:53:24 +08:00
bool Sprite : : initWithSpriteFrameName ( const char * spriteFrameName )
2012-04-19 14:35:52 +08:00
{
2013-07-26 06:53:24 +08:00
CCASSERT ( spriteFrameName ! = NULL , " " ) ;
2012-04-19 14:35:52 +08:00
2013-08-23 08:19:07 +08:00
SpriteFrame * frame = SpriteFrameCache : : getInstance ( ) - > getSpriteFrameByName ( spriteFrameName ) ;
return initWithSpriteFrame ( frame ) ;
2012-04-19 14:35:52 +08:00
}
// XXX: deprecated
/*
2013-06-20 14:13:12 +08:00
Sprite * Sprite : : initWithCGImage ( CGImageRef pImage )
2012-04-19 14:35:52 +08:00
{
// todo
2012-09-17 15:02:24 +08:00
// because it is deprecated, so we do not implement it
2012-04-19 14:35:52 +08:00
return NULL ;
}
*/
/*
2013-06-20 14:13:12 +08:00
Sprite * Sprite : : initWithCGImage ( CGImageRef pImage , const char * pszKey )
2012-04-19 14:35:52 +08:00
{
2013-07-20 13:01:27 +08:00
CCASSERT ( pImage ! = NULL ) ;
2012-04-19 14:35:52 +08:00
// XXX: possible bug. See issue #349. New API should be added
2013-07-26 06:53:24 +08:00
Texture2D * texture = TextureCache : : getInstance ( ) - > addCGImage ( pImage , pszKey ) ;
2012-04-19 14:35:52 +08:00
2013-07-26 06:53:24 +08:00
const Size & size = texture - > getContentSize ( ) ;
2013-07-12 14:30:26 +08:00
Rect rect = Rect ( 0 , 0 , size . width , size . height ) ;
2012-04-19 14:35:52 +08:00
return initWithTexture ( texture , rect ) ;
}
*/
2013-06-20 14:13:12 +08:00
Sprite : : Sprite ( void )
2013-08-23 08:19:07 +08:00
: _shouldBeHidden ( false )
2013-09-09 16:36:19 +08:00
, _texture ( nullptr )
, _physicsBody ( nullptr )
2012-04-19 14:35:52 +08:00
{
}
2013-06-20 14:13:12 +08:00
Sprite : : ~ Sprite ( void )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
CC_SAFE_RELEASE ( _texture ) ;
2012-04-19 14:35:52 +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
setContentSize ( untrimmedSize ) ;
setVertexRect ( rect ) ;
setTextureCoords ( rect ) ;
2013-06-20 14:13:12 +08:00
Point relativeOffset = _unflippedOffsetPositionFromCenter ;
2012-04-19 14:35:52 +08:00
// issue #732
2013-06-15 14:03:30 +08:00
if ( _flipX )
2012-04-19 14:35:52 +08:00
{
relativeOffset . x = - relativeOffset . x ;
}
2013-06-15 14:03:30 +08:00
if ( _flipY )
2012-04-19 14:35:52 +08:00
{
relativeOffset . y = - relativeOffset . y ;
}
2013-06-15 14:03:30 +08:00
_offsetPosition . x = relativeOffset . x + ( _contentSize . width - _rect . size . width ) / 2 ;
_offsetPosition . y = relativeOffset . y + ( _contentSize . height - _rect . size . height ) / 2 ;
2012-04-19 14:35:52 +08:00
// rendering using batch node
2013-06-15 14:03:30 +08:00
if ( _batchNode )
2012-04-19 14:35:52 +08:00
{
// update dirty_, don't update recursiveDirty_
setDirty ( true ) ;
}
else
{
// self rendering
// Atlas: Vertex
2013-06-15 14:03:30 +08:00
float x1 = 0 + _offsetPosition . x ;
float y1 = 0 + _offsetPosition . y ;
float x2 = x1 + _rect . size . width ;
float y2 = y1 + _rect . size . height ;
2012-04-19 14:35:52 +08:00
// Don't update Z.
2013-07-05 16:49:22 +08:00
_quad . bl . vertices = Vertex3F ( x1 , y1 , 0 ) ;
_quad . br . vertices = Vertex3F ( x2 , y1 , 0 ) ;
_quad . tl . vertices = Vertex3F ( x1 , y2 , 0 ) ;
_quad . tr . vertices = Vertex3F ( x2 , y2 , 0 ) ;
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
}
2013-06-20 14:13:12 +08:00
void Sprite : : setTextureCoords ( Rect rect )
2012-04-19 14:35:52 +08:00
{
rect = CC_RECT_POINTS_TO_PIXELS ( rect ) ;
2013-06-20 14:13:12 +08:00
Texture2D * tex = _batchNode ? _textureAtlas - > getTexture ( ) : _texture ;
2012-04-19 14:35:52 +08:00
if ( ! tex )
{
return ;
}
float atlasWidth = ( float ) tex - > getPixelsWide ( ) ;
float atlasHeight = ( float ) tex - > getPixelsHigh ( ) ;
float left , right , top , bottom ;
2013-06-15 14:03:30 +08:00
if ( _rectRotated )
2012-04-19 14:35:52 +08:00
{
# if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
left = ( 2 * rect . origin . x + 1 ) / ( 2 * atlasWidth ) ;
2013-07-26 06:53:24 +08:00
right = left + ( rect . size . height * 2 - 2 ) / ( 2 * atlasWidth ) ;
top = ( 2 * rect . origin . y + 1 ) / ( 2 * atlasHeight ) ;
bottom = top + ( rect . size . width * 2 - 2 ) / ( 2 * atlasHeight ) ;
2012-04-19 14:35:52 +08:00
# else
left = rect . origin . x / atlasWidth ;
2013-07-26 06:53:24 +08:00
right = ( rect . origin . x + rect . size . height ) / atlasWidth ;
top = rect . origin . y / atlasHeight ;
bottom = ( rect . origin . y + rect . size . width ) / atlasHeight ;
2012-04-19 14:35:52 +08:00
# endif // CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
2013-06-15 14:03:30 +08:00
if ( _flipX )
2012-04-19 14:35:52 +08:00
{
CC_SWAP ( top , bottom , float ) ;
}
2013-06-15 14:03:30 +08:00
if ( _flipY )
2012-04-19 14:35:52 +08:00
{
CC_SWAP ( left , right , float ) ;
}
2013-06-15 14:03:30 +08:00
_quad . bl . texCoords . u = left ;
_quad . bl . texCoords . v = top ;
_quad . br . texCoords . u = left ;
_quad . br . texCoords . v = bottom ;
_quad . tl . texCoords . u = right ;
_quad . tl . texCoords . v = top ;
_quad . tr . texCoords . u = right ;
_quad . tr . texCoords . v = bottom ;
2012-04-19 14:35:52 +08:00
}
else
{
# if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
left = ( 2 * rect . origin . x + 1 ) / ( 2 * atlasWidth ) ;
right = left + ( rect . size . width * 2 - 2 ) / ( 2 * atlasWidth ) ;
top = ( 2 * rect . origin . y + 1 ) / ( 2 * atlasHeight ) ;
bottom = top + ( rect . size . height * 2 - 2 ) / ( 2 * atlasHeight ) ;
# else
left = rect . origin . x / atlasWidth ;
2012-06-08 14:11:48 +08:00
right = ( rect . origin . x + rect . size . width ) / atlasWidth ;
2012-04-19 14:35:52 +08:00
top = rect . origin . y / atlasHeight ;
2012-06-08 14:11:48 +08:00
bottom = ( rect . origin . y + rect . size . height ) / atlasHeight ;
2012-04-19 14:35:52 +08:00
# endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
2013-06-15 14:03:30 +08:00
if ( _flipX )
2012-04-19 14:35:52 +08:00
{
CC_SWAP ( left , right , float ) ;
}
2013-06-15 14:03:30 +08:00
if ( _flipY )
2012-04-19 14:35:52 +08:00
{
CC_SWAP ( top , bottom , float ) ;
}
2013-06-15 14:03:30 +08:00
_quad . bl . texCoords . u = left ;
_quad . bl . texCoords . v = bottom ;
_quad . br . texCoords . u = right ;
_quad . br . texCoords . v = bottom ;
_quad . tl . texCoords . u = left ;
_quad . tl . texCoords . v = top ;
_quad . tr . texCoords . u = right ;
_quad . tr . texCoords . v = top ;
2012-04-19 14:35:52 +08:00
}
}
2013-09-09 16:36:19 +08:00
void Sprite : : setPhysicsBody ( PhysicsBody * body )
{
_physicsBody = body ;
}
PhysicsBody * Sprite : : getPhysicsBody ( ) const
{
return _physicsBody ;
}
2013-06-20 14:13:12 +08:00
void Sprite : : updateTransform ( void )
2012-04-19 14:35:52 +08:00
{
2013-07-20 13:01:27 +08:00
CCASSERT ( _batchNode , " updateTransform is only valid when Sprite is being rendered using an SpriteBatchNode " ) ;
2012-04-19 14:35:52 +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
{
2013-07-05 16:49:22 +08:00
_quad . br . vertices = _quad . tl . vertices = _quad . tr . vertices = _quad . bl . vertices = Vertex3F ( 0 , 0 , 0 ) ;
2013-06-15 14:03:30 +08:00
_shouldBeHidden = true ;
2012-04-19 14:35:52 +08:00
}
else
{
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
}
else
{
2013-07-20 13:01:27 +08:00
CCASSERT ( dynamic_cast < Sprite * > ( _parent ) , " Logic error in Sprite. Parent must be a Sprite " ) ;
2013-08-23 08:19:07 +08:00
_transformToBatch = AffineTransformConcat ( getNodeToParentTransform ( ) , static_cast < Sprite * > ( _parent ) - > _transformToBatch ) ;
2012-04-19 14:35:52 +08:00
}
//
// calculate the Quad based on the Affine Matrix
//
2013-06-20 14:13:12 +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 ;
2013-06-15 14:03:30 +08:00
float x = _transformToBatch . tx ;
float y = _transformToBatch . ty ;
2012-04-19 14:35:52 +08:00
2013-06-15 14:03:30 +08:00
float cr = _transformToBatch . a ;
float sr = _transformToBatch . b ;
float cr2 = _transformToBatch . d ;
float sr2 = - _transformToBatch . c ;
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 ;
2013-07-05 16:49:22 +08:00
_quad . bl . vertices = Vertex3F ( RENDER_IN_SUBPIXEL ( ax ) , RENDER_IN_SUBPIXEL ( ay ) , _vertexZ ) ;
_quad . br . vertices = Vertex3F ( RENDER_IN_SUBPIXEL ( bx ) , RENDER_IN_SUBPIXEL ( by ) , _vertexZ ) ;
_quad . tl . vertices = Vertex3F ( RENDER_IN_SUBPIXEL ( dx ) , RENDER_IN_SUBPIXEL ( dy ) , _vertexZ ) ;
_quad . tr . vertices = Vertex3F ( RENDER_IN_SUBPIXEL ( cx ) , RENDER_IN_SUBPIXEL ( cy ) , _vertexZ ) ;
2012-04-19 14:35:52 +08:00
}
2012-10-19 23:38:58 +08:00
// MARMALADE CHANGE: ADDED CHECK FOR NULL, TO PERMIT SPRITES WITH NO BATCH NODE / TEXTURE ATLAS
2013-06-15 14:03:30 +08:00
if ( _textureAtlas )
2012-11-12 10:20:04 +08:00
{
2013-06-15 14:03:30 +08:00
_textureAtlas - > updateQuad ( & _quad , _atlasIndex ) ;
2012-11-12 10:20:04 +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-06-15 14:03:30 +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-10-30 10:24:28 +08:00
2012-04-19 14:35:52 +08:00
# if CC_SPRITE_DEBUG_DRAW
// draw bounding box
2013-06-20 14:13:12 +08:00
Point vertices [ 4 ] = {
2013-07-12 18:04:32 +08:00
Point ( _quad . bl . vertices . x , _quad . bl . vertices . y ) ,
Point ( _quad . br . vertices . x , _quad . br . vertices . y ) ,
Point ( _quad . tr . vertices . x , _quad . tr . vertices . y ) ,
Point ( _quad . tl . vertices . x , _quad . tl . vertices . y ) ,
2012-04-19 14:35:52 +08:00
} ;
ccDrawPoly ( vertices , 4 , true ) ;
# endif // CC_SPRITE_DEBUG_DRAW
}
// draw
2013-06-20 14:13:12 +08:00
void Sprite : : draw ( void )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
CC_PROFILER_START_CATEGORY ( kProfilerCategorySprite , " CCSprite - draw " ) ;
2012-04-19 14:35:52 +08:00
2013-07-20 13:01:27 +08:00
CCASSERT ( ! _batchNode , " If Sprite is being rendered by SpriteBatchNode, Sprite#draw SHOULD NOT be called " ) ;
2012-04-19 14:35:52 +08:00
2013-07-09 18:33:36 +08:00
CC_NODE_DRAW_SETUP ( ) ;
2013-07-26 09:42:53 +08:00
GL : : blendFunc ( _blendFunc . src , _blendFunc . dst ) ;
2012-04-19 14:35:52 +08:00
2013-07-26 09:42:53 +08:00
GL : : bindTexture2D ( _texture - > getName ( ) ) ;
GL : : enableVertexAttribs ( GL : : VERTEX_ATTRIB_FLAG_POS_COLOR_TEX ) ;
2012-04-19 14:35:52 +08:00
2013-06-15 14:03:30 +08:00
# define kQuadSize sizeof(_quad.bl)
2013-04-05 13:20:59 +08:00
# ifdef EMSCRIPTEN
long offset = 0 ;
2013-06-15 14:03:30 +08:00
setGLBufferData ( & _quad , 4 * kQuadSize , 0 ) ;
2013-04-05 13:20:59 +08:00
# else
2013-06-15 14:03:30 +08:00
long offset = ( long ) & _quad ;
2013-04-05 13:20:59 +08:00
# endif // EMSCRIPTEN
2012-04-19 14:35:52 +08:00
// vertex
2013-07-05 16:49:22 +08:00
int diff = offsetof ( V3F_C4B_T2F , vertices ) ;
2013-07-25 17:48:22 +08:00
glVertexAttribPointer ( GLProgram : : VERTEX_ATTRIB_POSITION , 3 , GL_FLOAT , GL_FALSE , kQuadSize , ( void * ) ( offset + diff ) ) ;
2012-04-19 14:35:52 +08:00
2013-07-09 18:33:36 +08:00
// texCoods
diff = offsetof ( V3F_C4B_T2F , texCoords ) ;
2013-07-25 17:48:22 +08:00
glVertexAttribPointer ( GLProgram : : VERTEX_ATTRIB_TEX_COORDS , 2 , GL_FLOAT , GL_FALSE , kQuadSize , ( void * ) ( offset + diff ) ) ;
2013-06-06 14:41:22 +08:00
2012-04-19 14:35:52 +08:00
// color
2013-07-05 16:49:22 +08:00
diff = offsetof ( V3F_C4B_T2F , colors ) ;
2013-07-25 17:48:22 +08:00
glVertexAttribPointer ( GLProgram : : VERTEX_ATTRIB_COLOR , 4 , GL_UNSIGNED_BYTE , GL_TRUE , kQuadSize , ( void * ) ( offset + diff ) ) ;
2012-04-19 14:35:52 +08:00
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
CHECK_GL_ERROR_DEBUG ( ) ;
# if CC_SPRITE_DEBUG_DRAW == 1
// draw bounding box
2013-06-20 14:13:12 +08:00
Point vertices [ 4 ] = {
2013-07-12 18:04:32 +08:00
Point ( _quad . tl . vertices . x , _quad . tl . vertices . y ) ,
Point ( _quad . bl . vertices . x , _quad . bl . vertices . y ) ,
Point ( _quad . br . vertices . x , _quad . br . vertices . y ) ,
Point ( _quad . tr . vertices . x , _quad . tr . vertices . y ) ,
2012-04-19 14:35:52 +08:00
} ;
ccDrawPoly ( vertices , 4 , true ) ;
# elif CC_SPRITE_DEBUG_DRAW == 2
// draw texture box
2013-06-20 14:13:12 +08:00
Size s = this - > getTextureRect ( ) . size ;
Point offsetPix = this - > getOffsetPosition ( ) ;
Point vertices [ 4 ] = {
2013-07-12 18:04:32 +08:00
Point ( offsetPix . x , offsetPix . y ) , Point ( offsetPix . x + s . width , offsetPix . y ) ,
Point ( offsetPix . x + s . width , offsetPix . y + s . height ) , Point ( offsetPix . x , offsetPix . y + s . height )
2012-04-19 14:35:52 +08:00
} ;
ccDrawPoly ( vertices , 4 , true ) ;
# endif // CC_SPRITE_DEBUG_DRAW
CC_INCREMENT_GL_DRAWS ( 1 ) ;
2013-06-20 14:13:12 +08:00
CC_PROFILER_STOP_CATEGORY ( kProfilerCategorySprite , " CCSprite - draw " ) ;
2012-04-19 14:35:52 +08:00
}
2013-06-20 14:13:12 +08:00
// Node overrides
2012-04-19 14:35:52 +08:00
2013-07-26 07:27:24 +08:00
void Sprite : : addChild ( Node * child )
2012-04-19 14:35:52 +08:00
{
2013-07-26 07:27:24 +08:00
Node : : addChild ( child ) ;
2012-04-19 14:35:52 +08:00
}
2013-07-26 07:27:24 +08:00
void Sprite : : addChild ( Node * child , int zOrder )
2012-04-19 14:35:52 +08:00
{
2013-07-26 07:27:24 +08:00
Node : : addChild ( child , zOrder ) ;
2012-04-19 14:35:52 +08:00
}
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-07-26 07:27:24 +08:00
CCASSERT ( child ! = NULL , " Argument must be non-NULL " ) ;
2012-04-19 14:35:52 +08:00
2013-06-15 14:03:30 +08:00
if ( _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 " ) ;
CCASSERT ( childSprite - > getTexture ( ) - > getName ( ) = = _textureAtlas - > getTexture ( ) - > getName ( ) , " " ) ;
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 ) ;
2013-06-15 14:03:30 +08:00
_hasChildren = true ;
2012-04-19 14:35:52 +08:00
}
2013-07-26 07:27:24 +08:00
void Sprite : : reorderChild ( Node * child , int zOrder )
2012-04-19 14:35:52 +08:00
{
2013-07-26 07:27:24 +08:00
CCASSERT ( child ! = NULL , " " ) ;
CCASSERT ( _children - > containsObject ( child ) , " " ) ;
2012-04-19 14:35:52 +08:00
2013-07-26 07:27:24 +08:00
if ( zOrder = = child - > getZOrder ( ) )
2012-04-19 14:35:52 +08:00
{
return ;
}
2013-06-15 14:03:30 +08:00
if ( _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
{
2013-06-15 14:03:30 +08:00
if ( _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
{
2013-06-15 14:03:30 +08:00
if ( _batchNode )
2012-04-19 14:35:52 +08:00
{
2013-08-23 08:19:07 +08:00
Object * object = NULL ;
CCARRAY_FOREACH ( _children , object )
2012-04-19 14:35:52 +08:00
{
2013-08-23 08:19:07 +08:00
Sprite * child = dynamic_cast < Sprite * > ( object ) ;
2013-07-26 07:27:24 +08:00
if ( child )
2012-04-19 14:35:52 +08:00
{
2013-07-26 07:27:24 +08:00
_batchNode - > removeSpriteFromAtlas ( child ) ;
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-15 14:03:30 +08:00
_hasChildren = false ;
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
{
2013-09-01 06:18:28 +08:00
#if 0
2013-08-20 08:09:28 +08:00
int i = 0 , j = 0 , length = _children - > count ( ) ;
2012-04-19 14:35:52 +08:00
// insertion sort
for ( i = 1 ; i < length ; i + + )
{
j = i - 1 ;
2013-08-20 08:27:31 +08:00
auto tempI = static_cast < Node * > ( _children - > getObjectAtIndex ( i ) ) ;
auto tempJ = static_cast < Node * > ( _children - > getObjectAtIndex ( j ) ) ;
2012-04-19 14:35:52 +08:00
2013-08-20 08:09:28 +08:00
//continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller
while ( j > = 0 & & ( tempI - > getZOrder ( ) < tempJ - > getZOrder ( ) | |
( tempI - > getZOrder ( ) = = tempJ - > getZOrder ( ) & &
tempI - > getOrderOfArrival ( ) < tempJ - > getOrderOfArrival ( ) ) ) )
2012-04-19 14:35:52 +08:00
{
2013-08-20 08:09:28 +08:00
_children - > fastSetObject ( tempJ , j + 1 ) ;
2012-04-19 14:35:52 +08:00
j = j - 1 ;
2013-08-20 08:27:31 +08:00
if ( j > = 0 )
tempJ = static_cast < Node * > ( _children - > getObjectAtIndex ( j ) ) ;
2012-04-19 14:35:52 +08:00
}
2013-08-20 08:09:28 +08:00
_children - > fastSetObject ( tempI , j + 1 ) ;
2012-04-19 14:35:52 +08:00
}
2013-09-01 06:18:28 +08:00
# else
std : : sort ( std : : begin ( * _children ) , std : : end ( * _children ) , nodeComparisonLess ) ;
# endif
2012-04-19 14:35:52 +08:00
2013-06-15 14:03:30 +08:00
if ( _batchNode )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
arrayMakeObjectsPerformSelector ( _children , sortAllChildren , Sprite * ) ;
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 ) ;
// recursively set dirty
2013-06-15 14:03:30 +08:00
if ( _hasChildren )
2012-04-19 14:35:52 +08:00
{
2013-08-23 08:19:07 +08:00
Object * object = NULL ;
CCARRAY_FOREACH ( _children , object )
2012-04-19 14:35:52 +08:00
{
2013-08-23 08:19:07 +08:00
Sprite * child = dynamic_cast < Sprite * > ( object ) ;
2013-07-26 07:27:24 +08:00
if ( child )
2012-04-19 14:35:52 +08:00
{
2013-07-26 07:27:24 +08:00
child - > setDirtyRecursively ( true ) ;
2012-04-19 14:35:52 +08:00
}
}
}
}
// XXX HACK: optimization
# define SET_DIRTY_RECURSIVELY() { \
2013-06-15 14:03:30 +08:00
if ( _batchNode & & ! _recursiveDirty ) { \
_recursiveDirty = true ; \
2012-04-19 14:35:52 +08:00
setDirty ( true ) ; \
2013-06-15 14:03:30 +08:00
if ( _hasChildren ) \
2012-04-19 14:35:52 +08:00
setDirtyRecursively ( true ) ; \
} \
}
2013-06-20 14:13:12 +08:00
void Sprite : : setPosition ( const Point & 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-06-20 14:13:12 +08:00
void Sprite : : setRotation ( float fRotation )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
Node : : setRotation ( fRotation ) ;
2012-04-19 14:35:52 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2013-06-20 14:13:12 +08:00
void Sprite : : setRotationX ( float fRotationX )
2012-11-14 18:05:15 +08:00
{
2013-06-20 14:13:12 +08:00
Node : : setRotationX ( fRotationX ) ;
2012-11-14 18:05:15 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2013-06-20 14:13:12 +08:00
void Sprite : : setRotationY ( float fRotationY )
2012-11-14 18:05:15 +08:00
{
2013-06-20 14:13:12 +08:00
Node : : setRotationY ( 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-06-20 14:13:12 +08:00
void Sprite : : setVertexZ ( float fVertexZ )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
Node : : setVertexZ ( fVertexZ ) ;
2012-04-19 14:35:52 +08:00
SET_DIRTY_RECURSIVELY ( ) ;
}
2013-06-20 14:13:12 +08:00
void Sprite : : setAnchorPoint ( const Point & 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 ( ) ;
}
2013-06-20 14:13:12 +08:00
void Sprite : : ignoreAnchorPointForPosition ( bool value )
2012-04-19 14:35:52 +08:00
{
2013-07-20 13:01:27 +08:00
CCASSERT ( ! _batchNode , " ignoreAnchorPointForPosition is invalid in Sprite " ) ;
2013-06-20 14:13:12 +08:00
Node : : ignoreAnchorPointForPosition ( 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 ( ) ;
}
2013-06-20 14:13:12 +08:00
void Sprite : : setFlipX ( bool bFlipX )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
if ( _flipX ! = bFlipX )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
_flipX = bFlipX ;
setTextureRect ( _rect , _rectRotated , _contentSize ) ;
2012-04-19 14:35:52 +08:00
}
}
2013-07-04 08:44:41 +08:00
bool Sprite : : isFlipX ( void ) const
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
return _flipX ;
2012-04-19 14:35:52 +08:00
}
2013-06-20 14:13:12 +08:00
void Sprite : : setFlipY ( bool bFlipY )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
if ( _flipY ! = bFlipY )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
_flipY = bFlipY ;
setTextureRect ( _rect , _rectRotated , _contentSize ) ;
2012-04-19 14:35:52 +08:00
}
}
2013-07-04 08:44:41 +08:00
bool Sprite : : isFlipY ( void ) const
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
return _flipY ;
2012-04-19 14:35:52 +08:00
}
//
// RGBA protocol
//
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 ) ;
2013-02-27 15:30:49 +08:00
// special opacity for premultiplied textures
2013-06-15 14:03:30 +08:00
if ( _opacityModifyRGB )
2013-02-27 15:30:49 +08:00
{
color4 . r * = _displayedOpacity / 255.0f ;
color4 . g * = _displayedOpacity / 255.0f ;
color4 . b * = _displayedOpacity / 255.0f ;
}
2012-04-19 14:35:52 +08:00
2013-06-15 14:03:30 +08:00
_quad . bl . colors = color4 ;
_quad . br . colors = color4 ;
_quad . tl . colors = color4 ;
_quad . tr . colors = color4 ;
2012-04-19 14:35:52 +08:00
// renders using batch node
2013-06-15 14:03:30 +08:00
if ( _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 : : setOpacity ( GLubyte opacity )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
NodeRGBA : : setOpacity ( opacity ) ;
2012-04-19 14:35:52 +08:00
updateColor ( ) ;
}
2013-07-05 16:49:22 +08:00
void Sprite : : setColor ( const Color3B & color3 )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
NodeRGBA : : setColor ( color3 ) ;
2012-04-19 14:35:52 +08:00
2013-02-27 15:30:49 +08:00
updateColor ( ) ;
2012-04-19 14:35:52 +08:00
}
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
}
2013-07-05 16:49:22 +08:00
void Sprite : : updateDisplayedColor ( const Color3B & parentColor )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
NodeRGBA : : updateDisplayedColor ( parentColor ) ;
2013-02-27 15:30:49 +08:00
updateColor ( ) ;
2012-04-19 14:35:52 +08:00
}
2013-06-20 14:13:12 +08:00
void Sprite : : updateDisplayedOpacity ( GLubyte opacity )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
NodeRGBA : : updateDisplayedOpacity ( opacity ) ;
2013-02-27 15:30:49 +08:00
updateColor ( ) ;
2012-04-19 14:35:52 +08:00
}
// Frames
2013-06-20 14:13:12 +08:00
void Sprite : : setDisplayFrame ( SpriteFrame * pNewFrame )
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
_unflippedOffsetPositionFromCenter = pNewFrame - > getOffset ( ) ;
2012-04-19 14:35:52 +08:00
2013-06-20 14:13:12 +08:00
Texture2D * pNewTexture = pNewFrame - > getTexture ( ) ;
2012-04-19 14:35:52 +08:00
// update texture before updating texture rect
2013-06-15 14:03:30 +08:00
if ( pNewTexture ! = _texture )
2012-04-19 14:35:52 +08:00
{
setTexture ( pNewTexture ) ;
}
// update rect
2013-06-15 14:03:30 +08:00
_rectRotated = pNewFrame - > isRotated ( ) ;
setTextureRect ( pNewFrame - > getRect ( ) , _rectRotated , pNewFrame - > getOriginalSize ( ) ) ;
2012-04-19 14:35:52 +08:00
}
2013-06-20 14:13:12 +08:00
void Sprite : : setDisplayFrameWithAnimationName ( const char * animationName , int frameIndex )
2012-04-19 14:35:52 +08:00
{
2013-07-20 13:01:27 +08:00
CCASSERT ( animationName , " CCSprite#setDisplayFrameWithAnimationName. animationName must not be NULL " ) ;
2012-04-19 14:35:52 +08:00
2013-07-12 06:24:23 +08:00
Animation * a = AnimationCache : : getInstance ( ) - > animationByName ( 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-08-22 10:45:47 +08:00
AnimationFrame * frame = static_cast < AnimationFrame * > ( a - > getFrames ( ) - > getObjectAtIndex ( 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
setDisplayFrame ( frame - > getSpriteFrame ( ) ) ;
}
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-08-28 18:17:05 +08:00
SpriteFrame * Sprite : : getDisplayFrame ( )
2012-04-19 14:35:52 +08:00
{
2013-06-20 14:13:12 +08:00
return SpriteFrame : : createWithTexture ( _texture ,
2013-06-15 14:03:30 +08:00
CC_RECT_POINTS_TO_PIXELS ( _rect ) ,
_rectRotated ,
CC_POINT_POINTS_TO_PIXELS ( _unflippedOffsetPositionFromCenter ) ,
CC_SIZE_POINTS_TO_PIXELS ( _contentSize ) ) ;
2012-04-19 14:35:52 +08:00
}
2013-08-28 18:17:05 +08:00
SpriteBatchNode * Sprite : : getBatchNode ( )
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 ) {
2013-09-01 01:38:10 +08:00
_atlasIndex = INDEX_NOT_INITIALIZED ;
2012-04-19 14:35:52 +08:00
setTextureAtlas ( NULL ) ;
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 ;
2013-07-05 16:49:22 +08:00
_quad . bl . vertices = Vertex3F ( x1 , y1 , 0 ) ;
_quad . br . vertices = Vertex3F ( x2 , y1 , 0 ) ;
_quad . tl . vertices = Vertex3F ( x1 , y2 , 0 ) ;
_quad . tr . vertices = Vertex3F ( x2 , y2 , 0 ) ;
2012-04-19 14:35:52 +08:00
} else {
// using batch
2013-06-20 14:13:12 +08:00
_transformToBatch = AffineTransformIdentity ;
2013-06-15 14:03:30 +08:00
setTextureAtlas ( _batchNode - > getTextureAtlas ( ) ) ; // weak ref
2012-04-19 14:35:52 +08:00
}
}
// Texture protocol
2013-06-20 14:13:12 +08:00
void Sprite : : updateBlendFunc ( void )
2012-04-19 14:35:52 +08:00
{
2013-07-20 13:01:27 +08:00
CCASSERT ( ! _batchNode , " CCSprite: updateBlendFunc doesn't work when the sprite is rendered using a SpriteBatchNode " ) ;
2012-04-19 14:35:52 +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-07-10 11:57:35 +08:00
/*
* This array is the data of a white image with 2 by 2 dimension .
* It ' s used for creating a default texture when sprite ' s texture is set to NULL .
* Supposing codes as follows :
*
* auto sp = new Sprite ( ) ;
* sp - > init ( ) ; // Texture was set to NULL, in order to make opacity and color to work correctly, we need to create a 2x2 white texture.
*
* The test is in " TestCpp/SpriteTest/Sprite without texture " .
*/
2013-07-09 18:33:36 +08:00
static unsigned char cc_2x2_white_image [ ] = {
// RGBA8888
0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF ,
0xFF , 0xFF , 0xFF , 0xFF
} ;
2013-07-10 10:07:45 +08:00
# define CC_2x2_WHITE_IMAGE_KEY "cc_2x2_white_image"
2013-06-20 14:13:12 +08:00
void Sprite : : setTexture ( Texture2D * texture )
2012-04-19 14:35:52 +08:00
{
2012-06-08 14:11:48 +08:00
// If batchnode, then texture id should be the same
2013-07-20 13:01:27 +08:00
CCASSERT ( ! _batchNode | | texture - > getName ( ) = = _batchNode - > getTexture ( ) - > getName ( ) , " CCSprite: Batched sprites should use the same texture as the batchnode " ) ;
2012-04-19 14:35:52 +08:00
// accept texture==nil as argument
2013-07-20 13:01:27 +08:00
CCASSERT ( ! texture | | dynamic_cast < Texture2D * > ( texture ) , " setTexture expects a Texture2D. Invalid argument " ) ;
2013-06-06 14:22:09 +08:00
2013-07-10 10:07:45 +08:00
if ( NULL = = texture )
2013-07-09 18:33:36 +08:00
{
2013-07-10 10:07:45 +08:00
// Gets the texture by key firstly.
2013-07-12 06:24:23 +08:00
texture = TextureCache : : getInstance ( ) - > textureForKey ( CC_2x2_WHITE_IMAGE_KEY ) ;
2013-07-09 18:33:36 +08:00
2013-07-10 10:07:45 +08:00
// If texture wasn't in cache, create it from RAW data.
if ( NULL = = texture )
{
Image * image = new Image ( ) ;
2013-07-25 21:35:00 +08:00
bool isOK = image - > initWithRawData ( cc_2x2_white_image , sizeof ( cc_2x2_white_image ) , 2 , 2 , 8 ) ;
2013-09-01 01:38:10 +08:00
CCASSERT ( isOK , " The 2x2 empty texture was created unsuccessfully. " ) ;
2013-07-12 16:36:19 +08:00
texture = TextureCache : : getInstance ( ) - > addUIImage ( image , CC_2x2_WHITE_IMAGE_KEY ) ;
2013-07-10 10:07:45 +08:00
CC_SAFE_RELEASE ( image ) ;
}
2013-07-09 18:33:36 +08:00
}
2013-06-15 14:03:30 +08:00
if ( ! _batchNode & & _texture ! = texture )
2012-04-19 14:35:52 +08:00
{
CC_SAFE_RETAIN ( texture ) ;
2013-06-15 14:03:30 +08:00
CC_SAFE_RELEASE ( _texture ) ;
_texture = texture ;
2012-04-19 14:35:52 +08:00
updateBlendFunc ( ) ;
}
}
2013-07-23 18:26:26 +08:00
Texture2D * Sprite : : getTexture ( void ) const
2012-04-19 14:35:52 +08:00
{
2013-06-15 14:03:30 +08:00
return _texture ;
2012-04-19 14:35:52 +08:00
}
NS_CC_END