PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Smooth Drawing/libs/cocos2d/CCSprite.m

https://gitlab.com/Mr.Tomato/smooth-drawing
Objective C | 951 lines | 670 code | 195 blank | 86 comment | 75 complexity | 644581fd71b522dfa18055e63cf342a4 MD5 | raw file
  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. #import "ccConfig.h"
  27. #import "CCSpriteBatchNode.h"
  28. #import "CCSprite.h"
  29. #import "CCSpriteFrame.h"
  30. #import "CCSpriteFrameCache.h"
  31. #import "CCAnimation.h"
  32. #import "CCAnimationCache.h"
  33. #import "CCTextureCache.h"
  34. #import "CCDrawingPrimitives.h"
  35. #import "CCShaderCache.h"
  36. #import "ccGLStateCache.h"
  37. #import "CCGLProgram.h"
  38. #import "CCDirector.h"
  39. #import "Support/CGPointExtension.h"
  40. #import "Support/TransformUtils.h"
  41. #import "Support/CCProfiling.h"
  42. #import "Support/OpenGL_Internal.h"
  43. // external
  44. #import "kazmath/GL/matrix.h"
  45. #pragma mark -
  46. #pragma mark CCSprite
  47. #if CC_SPRITEBATCHNODE_RENDER_SUBPIXEL
  48. #define RENDER_IN_SUBPIXEL
  49. #else
  50. #define RENDER_IN_SUBPIXEL(__A__) ( (int)(__A__))
  51. #endif
  52. @interface CCSprite ()
  53. -(void) setTextureCoords:(CGRect)rect;
  54. -(void) updateBlendFunc;
  55. -(void) setReorderChildDirtyRecursively;
  56. @end
  57. @implementation CCSprite
  58. @synthesize dirty = dirty_;
  59. @synthesize quad = quad_;
  60. @synthesize atlasIndex = atlasIndex_;
  61. @synthesize textureRect = rect_;
  62. @synthesize textureRectRotated = rectRotated_;
  63. @synthesize blendFunc = blendFunc_;
  64. @synthesize textureAtlas = textureAtlas_;
  65. @synthesize offsetPosition = offsetPosition_;
  66. +(id)spriteWithTexture:(CCTexture2D*)texture
  67. {
  68. return [[[self alloc] initWithTexture:texture] autorelease];
  69. }
  70. +(id)spriteWithTexture:(CCTexture2D*)texture rect:(CGRect)rect
  71. {
  72. return [[[self alloc] initWithTexture:texture rect:rect] autorelease];
  73. }
  74. +(id)spriteWithFile:(NSString*)filename
  75. {
  76. return [[[self alloc] initWithFile:filename] autorelease];
  77. }
  78. +(id)spriteWithFile:(NSString*)filename rect:(CGRect)rect
  79. {
  80. return [[[self alloc] initWithFile:filename rect:rect] autorelease];
  81. }
  82. +(id)spriteWithSpriteFrame:(CCSpriteFrame*)spriteFrame
  83. {
  84. return [[[self alloc] initWithSpriteFrame:spriteFrame] autorelease];
  85. }
  86. +(id)spriteWithSpriteFrameName:(NSString*)spriteFrameName
  87. {
  88. CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:spriteFrameName];
  89. NSAssert1(frame!=nil, @"Invalid spriteFrameName: %@", spriteFrameName);
  90. return [self spriteWithSpriteFrame:frame];
  91. }
  92. +(id)spriteWithCGImage:(CGImageRef)image key:(NSString*)key
  93. {
  94. return [[[self alloc] initWithCGImage:image key:key] autorelease];
  95. }
  96. -(id) init
  97. {
  98. return [self initWithTexture:nil rect:CGRectZero];
  99. }
  100. // designated initializer
  101. -(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect rotated:(BOOL)rotated
  102. {
  103. if( (self = [super init]) )
  104. {
  105. // shader program
  106. self.shaderProgram = [[CCShaderCache sharedShaderCache] programForKey:kCCShader_PositionTextureColor];
  107. dirty_ = recursiveDirty_ = NO;
  108. opacityModifyRGB_ = YES;
  109. opacity_ = 255;
  110. color_ = colorUnmodified_ = ccWHITE;
  111. blendFunc_.src = CC_BLEND_SRC;
  112. blendFunc_.dst = CC_BLEND_DST;
  113. flipY_ = flipX_ = NO;
  114. // default transform anchor: center
  115. anchorPoint_ = ccp(0.5f, 0.5f);
  116. // zwoptex default values
  117. offsetPosition_ = CGPointZero;
  118. hasChildren_ = NO;
  119. batchNode_ = nil;
  120. // clean the Quad
  121. bzero(&quad_, sizeof(quad_));
  122. // Atlas: Color
  123. ccColor4B tmpColor = {255,255,255,255};
  124. quad_.bl.colors = tmpColor;
  125. quad_.br.colors = tmpColor;
  126. quad_.tl.colors = tmpColor;
  127. quad_.tr.colors = tmpColor;
  128. [self setTexture:texture];
  129. [self setTextureRect:rect rotated:rotated untrimmedSize:rect.size];
  130. // by default use "Self Render".
  131. // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
  132. [self setBatchNode:nil];
  133. }
  134. return self;
  135. }
  136. -(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect
  137. {
  138. return [self initWithTexture:texture rect:rect rotated:NO];
  139. }
  140. -(id) initWithTexture:(CCTexture2D*)texture
  141. {
  142. NSAssert(texture!=nil, @"Invalid texture for sprite");
  143. CGRect rect = CGRectZero;
  144. rect.size = texture.contentSize;
  145. return [self initWithTexture:texture rect:rect];
  146. }
  147. -(id) initWithFile:(NSString*)filename
  148. {
  149. NSAssert(filename != nil, @"Invalid filename for sprite");
  150. CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage: filename];
  151. if( texture ) {
  152. CGRect rect = CGRectZero;
  153. rect.size = texture.contentSize;
  154. return [self initWithTexture:texture rect:rect];
  155. }
  156. [self release];
  157. return nil;
  158. }
  159. -(id) initWithFile:(NSString*)filename rect:(CGRect)rect
  160. {
  161. NSAssert(filename!=nil, @"Invalid filename for sprite");
  162. CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage: filename];
  163. if( texture )
  164. return [self initWithTexture:texture rect:rect];
  165. [self release];
  166. return nil;
  167. }
  168. - (id) initWithSpriteFrame:(CCSpriteFrame*)spriteFrame
  169. {
  170. NSAssert(spriteFrame!=nil, @"Invalid spriteFrame for sprite");
  171. id ret = [self initWithTexture:spriteFrame.texture rect:spriteFrame.rect];
  172. [self setDisplayFrame:spriteFrame];
  173. return ret;
  174. }
  175. -(id)initWithSpriteFrameName:(NSString*)spriteFrameName
  176. {
  177. NSAssert(spriteFrameName!=nil, @"Invalid spriteFrameName for sprite");
  178. CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:spriteFrameName];
  179. return [self initWithSpriteFrame:frame];
  180. }
  181. - (id) initWithCGImage:(CGImageRef)image key:(NSString*)key
  182. {
  183. NSAssert(image!=nil, @"Invalid CGImageRef for sprite");
  184. // XXX: possible bug. See issue #349. New API should be added
  185. CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addCGImage:image forKey:key];
  186. CGRect rect = CGRectZero;
  187. rect.size = texture.contentSize;
  188. return [self initWithTexture:texture rect:rect];
  189. }
  190. - (NSString*) description
  191. {
  192. return [NSString stringWithFormat:@"<%@ = %08X | Rect = (%.2f,%.2f,%.2f,%.2f) | tag = %i | atlasIndex = %i>", [self class], self,
  193. rect_.origin.x, rect_.origin.y, rect_.size.width, rect_.size.height,
  194. tag_,
  195. atlasIndex_
  196. ];
  197. }
  198. - (void) dealloc
  199. {
  200. [texture_ release];
  201. [super dealloc];
  202. }
  203. -(CCSpriteBatchNode*) batchNode
  204. {
  205. return batchNode_;
  206. }
  207. -(void) setBatchNode:(CCSpriteBatchNode *)batchNode
  208. {
  209. batchNode_ = batchNode; // weak reference
  210. // self render
  211. if( ! batchNode ) {
  212. atlasIndex_ = CCSpriteIndexNotInitialized;
  213. textureAtlas_ = nil;
  214. dirty_ = recursiveDirty_ = NO;
  215. float x1 = offsetPosition_.x;
  216. float y1 = offsetPosition_.y;
  217. float x2 = x1 + rect_.size.width;
  218. float y2 = y1 + rect_.size.height;
  219. quad_.bl.vertices = (ccVertex3F) { x1, y1, 0 };
  220. quad_.br.vertices = (ccVertex3F) { x2, y1, 0 };
  221. quad_.tl.vertices = (ccVertex3F) { x1, y2, 0 };
  222. quad_.tr.vertices = (ccVertex3F) { x2, y2, 0 };
  223. } else {
  224. // using batch
  225. transformToBatch_ = CGAffineTransformIdentity;
  226. textureAtlas_ = [batchNode textureAtlas]; // weak ref
  227. }
  228. }
  229. -(void) setTextureRect:(CGRect)rect
  230. {
  231. [self setTextureRect:rect rotated:NO untrimmedSize:rect.size];
  232. }
  233. -(void) setTextureRect:(CGRect)rect rotated:(BOOL)rotated untrimmedSize:(CGSize)untrimmedSize
  234. {
  235. rectRotated_ = rotated;
  236. [self setContentSize:untrimmedSize];
  237. [self setVertexRect:rect];
  238. [self setTextureCoords:rect];
  239. CGPoint relativeOffset = unflippedOffsetPositionFromCenter_;
  240. // issue #732
  241. if( flipX_ )
  242. relativeOffset.x = -relativeOffset.x;
  243. if( flipY_ )
  244. relativeOffset.y = -relativeOffset.y;
  245. offsetPosition_.x = relativeOffset.x + (contentSize_.width - rect_.size.width) / 2;
  246. offsetPosition_.y = relativeOffset.y + (contentSize_.height - rect_.size.height) / 2;
  247. // rendering using batch node
  248. if( batchNode_ ) {
  249. // update dirty_, don't update recursiveDirty_
  250. dirty_ = YES;
  251. }
  252. // self rendering
  253. else
  254. {
  255. // Atlas: Vertex
  256. float x1 = offsetPosition_.x;
  257. float y1 = offsetPosition_.y;
  258. float x2 = x1 + rect_.size.width;
  259. float y2 = y1 + rect_.size.height;
  260. // Don't update Z.
  261. quad_.bl.vertices = (ccVertex3F) { x1, y1, 0 };
  262. quad_.br.vertices = (ccVertex3F) { x2, y1, 0 };
  263. quad_.tl.vertices = (ccVertex3F) { x1, y2, 0 };
  264. quad_.tr.vertices = (ccVertex3F) { x2, y2, 0 };
  265. }
  266. }
  267. // override this method to generate "double scale" sprites
  268. -(void) setVertexRect:(CGRect)rect
  269. {
  270. rect_ = rect;
  271. }
  272. -(void) setTextureCoords:(CGRect)rect
  273. {
  274. rect = CC_RECT_POINTS_TO_PIXELS(rect);
  275. CCTexture2D *tex = (batchNode_) ? [textureAtlas_ texture] : texture_;
  276. if(!tex)
  277. return;
  278. float atlasWidth = (float)tex.pixelsWide;
  279. float atlasHeight = (float)tex.pixelsHigh;
  280. float left, right ,top , bottom;
  281. if(rectRotated_)
  282. {
  283. #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
  284. left = (2*rect.origin.x+1)/(2*atlasWidth);
  285. right = left+(rect.size.height*2-2)/(2*atlasWidth);
  286. top = (2*rect.origin.y+1)/(2*atlasHeight);
  287. bottom = top+(rect.size.width*2-2)/(2*atlasHeight);
  288. #else
  289. left = rect.origin.x/atlasWidth;
  290. right = left+(rect.size.height/atlasWidth);
  291. top = rect.origin.y/atlasHeight;
  292. bottom = top+(rect.size.width/atlasHeight);
  293. #endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
  294. if( flipX_)
  295. CC_SWAP(top,bottom);
  296. if( flipY_)
  297. CC_SWAP(left,right);
  298. quad_.bl.texCoords.u = left;
  299. quad_.bl.texCoords.v = top;
  300. quad_.br.texCoords.u = left;
  301. quad_.br.texCoords.v = bottom;
  302. quad_.tl.texCoords.u = right;
  303. quad_.tl.texCoords.v = top;
  304. quad_.tr.texCoords.u = right;
  305. quad_.tr.texCoords.v = bottom;
  306. } else {
  307. #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
  308. left = (2*rect.origin.x+1)/(2*atlasWidth);
  309. right = left + (rect.size.width*2-2)/(2*atlasWidth);
  310. top = (2*rect.origin.y+1)/(2*atlasHeight);
  311. bottom = top + (rect.size.height*2-2)/(2*atlasHeight);
  312. #else
  313. left = rect.origin.x/atlasWidth;
  314. right = left + rect.size.width/atlasWidth;
  315. top = rect.origin.y/atlasHeight;
  316. bottom = top + rect.size.height/atlasHeight;
  317. #endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
  318. if( flipX_)
  319. CC_SWAP(left,right);
  320. if( flipY_)
  321. CC_SWAP(top,bottom);
  322. quad_.bl.texCoords.u = left;
  323. quad_.bl.texCoords.v = bottom;
  324. quad_.br.texCoords.u = right;
  325. quad_.br.texCoords.v = bottom;
  326. quad_.tl.texCoords.u = left;
  327. quad_.tl.texCoords.v = top;
  328. quad_.tr.texCoords.u = right;
  329. quad_.tr.texCoords.v = top;
  330. }
  331. }
  332. -(void)updateTransform
  333. {
  334. NSAssert( batchNode_, @"updateTransform is only valid when CCSprite is being rendered using an CCSpriteBatchNode");
  335. // recaculate matrix only if it is dirty
  336. if( self.dirty ) {
  337. // If it is not visible, or one of its ancestors is not visible, then do nothing:
  338. if( !visible_ || ( parent_ && parent_ != batchNode_ && ((CCSprite*)parent_)->shouldBeHidden_) ) {
  339. quad_.br.vertices = quad_.tl.vertices = quad_.tr.vertices = quad_.bl.vertices = (ccVertex3F){0,0,0};
  340. shouldBeHidden_ = YES;
  341. }
  342. else {
  343. shouldBeHidden_ = NO;
  344. if( ! parent_ || parent_ == batchNode_ )
  345. transformToBatch_ = [self nodeToParentTransform];
  346. else {
  347. NSAssert( [parent_ isKindOfClass:[CCSprite class]], @"Logic error in CCSprite. Parent must be a CCSprite");
  348. transformToBatch_ = CGAffineTransformConcat( [self nodeToParentTransform] , ((CCSprite*)parent_)->transformToBatch_ );
  349. }
  350. //
  351. // calculate the Quad based on the Affine Matrix
  352. //
  353. CGSize size = rect_.size;
  354. float x1 = offsetPosition_.x;
  355. float y1 = offsetPosition_.y;
  356. float x2 = x1 + size.width;
  357. float y2 = y1 + size.height;
  358. float x = transformToBatch_.tx;
  359. float y = transformToBatch_.ty;
  360. float cr = transformToBatch_.a;
  361. float sr = transformToBatch_.b;
  362. float cr2 = transformToBatch_.d;
  363. float sr2 = -transformToBatch_.c;
  364. float ax = x1 * cr - y1 * sr2 + x;
  365. float ay = x1 * sr + y1 * cr2 + y;
  366. float bx = x2 * cr - y1 * sr2 + x;
  367. float by = x2 * sr + y1 * cr2 + y;
  368. float cx = x2 * cr - y2 * sr2 + x;
  369. float cy = x2 * sr + y2 * cr2 + y;
  370. float dx = x1 * cr - y2 * sr2 + x;
  371. float dy = x1 * sr + y2 * cr2 + y;
  372. quad_.bl.vertices = (ccVertex3F) { RENDER_IN_SUBPIXEL(ax), RENDER_IN_SUBPIXEL(ay), vertexZ_ };
  373. quad_.br.vertices = (ccVertex3F) { RENDER_IN_SUBPIXEL(bx), RENDER_IN_SUBPIXEL(by), vertexZ_ };
  374. quad_.tl.vertices = (ccVertex3F) { RENDER_IN_SUBPIXEL(dx), RENDER_IN_SUBPIXEL(dy), vertexZ_ };
  375. quad_.tr.vertices = (ccVertex3F) { RENDER_IN_SUBPIXEL(cx), RENDER_IN_SUBPIXEL(cy), vertexZ_ };
  376. }
  377. [textureAtlas_ updateQuad:&quad_ atIndex:atlasIndex_];
  378. dirty_ = recursiveDirty_ = NO;
  379. }
  380. // recursively iterate over children
  381. if( hasChildren_ )
  382. [children_ makeObjectsPerformSelector:@selector(updateTransform)];
  383. #if CC_SPRITE_DEBUG_DRAW
  384. // draw bounding box
  385. CGPoint vertices[4] = {
  386. ccp( quad_.bl.vertices.x, quad_.bl.vertices.y ),
  387. ccp( quad_.br.vertices.x, quad_.br.vertices.y ),
  388. ccp( quad_.tr.vertices.x, quad_.tr.vertices.y ),
  389. ccp( quad_.tl.vertices.x, quad_.tl.vertices.y ),
  390. };
  391. ccDrawPoly(vertices, 4, YES);
  392. #endif // CC_SPRITE_DEBUG_DRAW
  393. }
  394. #pragma mark CCSprite - draw
  395. -(void) draw
  396. {
  397. CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, @"CCSprite - draw");
  398. NSAssert(!batchNode_, @"If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called");
  399. CC_NODE_DRAW_SETUP();
  400. ccGLBlendFunc( blendFunc_.src, blendFunc_.dst );
  401. ccGLBindTexture2D( [texture_ name] );
  402. //
  403. // Attributes
  404. //
  405. ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex );
  406. #define kQuadSize sizeof(quad_.bl)
  407. long offset = (long)&quad_;
  408. // vertex
  409. NSInteger diff = offsetof( ccV3F_C4B_T2F, vertices);
  410. glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff));
  411. // texCoods
  412. diff = offsetof( ccV3F_C4B_T2F, texCoords);
  413. glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));
  414. // color
  415. diff = offsetof( ccV3F_C4B_T2F, colors);
  416. glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff));
  417. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  418. CHECK_GL_ERROR_DEBUG();
  419. #if CC_SPRITE_DEBUG_DRAW == 1
  420. // draw bounding box
  421. CGPoint vertices[4]={
  422. ccp(quad_.tl.vertices.x,quad_.tl.vertices.y),
  423. ccp(quad_.bl.vertices.x,quad_.bl.vertices.y),
  424. ccp(quad_.br.vertices.x,quad_.br.vertices.y),
  425. ccp(quad_.tr.vertices.x,quad_.tr.vertices.y),
  426. };
  427. ccDrawPoly(vertices, 4, YES);
  428. #elif CC_SPRITE_DEBUG_DRAW == 2
  429. // draw texture box
  430. CGSize s = self.textureRect.size;
  431. CGPoint offsetPix = self.offsetPosition;
  432. CGPoint vertices[4] = {
  433. ccp(offsetPix.x,offsetPix.y), ccp(offsetPix.x+s.width,offsetPix.y),
  434. ccp(offsetPix.x+s.width,offsetPix.y+s.height), ccp(offsetPix.x,offsetPix.y+s.height)
  435. };
  436. ccDrawPoly(vertices, 4, YES);
  437. #endif // CC_SPRITE_DEBUG_DRAW
  438. CC_INCREMENT_GL_DRAWS(1);
  439. CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, @"CCSprite - draw");
  440. }
  441. #pragma mark CCSprite - CCNode overrides
  442. -(void) addChild:(CCSprite*)child z:(NSInteger)z tag:(NSInteger) aTag
  443. {
  444. NSAssert( child != nil, @"Argument must be non-nil");
  445. if( batchNode_ ) {
  446. NSAssert( [child isKindOfClass:[CCSprite class]], @"CCSprite only supports CCSprites as children when using CCSpriteBatchNode");
  447. NSAssert( child.texture.name == textureAtlas_.texture.name, @"CCSprite is not using the same texture id");
  448. //put it in descendants array of batch node
  449. [batchNode_ appendChild:child];
  450. if (!isReorderChildDirty_)
  451. [self setReorderChildDirtyRecursively];
  452. }
  453. //CCNode already sets isReorderChildDirty_ so this needs to be after batchNode check
  454. [super addChild:child z:z tag:aTag];
  455. hasChildren_ = YES;
  456. }
  457. -(void) reorderChild:(CCSprite*)child z:(NSInteger)z
  458. {
  459. NSAssert( child != nil, @"Child must be non-nil");
  460. NSAssert( [children_ containsObject:child], @"Child doesn't belong to Sprite" );
  461. if( z == child.zOrder )
  462. return;
  463. if( batchNode_ && ! isReorderChildDirty_)
  464. {
  465. [self setReorderChildDirtyRecursively];
  466. [batchNode_ reorderBatch:YES];
  467. }
  468. [super reorderChild:child z:z];
  469. }
  470. -(void)removeChild: (CCSprite *)sprite cleanup:(BOOL)doCleanup
  471. {
  472. if( batchNode_ )
  473. [batchNode_ removeSpriteFromAtlas:sprite];
  474. [super removeChild:sprite cleanup:doCleanup];
  475. hasChildren_ = ( [children_ count] > 0 );
  476. }
  477. -(void)removeAllChildrenWithCleanup:(BOOL)doCleanup
  478. {
  479. if( batchNode_ ) {
  480. CCSprite *child;
  481. CCARRAY_FOREACH(children_, child)
  482. [batchNode_ removeSpriteFromAtlas:child];
  483. }
  484. [super removeAllChildrenWithCleanup:doCleanup];
  485. hasChildren_ = NO;
  486. }
  487. - (void) sortAllChildren
  488. {
  489. if (isReorderChildDirty_)
  490. {
  491. NSInteger i,j,length = children_->data->num;
  492. CCNode** x = children_->data->arr;
  493. CCNode *tempItem;
  494. // insertion sort
  495. for(i=1; i<length; i++)
  496. {
  497. tempItem = x[i];
  498. j = i-1;
  499. //continue moving element downwards while zOrder is smaller or when zOrder is the same but orderOfArrival is smaller
  500. while(j>=0 && ( tempItem.zOrder < x[j].zOrder || ( tempItem.zOrder == x[j].zOrder && tempItem.orderOfArrival < x[j].orderOfArrival ) ) )
  501. {
  502. x[j+1] = x[j];
  503. j = j-1;
  504. }
  505. x[j+1] = tempItem;
  506. }
  507. if ( batchNode_)
  508. [children_ makeObjectsPerformSelector:@selector(sortAllChildren)];
  509. isReorderChildDirty_=NO;
  510. }
  511. }
  512. //
  513. // CCNode property overloads
  514. // used only when parent is CCSpriteBatchNode
  515. //
  516. #pragma mark CCSprite - property overloads
  517. -(void) setReorderChildDirtyRecursively
  518. {
  519. //only set parents flag the first time
  520. if ( ! isReorderChildDirty_ )
  521. {
  522. isReorderChildDirty_ = YES;
  523. CCNode* node = (CCNode*) parent_;
  524. while (node && node != batchNode_)
  525. {
  526. [(CCSprite*)node setReorderChildDirtyRecursively];
  527. node=node.parent;
  528. }
  529. }
  530. }
  531. -(void) setDirtyRecursively:(BOOL)b
  532. {
  533. dirty_ = recursiveDirty_ = b;
  534. // recursively set dirty
  535. if( hasChildren_ ) {
  536. CCSprite *child;
  537. CCARRAY_FOREACH(children_, child)
  538. [child setDirtyRecursively:YES];
  539. }
  540. }
  541. // XXX HACK: optimization
  542. #define SET_DIRTY_RECURSIVELY() { \
  543. if( batchNode_ && ! recursiveDirty_ ) { \
  544. dirty_ = recursiveDirty_ = YES; \
  545. if( hasChildren_) \
  546. [self setDirtyRecursively:YES]; \
  547. } \
  548. }
  549. -(void)setPosition:(CGPoint)pos
  550. {
  551. [super setPosition:pos];
  552. SET_DIRTY_RECURSIVELY();
  553. }
  554. -(void)setRotation:(float)rot
  555. {
  556. [super setRotation:rot];
  557. SET_DIRTY_RECURSIVELY();
  558. }
  559. -(void)setSkewX:(float)sx
  560. {
  561. [super setSkewX:sx];
  562. SET_DIRTY_RECURSIVELY();
  563. }
  564. -(void)setSkewY:(float)sy
  565. {
  566. [super setSkewY:sy];
  567. SET_DIRTY_RECURSIVELY();
  568. }
  569. -(void)setScaleX:(float) sx
  570. {
  571. [super setScaleX:sx];
  572. SET_DIRTY_RECURSIVELY();
  573. }
  574. -(void)setScaleY:(float) sy
  575. {
  576. [super setScaleY:sy];
  577. SET_DIRTY_RECURSIVELY();
  578. }
  579. -(void)setScale:(float) s
  580. {
  581. [super setScale:s];
  582. SET_DIRTY_RECURSIVELY();
  583. }
  584. -(void) setVertexZ:(float)z
  585. {
  586. [super setVertexZ:z];
  587. SET_DIRTY_RECURSIVELY();
  588. }
  589. -(void)setAnchorPoint:(CGPoint)anchor
  590. {
  591. [super setAnchorPoint:anchor];
  592. SET_DIRTY_RECURSIVELY();
  593. }
  594. -(void)setIsRelativeAnchorPoint:(BOOL)relative
  595. {
  596. NSAssert( ! batchNode_, @"relativeTransformAnchor is invalid in CCSprite");
  597. [super setIsRelativeAnchorPoint:relative];
  598. }
  599. -(void)setVisible:(BOOL)v
  600. {
  601. [super setVisible:v];
  602. SET_DIRTY_RECURSIVELY();
  603. }
  604. -(void)setFlipX:(BOOL)b
  605. {
  606. if( flipX_ != b ) {
  607. flipX_ = b;
  608. [self setTextureRect:rect_ rotated:rectRotated_ untrimmedSize:contentSize_];
  609. }
  610. }
  611. -(BOOL) flipX
  612. {
  613. return flipX_;
  614. }
  615. -(void) setFlipY:(BOOL)b
  616. {
  617. if( flipY_ != b ) {
  618. flipY_ = b;
  619. [self setTextureRect:rect_ rotated:rectRotated_ untrimmedSize:contentSize_];
  620. }
  621. }
  622. -(BOOL) flipY
  623. {
  624. return flipY_;
  625. }
  626. //
  627. // RGBA protocol
  628. //
  629. #pragma mark CCSprite - RGBA protocol
  630. -(void) updateColor
  631. {
  632. ccColor4B color4 = {color_.r, color_.g, color_.b, opacity_};
  633. quad_.bl.colors = color4;
  634. quad_.br.colors = color4;
  635. quad_.tl.colors = color4;
  636. quad_.tr.colors = color4;
  637. // renders using batch node
  638. if( batchNode_ ) {
  639. if( atlasIndex_ != CCSpriteIndexNotInitialized)
  640. [textureAtlas_ updateQuad:&quad_ atIndex:atlasIndex_];
  641. else
  642. // no need to set it recursively
  643. // update dirty_, don't update recursiveDirty_
  644. dirty_ = YES;
  645. }
  646. // self render
  647. // do nothing
  648. }
  649. -(GLubyte) opacity
  650. {
  651. return opacity_;
  652. }
  653. -(void) setOpacity:(GLubyte) anOpacity
  654. {
  655. opacity_ = anOpacity;
  656. // special opacity for premultiplied textures
  657. if( opacityModifyRGB_ )
  658. [self setColor: colorUnmodified_];
  659. [self updateColor];
  660. }
  661. - (ccColor3B) color
  662. {
  663. if(opacityModifyRGB_)
  664. return colorUnmodified_;
  665. return color_;
  666. }
  667. -(void) setColor:(ccColor3B)color3
  668. {
  669. color_ = colorUnmodified_ = color3;
  670. if( opacityModifyRGB_ ){
  671. color_.r = color3.r * opacity_/255.0f;
  672. color_.g = color3.g * opacity_/255.0f;
  673. color_.b = color3.b * opacity_/255.0f;
  674. }
  675. [self updateColor];
  676. }
  677. -(void) setOpacityModifyRGB:(BOOL)modify
  678. {
  679. ccColor3B oldColor = self.color;
  680. opacityModifyRGB_ = modify;
  681. self.color = oldColor;
  682. }
  683. -(BOOL) doesOpacityModifyRGB
  684. {
  685. return opacityModifyRGB_;
  686. }
  687. //
  688. // Frames
  689. //
  690. #pragma mark CCSprite - Frames
  691. -(void) setDisplayFrame:(CCSpriteFrame*)frame
  692. {
  693. unflippedOffsetPositionFromCenter_ = frame.offset;
  694. CCTexture2D *newTexture = [frame texture];
  695. // update texture before updating texture rect
  696. if ( newTexture.name != texture_.name )
  697. [self setTexture: newTexture];
  698. // update rect
  699. rectRotated_ = frame.rotated;
  700. [self setTextureRect:frame.rect rotated:rectRotated_ untrimmedSize:frame.originalSize];
  701. }
  702. -(void) setDisplayFrameWithAnimationName: (NSString*) animationName index:(int) frameIndex
  703. {
  704. NSAssert( animationName, @"CCSprite#setDisplayFrameWithAnimationName. animationName must not be nil");
  705. CCAnimation *a = [[CCAnimationCache sharedAnimationCache] animationByName:animationName];
  706. NSAssert( a, @"CCSprite#setDisplayFrameWithAnimationName: Frame not found");
  707. CCAnimationFrame *frame = [[a frames] objectAtIndex:frameIndex];
  708. NSAssert( frame, @"CCSprite#setDisplayFrame. Invalid frame");
  709. [self setDisplayFrame:frame.spriteFrame];
  710. }
  711. -(BOOL) isFrameDisplayed:(CCSpriteFrame*)frame
  712. {
  713. CGRect r = [frame rect];
  714. return ( CGRectEqualToRect(r, rect_) &&
  715. frame.texture.name == self.texture.name &&
  716. CGPointEqualToPoint( frame.offset, unflippedOffsetPositionFromCenter_ ) );
  717. }
  718. -(CCSpriteFrame*) displayFrame
  719. {
  720. return [CCSpriteFrame frameWithTexture:texture_
  721. rectInPixels:CC_RECT_POINTS_TO_PIXELS(rect_)
  722. rotated:rectRotated_
  723. offset:unflippedOffsetPositionFromCenter_
  724. originalSize:CC_SIZE_POINTS_TO_PIXELS(contentSize_)];
  725. }
  726. #pragma mark CCSprite - CocosNodeTexture protocol
  727. -(void) updateBlendFunc
  728. {
  729. NSAssert( ! batchNode_, @"CCSprite: updateBlendFunc doesn't work when the sprite is rendered using a CCSpriteBatchNode");
  730. // it is possible to have an untextured sprite
  731. if( !texture_ || ! [texture_ hasPremultipliedAlpha] ) {
  732. blendFunc_.src = GL_SRC_ALPHA;
  733. blendFunc_.dst = GL_ONE_MINUS_SRC_ALPHA;
  734. [self setOpacityModifyRGB:NO];
  735. } else {
  736. blendFunc_.src = CC_BLEND_SRC;
  737. blendFunc_.dst = CC_BLEND_DST;
  738. [self setOpacityModifyRGB:YES];
  739. }
  740. }
  741. -(void) setTexture:(CCTexture2D*)texture
  742. {
  743. NSAssert( ! batchNode_, @"CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteBatchNode");
  744. // accept texture==nil as argument
  745. NSAssert( !texture || [texture isKindOfClass:[CCTexture2D class]], @"setTexture expects a CCTexture2D. Invalid argument");
  746. if( texture_ != texture ) {
  747. [texture_ release];
  748. texture_ = [texture retain];
  749. [self updateBlendFunc];
  750. }
  751. }
  752. -(CCTexture2D*) texture
  753. {
  754. return texture_;
  755. }
  756. @end