diff options
| author | Starla Insigna <starla4444@gmail.com> | 2011-07-30 11:19:14 -0400 |
|---|---|---|
| committer | Starla Insigna <starla4444@gmail.com> | 2011-07-30 11:19:14 -0400 |
| commit | 9cd57b731ab1c666d4a1cb725538fdc137763d12 (patch) | |
| tree | 5bac45ae5157a1cb10c6e45500cbf72789917980 /libs/cocos2d/CCSprite.m | |
| download | cartcollect-9cd57b731ab1c666d4a1cb725538fdc137763d12.tar.gz cartcollect-9cd57b731ab1c666d4a1cb725538fdc137763d12.tar.bz2 cartcollect-9cd57b731ab1c666d4a1cb725538fdc137763d12.zip | |
Initial commit (version 0.2.1)
Diffstat (limited to 'libs/cocos2d/CCSprite.m')
| -rwxr-xr-x | libs/cocos2d/CCSprite.m | 1029 |
1 files changed, 1029 insertions, 0 deletions
| diff --git a/libs/cocos2d/CCSprite.m b/libs/cocos2d/CCSprite.m new file mode 100755 index 0000000..37f06d2 --- /dev/null +++ b/libs/cocos2d/CCSprite.m | |||
| @@ -0,0 +1,1029 @@ | |||
| 1 | /* | ||
| 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | * Copyright (c) 2008-2010 Ricardo Quesada | ||
| 5 | * Copyright (c) 2011 Zynga Inc. | ||
| 6 | * | ||
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 8 | * of this software and associated documentation files (the "Software"), to deal | ||
| 9 | * in the Software without restriction, including without limitation the rights | ||
| 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 11 | * copies of the Software, and to permit persons to whom the Software is | ||
| 12 | * furnished to do so, subject to the following conditions: | ||
| 13 | * | ||
| 14 | * The above copyright notice and this permission notice shall be included in | ||
| 15 | * all copies or substantial portions of the Software. | ||
| 16 | * | ||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 23 | * THE SOFTWARE. | ||
| 24 | * | ||
| 25 | */ | ||
| 26 | |||
| 27 | #import <Availability.h> | ||
| 28 | |||
| 29 | #import "ccConfig.h" | ||
| 30 | #import "CCSpriteBatchNode.h" | ||
| 31 | #import "CCSprite.h" | ||
| 32 | #import "CCSpriteFrame.h" | ||
| 33 | #import "CCSpriteFrameCache.h" | ||
| 34 | #import "CCAnimation.h" | ||
| 35 | #import "CCAnimationCache.h" | ||
| 36 | #import "CCTextureCache.h" | ||
| 37 | #import "Support/CGPointExtension.h" | ||
| 38 | #import "CCDrawingPrimitives.h" | ||
| 39 | |||
| 40 | #pragma mark - | ||
| 41 | #pragma mark CCSprite | ||
| 42 | |||
| 43 | #if CC_SPRITEBATCHNODE_RENDER_SUBPIXEL | ||
| 44 | #define RENDER_IN_SUBPIXEL | ||
| 45 | #else | ||
| 46 | #define RENDER_IN_SUBPIXEL(__A__) ( (int)(__A__)) | ||
| 47 | #endif | ||
| 48 | |||
| 49 | // XXX: Optmization | ||
| 50 | struct transformValues_ { | ||
| 51 | CGPoint pos; // position x and y | ||
| 52 | CGPoint scale; // scale x and y | ||
| 53 | float rotation; | ||
| 54 | CGPoint skew; // skew x and y | ||
| 55 | CGPoint ap; // anchor point in pixels | ||
| 56 | BOOL visible; | ||
| 57 | }; | ||
| 58 | |||
| 59 | @interface CCSprite (Private) | ||
| 60 | -(void)updateTextureCoords:(CGRect)rect; | ||
| 61 | -(void)updateBlendFunc; | ||
| 62 | -(void) initAnimationDictionary; | ||
| 63 | -(void) getTransformValues:(struct transformValues_*)tv; // optimization | ||
| 64 | @end | ||
| 65 | |||
| 66 | @implementation CCSprite | ||
| 67 | |||
| 68 | @synthesize dirty = dirty_; | ||
| 69 | @synthesize quad = quad_; | ||
| 70 | @synthesize atlasIndex = atlasIndex_; | ||
| 71 | @synthesize textureRect = rect_; | ||
| 72 | @synthesize textureRectRotated = rectRotated_; | ||
| 73 | @synthesize blendFunc = blendFunc_; | ||
| 74 | @synthesize usesBatchNode = usesBatchNode_; | ||
| 75 | @synthesize textureAtlas = textureAtlas_; | ||
| 76 | @synthesize batchNode = batchNode_; | ||
| 77 | @synthesize honorParentTransform = honorParentTransform_; | ||
| 78 | @synthesize offsetPositionInPixels = offsetPositionInPixels_; | ||
| 79 | |||
| 80 | |||
| 81 | +(id)spriteWithTexture:(CCTexture2D*)texture | ||
| 82 | { | ||
| 83 | return [[[self alloc] initWithTexture:texture] autorelease]; | ||
| 84 | } | ||
| 85 | |||
| 86 | +(id)spriteWithTexture:(CCTexture2D*)texture rect:(CGRect)rect | ||
| 87 | { | ||
| 88 | return [[[self alloc] initWithTexture:texture rect:rect] autorelease]; | ||
| 89 | } | ||
| 90 | |||
| 91 | +(id)spriteWithFile:(NSString*)filename | ||
| 92 | { | ||
| 93 | return [[[self alloc] initWithFile:filename] autorelease]; | ||
| 94 | } | ||
| 95 | |||
| 96 | +(id)spriteWithFile:(NSString*)filename rect:(CGRect)rect | ||
| 97 | { | ||
| 98 | return [[[self alloc] initWithFile:filename rect:rect] autorelease]; | ||
| 99 | } | ||
| 100 | |||
| 101 | +(id)spriteWithSpriteFrame:(CCSpriteFrame*)spriteFrame | ||
| 102 | { | ||
| 103 | return [[[self alloc] initWithSpriteFrame:spriteFrame] autorelease]; | ||
| 104 | } | ||
| 105 | |||
| 106 | +(id)spriteWithSpriteFrameName:(NSString*)spriteFrameName | ||
| 107 | { | ||
| 108 | CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:spriteFrameName]; | ||
| 109 | |||
| 110 | NSAssert1(frame!=nil, @"Invalid spriteFrameName: %@", spriteFrameName); | ||
| 111 | return [self spriteWithSpriteFrame:frame]; | ||
| 112 | } | ||
| 113 | |||
| 114 | +(id)spriteWithCGImage:(CGImageRef)image key:(NSString*)key | ||
| 115 | { | ||
| 116 | return [[[self alloc] initWithCGImage:image key:key] autorelease]; | ||
| 117 | } | ||
| 118 | |||
| 119 | +(id) spriteWithBatchNode:(CCSpriteBatchNode*)batchNode rect:(CGRect)rect | ||
| 120 | { | ||
| 121 | return [[[self alloc] initWithBatchNode:batchNode rect:rect] autorelease]; | ||
| 122 | } | ||
| 123 | |||
| 124 | -(id) init | ||
| 125 | { | ||
| 126 | if( (self=[super init]) ) { | ||
| 127 | dirty_ = recursiveDirty_ = NO; | ||
| 128 | |||
| 129 | // by default use "Self Render". | ||
| 130 | // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" | ||
| 131 | [self useSelfRender]; | ||
| 132 | |||
| 133 | opacityModifyRGB_ = YES; | ||
| 134 | opacity_ = 255; | ||
| 135 | color_ = colorUnmodified_ = ccWHITE; | ||
| 136 | |||
| 137 | blendFunc_.src = CC_BLEND_SRC; | ||
| 138 | blendFunc_.dst = CC_BLEND_DST; | ||
| 139 | |||
| 140 | // update texture (calls updateBlendFunc) | ||
| 141 | [self setTexture:nil]; | ||
| 142 | |||
| 143 | // clean the Quad | ||
| 144 | bzero(&quad_, sizeof(quad_)); | ||
| 145 | |||
| 146 | flipY_ = flipX_ = NO; | ||
| 147 | |||
| 148 | // lazy alloc | ||
| 149 | animations_ = nil; | ||
| 150 | |||
| 151 | // default transform anchor: center | ||
| 152 | anchorPoint_ = ccp(0.5f, 0.5f); | ||
| 153 | |||
| 154 | // zwoptex default values | ||
| 155 | offsetPositionInPixels_ = CGPointZero; | ||
| 156 | |||
| 157 | honorParentTransform_ = CC_HONOR_PARENT_TRANSFORM_ALL; | ||
| 158 | hasChildren_ = NO; | ||
| 159 | |||
| 160 | // Atlas: Color | ||
| 161 | ccColor4B tmpColor = {255,255,255,255}; | ||
| 162 | quad_.bl.colors = tmpColor; | ||
| 163 | quad_.br.colors = tmpColor; | ||
| 164 | quad_.tl.colors = tmpColor; | ||
| 165 | quad_.tr.colors = tmpColor; | ||
| 166 | |||
| 167 | // Atlas: Vertex | ||
| 168 | |||
| 169 | // updated in "useSelfRender" | ||
| 170 | |||
| 171 | // Atlas: TexCoords | ||
| 172 | [self setTextureRectInPixels:CGRectZero rotated:NO untrimmedSize:CGSizeZero]; | ||
| 173 | |||
| 174 | // updateMethod selector | ||
| 175 | updateMethod = (__typeof__(updateMethod))[self methodForSelector:@selector(updateTransform)]; | ||
| 176 | } | ||
| 177 | |||
| 178 | return self; | ||
| 179 | } | ||
| 180 | |||
| 181 | -(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect | ||
| 182 | { | ||
| 183 | NSAssert(texture!=nil, @"Invalid texture for sprite"); | ||
| 184 | // IMPORTANT: [self init] and not [super init]; | ||
| 185 | if( (self = [self init]) ) | ||
| 186 | { | ||
| 187 | [self setTexture:texture]; | ||
| 188 | [self setTextureRect:rect]; | ||
| 189 | } | ||
| 190 | return self; | ||
| 191 | } | ||
| 192 | |||
| 193 | -(id) initWithTexture:(CCTexture2D*)texture | ||
| 194 | { | ||
| 195 | NSAssert(texture!=nil, @"Invalid texture for sprite"); | ||
| 196 | |||
| 197 | CGRect rect = CGRectZero; | ||
| 198 | rect.size = texture.contentSize; | ||
| 199 | return [self initWithTexture:texture rect:rect]; | ||
| 200 | } | ||
| 201 | |||
| 202 | -(id) initWithFile:(NSString*)filename | ||
| 203 | { | ||
| 204 | NSAssert(filename!=nil, @"Invalid filename for sprite"); | ||
| 205 | |||
| 206 | CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage: filename]; | ||
| 207 | if( texture ) { | ||
| 208 | CGRect rect = CGRectZero; | ||
| 209 | rect.size = texture.contentSize; | ||
| 210 | return [self initWithTexture:texture rect:rect]; | ||
| 211 | } | ||
| 212 | |||
| 213 | [self release]; | ||
| 214 | return nil; | ||
| 215 | } | ||
| 216 | |||
| 217 | -(id) initWithFile:(NSString*)filename rect:(CGRect)rect | ||
| 218 | { | ||
| 219 | NSAssert(filename!=nil, @"Invalid filename for sprite"); | ||
| 220 | |||
| 221 | CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage: filename]; | ||
| 222 | if( texture ) | ||
| 223 | return [self initWithTexture:texture rect:rect]; | ||
| 224 | |||
| 225 | [self release]; | ||
| 226 | return nil; | ||
| 227 | } | ||
| 228 | |||
| 229 | - (id) initWithSpriteFrame:(CCSpriteFrame*)spriteFrame | ||
| 230 | { | ||
| 231 | NSAssert(spriteFrame!=nil, @"Invalid spriteFrame for sprite"); | ||
| 232 | |||
| 233 | id ret = [self initWithTexture:spriteFrame.texture rect:spriteFrame.rect]; | ||
| 234 | [self setDisplayFrame:spriteFrame]; | ||
| 235 | return ret; | ||
| 236 | } | ||
| 237 | |||
| 238 | -(id)initWithSpriteFrameName:(NSString*)spriteFrameName | ||
| 239 | { | ||
| 240 | NSAssert(spriteFrameName!=nil, @"Invalid spriteFrameName for sprite"); | ||
| 241 | |||
| 242 | CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:spriteFrameName]; | ||
| 243 | return [self initWithSpriteFrame:frame]; | ||
| 244 | } | ||
| 245 | |||
| 246 | // XXX: deprecated | ||
| 247 | - (id) initWithCGImage: (CGImageRef)image | ||
| 248 | { | ||
| 249 | NSAssert(image!=nil, @"Invalid CGImageRef for sprite"); | ||
| 250 | |||
| 251 | // XXX: possible bug. See issue #349. New API should be added | ||
| 252 | NSString *key = [NSString stringWithFormat:@"%08X",(unsigned long)image]; | ||
| 253 | CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addCGImage:image forKey:key]; | ||
| 254 | |||
| 255 | CGRect rect = CGRectZero; | ||
| 256 | rect.size = texture.contentSize; | ||
| 257 | |||
| 258 | return [self initWithTexture:texture rect:rect]; | ||
| 259 | } | ||
| 260 | |||
| 261 | - (id) initWithCGImage:(CGImageRef)image key:(NSString*)key | ||
| 262 | { | ||
| 263 | NSAssert(image!=nil, @"Invalid CGImageRef for sprite"); | ||
| 264 | |||
| 265 | // XXX: possible bug. See issue #349. New API should be added | ||
| 266 | CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addCGImage:image forKey:key]; | ||
| 267 | |||
| 268 | CGRect rect = CGRectZero; | ||
| 269 | rect.size = texture.contentSize; | ||
| 270 | |||
| 271 | return [self initWithTexture:texture rect:rect]; | ||
| 272 | } | ||
| 273 | |||
| 274 | -(id) initWithBatchNode:(CCSpriteBatchNode*)batchNode rect:(CGRect)rect | ||
| 275 | { | ||
| 276 | id ret = [self initWithTexture:batchNode.texture rect:rect]; | ||
| 277 | [self useBatchNode:batchNode]; | ||
| 278 | |||
| 279 | return ret; | ||
| 280 | } | ||
| 281 | |||
| 282 | -(id) initWithBatchNode:(CCSpriteBatchNode*)batchNode rectInPixels:(CGRect)rect | ||
| 283 | { | ||
| 284 | id ret = [self initWithTexture:batchNode.texture]; | ||
| 285 | [self setTextureRectInPixels:rect rotated:NO untrimmedSize:rect.size]; | ||
| 286 | [self useBatchNode:batchNode]; | ||
| 287 | |||
| 288 | return ret; | ||
| 289 | } | ||
| 290 | |||
| 291 | - (NSString*) description | ||
| 292 | { | ||
| 293 | return [NSString stringWithFormat:@"<%@ = %08X | Rect = (%.2f,%.2f,%.2f,%.2f) | tag = %i | atlasIndex = %i>", [self class], self, | ||
| 294 | rect_.origin.x, rect_.origin.y, rect_.size.width, rect_.size.height, | ||
| 295 | tag_, | ||
| 296 | atlasIndex_ | ||
| 297 | ]; | ||
| 298 | } | ||
| 299 | |||
| 300 | - (void) dealloc | ||
| 301 | { | ||
| 302 | [texture_ release]; | ||
| 303 | [animations_ release]; | ||
| 304 | [super dealloc]; | ||
| 305 | } | ||
| 306 | |||
| 307 | -(void) useSelfRender | ||
| 308 | { | ||
| 309 | atlasIndex_ = CCSpriteIndexNotInitialized; | ||
| 310 | usesBatchNode_ = NO; | ||
| 311 | textureAtlas_ = nil; | ||
| 312 | batchNode_ = nil; | ||
| 313 | dirty_ = recursiveDirty_ = NO; | ||
| 314 | |||
| 315 | float x1 = 0 + offsetPositionInPixels_.x; | ||
| 316 | float y1 = 0 + offsetPositionInPixels_.y; | ||
| 317 | float x2 = x1 + rectInPixels_.size.width; | ||
| 318 | float y2 = y1 + rectInPixels_.size.height; | ||
| 319 | quad_.bl.vertices = (ccVertex3F) { x1, y1, 0 }; | ||
| 320 | quad_.br.vertices = (ccVertex3F) { x2, y1, 0 }; | ||
| 321 | quad_.tl.vertices = (ccVertex3F) { x1, y2, 0 }; | ||
| 322 | quad_.tr.vertices = (ccVertex3F) { x2, y2, 0 }; | ||
| 323 | } | ||
| 324 | |||
| 325 | -(void) useBatchNode:(CCSpriteBatchNode*)batchNode | ||
| 326 | { | ||
| 327 | usesBatchNode_ = YES; | ||
| 328 | textureAtlas_ = [batchNode textureAtlas]; // weak ref | ||
| 329 | batchNode_ = batchNode; // weak ref | ||
| 330 | } | ||
| 331 | |||
| 332 | -(void) initAnimationDictionary | ||
| 333 | { | ||
| 334 | animations_ = [[NSMutableDictionary alloc] initWithCapacity:2]; | ||
| 335 | } | ||
| 336 | |||
| 337 | -(void)setTextureRect:(CGRect)rect | ||
| 338 | { | ||
| 339 | CGRect rectInPixels = CC_RECT_POINTS_TO_PIXELS( rect ); | ||
| 340 | [self setTextureRectInPixels:rectInPixels rotated:NO untrimmedSize:rectInPixels.size]; | ||
| 341 | } | ||
| 342 | |||
| 343 | -(void)setTextureRectInPixels:(CGRect)rect rotated:(BOOL)rotated untrimmedSize:(CGSize)untrimmedSize | ||
| 344 | { | ||
| 345 | rectInPixels_ = rect; | ||
| 346 | rect_ = CC_RECT_PIXELS_TO_POINTS( rect ); | ||
| 347 | rectRotated_ = rotated; | ||
| 348 | |||
| 349 | [self setContentSizeInPixels:untrimmedSize]; | ||
| 350 | [self updateTextureCoords:rectInPixels_]; | ||
| 351 | |||
| 352 | CGPoint relativeOffsetInPixels = unflippedOffsetPositionFromCenter_; | ||
| 353 | |||
| 354 | // issue #732 | ||
| 355 | if( flipX_ ) | ||
| 356 | relativeOffsetInPixels.x = -relativeOffsetInPixels.x; | ||
| 357 | if( flipY_ ) | ||
| 358 | relativeOffsetInPixels.y = -relativeOffsetInPixels.y; | ||
| 359 | |||
| 360 | offsetPositionInPixels_.x = relativeOffsetInPixels.x + (contentSizeInPixels_.width - rectInPixels_.size.width) / 2; | ||
| 361 | offsetPositionInPixels_.y = relativeOffsetInPixels.y + (contentSizeInPixels_.height - rectInPixels_.size.height) / 2; | ||
| 362 | |||
| 363 | |||
| 364 | // rendering using batch node | ||
| 365 | if( usesBatchNode_ ) { | ||
| 366 | // update dirty_, don't update recursiveDirty_ | ||
| 367 | dirty_ = YES; | ||
| 368 | } | ||
| 369 | |||
| 370 | // self rendering | ||
| 371 | else | ||
| 372 | { | ||
| 373 | // Atlas: Vertex | ||
| 374 | float x1 = 0 + offsetPositionInPixels_.x; | ||
| 375 | float y1 = 0 + offsetPositionInPixels_.y; | ||
| 376 | float x2 = x1 + rectInPixels_.size.width; | ||
| 377 | float y2 = y1 + rectInPixels_.size.height; | ||
| 378 | |||
| 379 | // Don't update Z. | ||
| 380 | quad_.bl.vertices = (ccVertex3F) { x1, y1, 0 }; | ||
| 381 | quad_.br.vertices = (ccVertex3F) { x2, y1, 0 }; | ||
| 382 | quad_.tl.vertices = (ccVertex3F) { x1, y2, 0 }; | ||
| 383 | quad_.tr.vertices = (ccVertex3F) { x2, y2, 0 }; | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | -(void)updateTextureCoords:(CGRect)rect | ||
| 388 | { | ||
| 389 | CCTexture2D *tex = (usesBatchNode_)?[textureAtlas_ texture]:texture_; | ||
| 390 | if(!tex) | ||
| 391 | return; | ||
| 392 | |||
| 393 | float atlasWidth = (float)tex.pixelsWide; | ||
| 394 | float atlasHeight = (float)tex.pixelsHigh; | ||
| 395 | |||
| 396 | float left,right,top,bottom; | ||
| 397 | |||
| 398 | if(rectRotated_){ | ||
| 399 | #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
| 400 | left = (2*rect.origin.x+1)/(2*atlasWidth); | ||
| 401 | right = left+(rect.size.height*2-2)/(2*atlasWidth); | ||
| 402 | top = (2*rect.origin.y+1)/(2*atlasHeight); | ||
| 403 | bottom = top+(rect.size.width*2-2)/(2*atlasHeight); | ||
| 404 | #else | ||
| 405 | left = rect.origin.x/atlasWidth; | ||
| 406 | right = left+(rect.size.height/atlasWidth); | ||
| 407 | top = rect.origin.y/atlasHeight; | ||
| 408 | bottom = top+(rect.size.width/atlasHeight); | ||
| 409 | #endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
| 410 | |||
| 411 | if( flipX_) | ||
| 412 | CC_SWAP(top,bottom); | ||
| 413 | if( flipY_) | ||
| 414 | CC_SWAP(left,right); | ||
| 415 | |||
| 416 | quad_.bl.texCoords.u = left; | ||
| 417 | quad_.bl.texCoords.v = top; | ||
| 418 | quad_.br.texCoords.u = left; | ||
| 419 | quad_.br.texCoords.v = bottom; | ||
| 420 | quad_.tl.texCoords.u = right; | ||
| 421 | quad_.tl.texCoords.v = top; | ||
| 422 | quad_.tr.texCoords.u = right; | ||
| 423 | quad_.tr.texCoords.v = bottom; | ||
| 424 | } else { | ||
| 425 | #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
| 426 | left = (2*rect.origin.x+1)/(2*atlasWidth); | ||
| 427 | right = left + (rect.size.width*2-2)/(2*atlasWidth); | ||
| 428 | top = (2*rect.origin.y+1)/(2*atlasHeight); | ||
| 429 | bottom = top + (rect.size.height*2-2)/(2*atlasHeight); | ||
| 430 | #else | ||
| 431 | left = rect.origin.x/atlasWidth; | ||
| 432 | right = left + rect.size.width/atlasWidth; | ||
| 433 | top = rect.origin.y/atlasHeight; | ||
| 434 | bottom = top + rect.size.height/atlasHeight; | ||
| 435 | #endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL | ||
| 436 | |||
| 437 | if( flipX_) | ||
| 438 | CC_SWAP(left,right); | ||
| 439 | if( flipY_) | ||
| 440 | CC_SWAP(top,bottom); | ||
| 441 | |||
| 442 | quad_.bl.texCoords.u = left; | ||
| 443 | quad_.bl.texCoords.v = bottom; | ||
| 444 | quad_.br.texCoords.u = right; | ||
| 445 | quad_.br.texCoords.v = bottom; | ||
| 446 | quad_.tl.texCoords.u = left; | ||
| 447 | quad_.tl.texCoords.v = top; | ||
| 448 | quad_.tr.texCoords.u = right; | ||
| 449 | quad_.tr.texCoords.v = top; | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | -(void)updateTransform | ||
| 454 | { | ||
| 455 | NSAssert( usesBatchNode_, @"updateTransform is only valid when CCSprite is being renderd using an CCSpriteBatchNode"); | ||
| 456 | |||
| 457 | // optimization. Quick return if not dirty | ||
| 458 | if( ! dirty_ ) | ||
| 459 | return; | ||
| 460 | |||
| 461 | CGAffineTransform matrix; | ||
| 462 | |||
| 463 | // Optimization: if it is not visible, then do nothing | ||
| 464 | if( ! visible_ ) { | ||
| 465 | quad_.br.vertices = quad_.tl.vertices = quad_.tr.vertices = quad_.bl.vertices = (ccVertex3F){0,0,0}; | ||
| 466 | [textureAtlas_ updateQuad:&quad_ atIndex:atlasIndex_]; | ||
| 467 | dirty_ = recursiveDirty_ = NO; | ||
| 468 | return ; | ||
| 469 | } | ||
| 470 | |||
| 471 | |||
| 472 | // Optimization: If parent is batchnode, or parent is nil | ||
| 473 | // build Affine transform manually | ||
| 474 | if( ! parent_ || parent_ == batchNode_ ) { | ||
| 475 | |||
| 476 | float radians = -CC_DEGREES_TO_RADIANS(rotation_); | ||
| 477 | float c = cosf(radians); | ||
| 478 | float s = sinf(radians); | ||
| 479 | |||
| 480 | matrix = CGAffineTransformMake( c * scaleX_, s * scaleX_, | ||
| 481 | -s * scaleY_, c * scaleY_, | ||
| 482 | positionInPixels_.x, positionInPixels_.y); | ||
| 483 | if( skewX_ || skewY_ ) { | ||
| 484 | CGAffineTransform skewMatrix = CGAffineTransformMake(1.0f, tanf(CC_DEGREES_TO_RADIANS(skewY_)), | ||
| 485 | tanf(CC_DEGREES_TO_RADIANS(skewX_)), 1.0f, | ||
| 486 | 0.0f, 0.0f); | ||
| 487 | matrix = CGAffineTransformConcat(skewMatrix, matrix); | ||
| 488 | } | ||
| 489 | matrix = CGAffineTransformTranslate(matrix, -anchorPointInPixels_.x, -anchorPointInPixels_.y); | ||
| 490 | |||
| 491 | |||
| 492 | } else { // parent_ != batchNode_ | ||
| 493 | |||
| 494 | // else do affine transformation according to the HonorParentTransform | ||
| 495 | |||
| 496 | matrix = CGAffineTransformIdentity; | ||
| 497 | ccHonorParentTransform prevHonor = CC_HONOR_PARENT_TRANSFORM_ALL; | ||
| 498 | |||
| 499 | for (CCNode *p = self ; p && p != batchNode_ ; p = p.parent) { | ||
| 500 | |||
| 501 | // Might happen. Issue #1053 | ||
| 502 | NSAssert( [p isKindOfClass:[CCSprite class]], @"CCSprite should be a CCSprite subclass. Probably you initialized an sprite with a batchnode, but you didn't add it to the batch node." ); | ||
| 503 | |||
| 504 | struct transformValues_ tv; | ||
| 505 | [(CCSprite*)p getTransformValues: &tv]; | ||
| 506 | |||
| 507 | // If any of the parents are not visible, then don't draw this node | ||
| 508 | if( ! tv.visible ) { | ||
| 509 | quad_.br.vertices = quad_.tl.vertices = quad_.tr.vertices = quad_.bl.vertices = (ccVertex3F){0,0,0}; | ||
| 510 | [textureAtlas_ updateQuad:&quad_ atIndex:atlasIndex_]; | ||
| 511 | dirty_ = recursiveDirty_ = NO; | ||
| 512 | return; | ||
| 513 | } | ||
| 514 | CGAffineTransform newMatrix = CGAffineTransformIdentity; | ||
| 515 | |||
| 516 | // 2nd: Translate, Skew, Rotate, Scale | ||
| 517 | if( prevHonor & CC_HONOR_PARENT_TRANSFORM_TRANSLATE ) | ||
| 518 | newMatrix = CGAffineTransformTranslate(newMatrix, tv.pos.x, tv.pos.y); | ||
| 519 | if( prevHonor & CC_HONOR_PARENT_TRANSFORM_ROTATE ) | ||
| 520 | newMatrix = CGAffineTransformRotate(newMatrix, -CC_DEGREES_TO_RADIANS(tv.rotation)); | ||
| 521 | if ( prevHonor & CC_HONOR_PARENT_TRANSFORM_SKEW ) { | ||
| 522 | CGAffineTransform skew = CGAffineTransformMake(1.0f, tanf(CC_DEGREES_TO_RADIANS(tv.skew.y)), tanf(CC_DEGREES_TO_RADIANS(tv.skew.x)), 1.0f, 0.0f, 0.0f); | ||
| 523 | // apply the skew to the transform | ||
| 524 | newMatrix = CGAffineTransformConcat(skew, newMatrix); | ||
| 525 | } | ||
| 526 | if( prevHonor & CC_HONOR_PARENT_TRANSFORM_SCALE ) { | ||
| 527 | newMatrix = CGAffineTransformScale(newMatrix, tv.scale.x, tv.scale.y); | ||
| 528 | } | ||
| 529 | |||
| 530 | // 3rd: Translate anchor point | ||
| 531 | newMatrix = CGAffineTransformTranslate(newMatrix, -tv.ap.x, -tv.ap.y); | ||
| 532 | |||
| 533 | // 4th: Matrix multiplication | ||
| 534 | matrix = CGAffineTransformConcat( matrix, newMatrix); | ||
| 535 | |||
| 536 | prevHonor = [(CCSprite*)p honorParentTransform]; | ||
| 537 | } | ||
| 538 | } | ||
| 539 | |||
| 540 | |||
| 541 | // | ||
| 542 | // calculate the Quad based on the Affine Matrix | ||
| 543 | // | ||
| 544 | |||
| 545 | CGSize size = rectInPixels_.size; | ||
| 546 | |||
| 547 | float x1 = offsetPositionInPixels_.x; | ||
| 548 | float y1 = offsetPositionInPixels_.y; | ||
| 549 | |||
| 550 | float x2 = x1 + size.width; | ||
| 551 | float y2 = y1 + size.height; | ||
| 552 | float x = matrix.tx; | ||
| 553 | float y = matrix.ty; | ||
| 554 | |||
| 555 | float cr = matrix.a; | ||
| 556 | float sr = matrix.b; | ||
| 557 | float cr2 = matrix.d; | ||
| 558 | float sr2 = -matrix.c; | ||
| 559 | float ax = x1 * cr - y1 * sr2 + x; | ||
| 560 | float ay = x1 * sr + y1 * cr2 + y; | ||
| 561 | |||
| 562 | float bx = x2 * cr - y1 * sr2 + x; | ||
| 563 | float by = x2 * sr + y1 * cr2 + y; | ||
| 564 | |||
| 565 | float cx = x2 * cr - y2 * sr2 + x; | ||
| 566 | float cy = x2 * sr + y2 * cr2 + y; | ||
| 567 | |||
| 568 | float dx = x1 * cr - y2 * sr2 + x; | ||
| 569 | float dy = x1 * sr + y2 * cr2 + y; | ||
| 570 | |||
| 571 | quad_.bl.vertices = (ccVertex3F) { RENDER_IN_SUBPIXEL(ax), RENDER_IN_SUBPIXEL(ay), vertexZ_ }; | ||
| 572 | quad_.br.vertices = (ccVertex3F) { RENDER_IN_SUBPIXEL(bx), RENDER_IN_SUBPIXEL(by), vertexZ_ }; | ||
| 573 | quad_.tl.vertices = (ccVertex3F) { RENDER_IN_SUBPIXEL(dx), RENDER_IN_SUBPIXEL(dy), vertexZ_ }; | ||
| 574 | quad_.tr.vertices = (ccVertex3F) { RENDER_IN_SUBPIXEL(cx), RENDER_IN_SUBPIXEL(cy), vertexZ_ }; | ||
| 575 | |||
| 576 | [textureAtlas_ updateQuad:&quad_ atIndex:atlasIndex_]; | ||
| 577 | dirty_ = recursiveDirty_ = NO; | ||
| 578 | } | ||
| 579 | |||
| 580 | // XXX: Optimization: instead of calling 5 times the parent sprite to obtain: position, scale.x, scale.y, anchorpoint and rotation, | ||
| 581 | // this fuction return the 5 values in 1 single call | ||
| 582 | -(void) getTransformValues:(struct transformValues_*) tv | ||
| 583 | { | ||
| 584 | tv->pos = positionInPixels_; | ||
| 585 | tv->scale.x = scaleX_; | ||
| 586 | tv->scale.y = scaleY_; | ||
| 587 | tv->rotation = rotation_; | ||
| 588 | tv->skew.x = skewX_; | ||
| 589 | tv->skew.y = skewY_; | ||
| 590 | tv->ap = anchorPointInPixels_; | ||
| 591 | tv->visible = visible_; | ||
| 592 | } | ||
| 593 | |||
| 594 | #pragma mark CCSprite - draw | ||
| 595 | |||
| 596 | -(void) draw | ||
| 597 | { | ||
| 598 | [super draw]; | ||
| 599 | |||
| 600 | NSAssert(!usesBatchNode_, @"If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called"); | ||
| 601 | |||
| 602 | // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
| 603 | // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY | ||
| 604 | // Unneeded states: - | ||
| 605 | |||
| 606 | BOOL newBlend = blendFunc_.src != CC_BLEND_SRC || blendFunc_.dst != CC_BLEND_DST; | ||
| 607 | if( newBlend ) | ||
| 608 | glBlendFunc( blendFunc_.src, blendFunc_.dst ); | ||
| 609 | |||
| 610 | #define kQuadSize sizeof(quad_.bl) | ||
| 611 | glBindTexture(GL_TEXTURE_2D, [texture_ name]); | ||
| 612 | |||
| 613 | long offset = (long)&quad_; | ||
| 614 | |||
| 615 | // vertex | ||
| 616 | NSInteger diff = offsetof( ccV3F_C4B_T2F, vertices); | ||
| 617 | glVertexPointer(3, GL_FLOAT, kQuadSize, (void*) (offset + diff) ); | ||
| 618 | |||
| 619 | // color | ||
| 620 | diff = offsetof( ccV3F_C4B_T2F, colors); | ||
| 621 | glColorPointer(4, GL_UNSIGNED_BYTE, kQuadSize, (void*)(offset + diff)); | ||
| 622 | |||
| 623 | // tex coords | ||
| 624 | diff = offsetof( ccV3F_C4B_T2F, texCoords); | ||
| 625 | glTexCoordPointer(2, GL_FLOAT, kQuadSize, (void*)(offset + diff)); | ||
| 626 | |||
| 627 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | ||
| 628 | |||
| 629 | if( newBlend ) | ||
| 630 | glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST); | ||
| 631 | |||
| 632 | #if CC_SPRITE_DEBUG_DRAW == 1 | ||
| 633 | // draw bounding box | ||
| 634 | CGSize s = self.contentSize; | ||
| 635 | CGPoint vertices[4] = { | ||
| 636 | ccp(0,0), ccp(s.width,0), | ||
| 637 | ccp(s.width,s.height), ccp(0,s.height) | ||
| 638 | }; | ||
| 639 | ccDrawPoly(vertices, 4, YES); | ||
| 640 | #elif CC_SPRITE_DEBUG_DRAW == 2 | ||
| 641 | // draw texture box | ||
| 642 | CGSize s = self.textureRect.size; | ||
| 643 | CGPoint offsetPix = self.offsetPositionInPixels; | ||
| 644 | CGPoint vertices[4] = { | ||
| 645 | ccp(offsetPix.x,offsetPix.y), ccp(offsetPix.x+s.width,offsetPix.y), | ||
| 646 | ccp(offsetPix.x+s.width,offsetPix.y+s.height), ccp(offsetPix.x,offsetPix.y+s.height) | ||
| 647 | }; | ||
| 648 | ccDrawPoly(vertices, 4, YES); | ||
| 649 | #endif // CC_SPRITE_DEBUG_DRAW | ||
| 650 | |||
| 651 | } | ||
| 652 | |||
| 653 | #pragma mark CCSprite - CCNode overrides | ||
| 654 | |||
| 655 | -(void) addChild:(CCSprite*)child z:(NSInteger)z tag:(NSInteger) aTag | ||
| 656 | { | ||
| 657 | NSAssert( child != nil, @"Argument must be non-nil"); | ||
| 658 | |||
| 659 | [super addChild:child z:z tag:aTag]; | ||
| 660 | |||
| 661 | if( usesBatchNode_ ) { | ||
| 662 | NSAssert( [child isKindOfClass:[CCSprite class]], @"CCSprite only supports CCSprites as children when using CCSpriteBatchNode"); | ||
| 663 | NSAssert( child.texture.name == textureAtlas_.texture.name, @"CCSprite is not using the same texture id"); | ||
| 664 | |||
| 665 | NSUInteger index = [batchNode_ atlasIndexForChild:child atZ:z]; | ||
| 666 | [batchNode_ insertChild:child inAtlasAtIndex:index]; | ||
| 667 | } | ||
| 668 | |||
| 669 | hasChildren_ = YES; | ||
| 670 | } | ||
| 671 | |||
| 672 | -(void) reorderChild:(CCSprite*)child z:(NSInteger)z | ||
| 673 | { | ||
| 674 | NSAssert( child != nil, @"Child must be non-nil"); | ||
| 675 | NSAssert( [children_ containsObject:child], @"Child doesn't belong to Sprite" ); | ||
| 676 | |||
| 677 | if( z == child.zOrder ) | ||
| 678 | return; | ||
| 679 | |||
| 680 | if( usesBatchNode_ ) { | ||
| 681 | // XXX: Instead of removing/adding, it is more efficient to reorder manually | ||
| 682 | [child retain]; | ||
| 683 | [self removeChild:child cleanup:NO]; | ||
| 684 | [self addChild:child z:z]; | ||
| 685 | [child release]; | ||
| 686 | } | ||
| 687 | |||
| 688 | else | ||
| 689 | [super reorderChild:child z:z]; | ||
| 690 | } | ||
| 691 | |||
| 692 | -(void)removeChild: (CCSprite *)sprite cleanup:(BOOL)doCleanup | ||
| 693 | { | ||
| 694 | if( usesBatchNode_ ) | ||
| 695 | [batchNode_ removeSpriteFromAtlas:sprite]; | ||
| 696 | |||
| 697 | [super removeChild:sprite cleanup:doCleanup]; | ||
| 698 | |||
| 699 | hasChildren_ = ( [children_ count] > 0 ); | ||
| 700 | } | ||
| 701 | |||
| 702 | -(void)removeAllChildrenWithCleanup:(BOOL)doCleanup | ||
| 703 | { | ||
| 704 | if( usesBatchNode_ ) { | ||
| 705 | CCSprite *child; | ||
| 706 | CCARRAY_FOREACH(children_, child) | ||
| 707 | [batchNode_ removeSpriteFromAtlas:child]; | ||
| 708 | } | ||
| 709 | |||
| 710 | [super removeAllChildrenWithCleanup:doCleanup]; | ||
| 711 | |||
| 712 | hasChildren_ = NO; | ||
| 713 | } | ||
| 714 | |||
| 715 | // | ||
| 716 | // CCNode property overloads | ||
| 717 | // used only when parent is CCSpriteBatchNode | ||
| 718 | // | ||
| 719 | #pragma mark CCSprite - property overloads | ||
| 720 | |||
| 721 | |||
| 722 | -(void) setDirtyRecursively:(BOOL)b | ||
| 723 | { | ||
| 724 | dirty_ = recursiveDirty_ = b; | ||
| 725 | // recursively set dirty | ||
| 726 | if( hasChildren_ ) { | ||
| 727 | CCSprite *child; | ||
| 728 | CCARRAY_FOREACH(children_, child) | ||
| 729 | [child setDirtyRecursively:YES]; | ||
| 730 | } | ||
| 731 | } | ||
| 732 | |||
| 733 | // XXX HACK: optimization | ||
| 734 | #define SET_DIRTY_RECURSIVELY() { \ | ||
| 735 | if( usesBatchNode_ && ! recursiveDirty_ ) { \ | ||
| 736 | dirty_ = recursiveDirty_ = YES; \ | ||
| 737 | if( hasChildren_) \ | ||
| 738 | [self setDirtyRecursively:YES]; \ | ||
| 739 | } \ | ||
| 740 | } | ||
| 741 | |||
| 742 | -(void)setPosition:(CGPoint)pos | ||
| 743 | { | ||
| 744 | [super setPosition:pos]; | ||
| 745 | SET_DIRTY_RECURSIVELY(); | ||
| 746 | } | ||
| 747 | |||
| 748 | -(void)setPositionInPixels:(CGPoint)pos | ||
| 749 | { | ||
| 750 | [super setPositionInPixels:pos]; | ||
| 751 | SET_DIRTY_RECURSIVELY(); | ||
| 752 | } | ||
| 753 | |||
| 754 | -(void)setRotation:(float)rot | ||
| 755 | { | ||
| 756 | [super setRotation:rot]; | ||
| 757 | SET_DIRTY_RECURSIVELY(); | ||
| 758 | } | ||
| 759 | |||
| 760 | -(void)setSkewX:(float)sx | ||
| 761 | { | ||
| 762 | [super setSkewX:sx]; | ||
| 763 | SET_DIRTY_RECURSIVELY(); | ||
| 764 | } | ||
| 765 | |||
| 766 | -(void)setSkewY:(float)sy | ||
| 767 | { | ||
| 768 | [super setSkewY:sy]; | ||
| 769 | SET_DIRTY_RECURSIVELY(); | ||
| 770 | } | ||
| 771 | |||
| 772 | -(void)setScaleX:(float) sx | ||
| 773 | { | ||
| 774 | [super setScaleX:sx]; | ||
| 775 | SET_DIRTY_RECURSIVELY(); | ||
| 776 | } | ||
| 777 | |||
| 778 | -(void)setScaleY:(float) sy | ||
| 779 | { | ||
| 780 | [super setScaleY:sy]; | ||
| 781 | SET_DIRTY_RECURSIVELY(); | ||
| 782 | } | ||
| 783 | |||
| 784 | -(void)setScale:(float) s | ||
| 785 | { | ||
| 786 | [super setScale:s]; | ||
| 787 | SET_DIRTY_RECURSIVELY(); | ||
| 788 | } | ||
| 789 | |||
| 790 | -(void) setVertexZ:(float)z | ||
| 791 | { | ||
| 792 | [super setVertexZ:z]; | ||
| 793 | SET_DIRTY_RECURSIVELY(); | ||
| 794 | } | ||
| 795 | |||
| 796 | -(void)setAnchorPoint:(CGPoint)anchor | ||
| 797 | { | ||
| 798 | [super setAnchorPoint:anchor]; | ||
| 799 | SET_DIRTY_RECURSIVELY(); | ||
| 800 | } | ||
| 801 | |||
| 802 | -(void)setIsRelativeAnchorPoint:(BOOL)relative | ||
| 803 | { | ||
| 804 | NSAssert( ! usesBatchNode_, @"relativeTransformAnchor is invalid in CCSprite"); | ||
| 805 | [super setIsRelativeAnchorPoint:relative]; | ||
| 806 | } | ||
| 807 | |||
| 808 | -(void)setVisible:(BOOL)v | ||
| 809 | { | ||
| 810 | [super setVisible:v]; | ||
| 811 | SET_DIRTY_RECURSIVELY(); | ||
| 812 | } | ||
| 813 | |||
| 814 | -(void)setFlipX:(BOOL)b | ||
| 815 | { | ||
| 816 | if( flipX_ != b ) { | ||
| 817 | flipX_ = b; | ||
| 818 | [self setTextureRectInPixels:rectInPixels_ rotated:rectRotated_ untrimmedSize:contentSizeInPixels_]; | ||
| 819 | } | ||
| 820 | } | ||
| 821 | -(BOOL) flipX | ||
| 822 | { | ||
| 823 | return flipX_; | ||
| 824 | } | ||
| 825 | |||
| 826 | -(void) setFlipY:(BOOL)b | ||
| 827 | { | ||
| 828 | if( flipY_ != b ) { | ||
| 829 | flipY_ = b; | ||
| 830 | [self setTextureRectInPixels:rectInPixels_ rotated:rectRotated_ untrimmedSize:contentSizeInPixels_]; | ||
| 831 | } | ||
| 832 | } | ||
| 833 | -(BOOL) flipY | ||
| 834 | { | ||
| 835 | return flipY_; | ||
| 836 | } | ||
| 837 | |||
| 838 | // | ||
| 839 | // RGBA protocol | ||
| 840 | // | ||
| 841 | #pragma mark CCSprite - RGBA protocol | ||
| 842 | -(void) updateColor | ||
| 843 | { | ||
| 844 | ccColor4B color4 = {color_.r, color_.g, color_.b, opacity_ }; | ||
| 845 | |||
| 846 | quad_.bl.colors = color4; | ||
| 847 | quad_.br.colors = color4; | ||
| 848 | quad_.tl.colors = color4; | ||
| 849 | quad_.tr.colors = color4; | ||
| 850 | |||
| 851 | // renders using Sprite Manager | ||
| 852 | if( usesBatchNode_ ) { | ||
| 853 | if( atlasIndex_ != CCSpriteIndexNotInitialized) | ||
| 854 | [textureAtlas_ updateQuad:&quad_ atIndex:atlasIndex_]; | ||
| 855 | else | ||
| 856 | // no need to set it recursively | ||
| 857 | // update dirty_, don't update recursiveDirty_ | ||
| 858 | dirty_ = YES; | ||
| 859 | } | ||
| 860 | // self render | ||
| 861 | // do nothing | ||
| 862 | } | ||
| 863 | |||
| 864 | -(GLubyte) opacity | ||
| 865 | { | ||
| 866 | return opacity_; | ||
| 867 | } | ||
| 868 | |||
| 869 | -(void) setOpacity:(GLubyte) anOpacity | ||
| 870 | { | ||
| 871 | opacity_ = anOpacity; | ||
| 872 | |||
| 873 | // special opacity for premultiplied textures | ||
| 874 | if( opacityModifyRGB_ ) | ||
| 875 | [self setColor: colorUnmodified_]; | ||
| 876 | |||
| 877 | [self updateColor]; | ||
| 878 | } | ||
| 879 | |||
| 880 | - (ccColor3B) color | ||
| 881 | { | ||
| 882 | if(opacityModifyRGB_) | ||
| 883 | return colorUnmodified_; | ||
| 884 | |||
| 885 | return color_; | ||
| 886 | } | ||
| 887 | |||
| 888 | -(void) setColor:(ccColor3B)color3 | ||
| 889 | { | ||
| 890 | color_ = colorUnmodified_ = color3; | ||
| 891 | |||
| 892 | if( opacityModifyRGB_ ){ | ||
| 893 | color_.r = color3.r * opacity_/255; | ||
| 894 | color_.g = color3.g * opacity_/255; | ||
| 895 | color_.b = color3.b * opacity_/255; | ||
| 896 | } | ||
| 897 | |||
| 898 | [self updateColor]; | ||
| 899 | } | ||
| 900 | |||
| 901 | -(void) setOpacityModifyRGB:(BOOL)modify | ||
| 902 | { | ||
| 903 | ccColor3B oldColor = self.color; | ||
| 904 | opacityModifyRGB_ = modify; | ||
| 905 | self.color = oldColor; | ||
| 906 | } | ||
| 907 | |||
| 908 | -(BOOL) doesOpacityModifyRGB | ||
| 909 | { | ||
| 910 | return opacityModifyRGB_; | ||
| 911 | } | ||
| 912 | |||
| 913 | // | ||
| 914 | // Frames | ||
| 915 | // | ||
| 916 | #pragma mark CCSprite - Frames | ||
| 917 | |||
| 918 | -(void) setDisplayFrame:(CCSpriteFrame*)frame | ||
| 919 | { | ||
| 920 | unflippedOffsetPositionFromCenter_ = frame.offsetInPixels; | ||
| 921 | |||
| 922 | CCTexture2D *newTexture = [frame texture]; | ||
| 923 | // update texture before updating texture rect | ||
| 924 | if ( newTexture.name != texture_.name ) | ||
| 925 | [self setTexture: newTexture]; | ||
| 926 | |||
| 927 | // update rect | ||
| 928 | rectRotated_ = frame.rotated; | ||
| 929 | [self setTextureRectInPixels:frame.rectInPixels rotated:frame.rotated untrimmedSize:frame.originalSizeInPixels]; | ||
| 930 | } | ||
| 931 | |||
| 932 | // XXX deprecated | ||
| 933 | -(void) setDisplayFrame: (NSString*) animationName index:(int) frameIndex | ||
| 934 | { | ||
| 935 | if( ! animations_ ) | ||
| 936 | [self initAnimationDictionary]; | ||
| 937 | |||
| 938 | CCAnimation *a = [animations_ objectForKey: animationName]; | ||
| 939 | CCSpriteFrame *frame = [[a frames] objectAtIndex:frameIndex]; | ||
| 940 | |||
| 941 | NSAssert( frame, @"CCSprite#setDisplayFrame. Invalid frame"); | ||
| 942 | |||
| 943 | [self setDisplayFrame:frame]; | ||
| 944 | } | ||
| 945 | |||
| 946 | -(void) setDisplayFrameWithAnimationName: (NSString*) animationName index:(int) frameIndex | ||
| 947 | { | ||
| 948 | NSAssert( animationName, @"CCSprite#setDisplayFrameWithAnimationName. animationName must not be nil"); | ||
| 949 | |||
| 950 | CCAnimation *a = [[CCAnimationCache sharedAnimationCache] animationByName:animationName]; | ||
| 951 | |||
| 952 | NSAssert( a, @"CCSprite#setDisplayFrameWithAnimationName: Frame not found"); | ||
| 953 | |||
| 954 | CCSpriteFrame *frame = [[a frames] objectAtIndex:frameIndex]; | ||
| 955 | |||
| 956 | NSAssert( frame, @"CCSprite#setDisplayFrame. Invalid frame"); | ||
| 957 | |||
| 958 | [self setDisplayFrame:frame]; | ||
| 959 | } | ||
| 960 | |||
| 961 | |||
| 962 | -(BOOL) isFrameDisplayed:(CCSpriteFrame*)frame | ||
| 963 | { | ||
| 964 | CGRect r = [frame rect]; | ||
| 965 | return ( CGRectEqualToRect(r, rect_) && | ||
| 966 | frame.texture.name == self.texture.name ); | ||
| 967 | } | ||
| 968 | |||
| 969 | -(CCSpriteFrame*) displayedFrame | ||
| 970 | { | ||
| 971 | return [CCSpriteFrame frameWithTexture:texture_ | ||
| 972 | rectInPixels:rectInPixels_ | ||
| 973 | rotated:rectRotated_ | ||
| 974 | offset:unflippedOffsetPositionFromCenter_ | ||
| 975 | originalSize:contentSizeInPixels_]; | ||
| 976 | } | ||
| 977 | |||
| 978 | -(void) addAnimation: (CCAnimation*) anim | ||
| 979 | { | ||
| 980 | // lazy alloc | ||
| 981 | if( ! animations_ ) | ||
| 982 | [self initAnimationDictionary]; | ||
| 983 | |||
| 984 | [animations_ setObject:anim forKey:[anim name]]; | ||
| 985 | } | ||
| 986 | |||
| 987 | -(CCAnimation*)animationByName: (NSString*) animationName | ||
| 988 | { | ||
| 989 | NSAssert( animationName != nil, @"animationName parameter must be non nil"); | ||
| 990 | return [animations_ objectForKey:animationName]; | ||
| 991 | } | ||
| 992 | |||
| 993 | #pragma mark CCSprite - CocosNodeTexture protocol | ||
| 994 | |||
| 995 | -(void) updateBlendFunc | ||
| 996 | { | ||
| 997 | NSAssert( ! usesBatchNode_, @"CCSprite: updateBlendFunc doesn't work when the sprite is rendered using a CCSpriteBatchNode"); | ||
| 998 | |||
| 999 | // it's possible to have an untextured sprite | ||
| 1000 | if( !texture_ || ! [texture_ hasPremultipliedAlpha] ) { | ||
| 1001 | blendFunc_.src = GL_SRC_ALPHA; | ||
| 1002 | blendFunc_.dst = GL_ONE_MINUS_SRC_ALPHA; | ||
| 1003 | [self setOpacityModifyRGB:NO]; | ||
| 1004 | } else { | ||
| 1005 | blendFunc_.src = CC_BLEND_SRC; | ||
| 1006 | blendFunc_.dst = CC_BLEND_DST; | ||
| 1007 | [self setOpacityModifyRGB:YES]; | ||
| 1008 | } | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | -(void) setTexture:(CCTexture2D*)texture | ||
| 1012 | { | ||
| 1013 | NSAssert( ! usesBatchNode_, @"CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteBatchNode"); | ||
| 1014 | |||
| 1015 | // accept texture==nil as argument | ||
| 1016 | NSAssert( !texture || [texture isKindOfClass:[CCTexture2D class]], @"setTexture expects a CCTexture2D. Invalid argument"); | ||
| 1017 | |||
| 1018 | [texture_ release]; | ||
| 1019 | texture_ = [texture retain]; | ||
| 1020 | |||
| 1021 | [self updateBlendFunc]; | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | -(CCTexture2D*) texture | ||
| 1025 | { | ||
| 1026 | return texture_; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | @end | ||
