Skip to content

Commit c6311e3

Browse files
committed
Merge pull request #1380 from danielgronlund/assets-sprite-atlas-support
CCSpriteFrameCache support for loading sprite sheets from image assets.
2 parents 5e7c087 + 984c322 commit c6311e3

File tree

2 files changed

+163
-25
lines changed

2 files changed

+163
-25
lines changed

cocos2d/CCSpriteFrameCache.h

+9
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@
7676
*/
7777
-(void) addSpriteFramesWithFile:(NSString*)plist;
7878

79+
/**
80+
* Add Sprite frames to the cache from the specified sprite atlas asset.
81+
*
82+
* @param name the name of the sprite atlas asset.
83+
*/
84+
-(void) addSpriteFramesFromSpriteAtlasAssetNamed:(NSString *)name;
85+
7986
/**
8087
* Add sprite frames to the cache from the specified plist and texture file.
8188
*
@@ -100,6 +107,8 @@
100107
*/
101108
-(void) addSpriteFrame:(CCSpriteFrame*)frame name:(NSString*)frameName;
102109

110+
111+
103112
/**
104113
* Registers a sprite sheet with the sprite frame cache so that the sprite frames can be loaded by name.
105114
*

cocos2d/CCSpriteFrameCache.m

+154-25
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
#import "CCSprite.h"
4343
#import "Support/CCFileUtils.h"
4444
#import "CCTexture.h"
45-
45+
#import "CCDirector.h"
4646

4747
@interface CCSpriteFrame(Proxy)
4848
- (BOOL)hasProxy;
@@ -180,6 +180,43 @@ - (void) registerSpriteFramesFile:(NSString*)plist
180180

181181
#pragma mark CCSpriteFrameCache - loading sprite frames
182182

183+
-(void) addSpriteFrameWithDictionary:(NSDictionary*)frameDict texture:(CCTexture *)texture scaleSuffix:(NSString *)scaleSuffix
184+
{
185+
// Reducing frame name string to base asset name by cutting of extensions and resolution suffix.
186+
NSString *frameName = [[frameDict objectForKey:@"name"] stringByDeletingPathExtension];
187+
NSString *frameDictKey = frameName;
188+
189+
if (frameName.length > 3) {
190+
NSString *resolutionComponent = [frameName substringWithRange:NSMakeRange(frameName.length -3, 3)];
191+
if ([resolutionComponent isEqualToString:scaleSuffix]) {
192+
frameDictKey = [frameDictKey stringByReplacingCharactersInRange:NSMakeRange(frameDictKey.length - 3, 3) withString:@""];
193+
}
194+
}
195+
196+
CCSpriteFrame *spriteFrame=nil;
197+
198+
// get values
199+
CGSize spriteSize = CCRectFromString([frameDict objectForKey:@"textureRect"]).size;
200+
CGPoint spriteOffset = CCPointFromString([frameDict objectForKey:@"spriteOffset"]);
201+
CGSize spriteSourceSize = CCSizeFromString([frameDict objectForKey:@"spriteSourceSize"]);
202+
CGRect textureRect = CCRectFromString([frameDict objectForKey:@"textureRect"]);
203+
BOOL textureRotated = [[frameDict objectForKey:@"textureRotated"] boolValue];
204+
205+
// get aliases
206+
NSArray *aliases = [frameDict objectForKey:@"aliases"];
207+
for(NSString *alias in aliases) {
208+
if( [_spriteFramesAliases objectForKey:alias] )
209+
CCLOGWARN(@"cocos2d: WARNING: an alias with name %@ already exists",alias);
210+
211+
[_spriteFramesAliases setObject:frameDictKey forKey:alias];
212+
}
213+
214+
// set frame info
215+
CGRect rectInPixels = CGRectMake(textureRect.origin.x, textureRect.origin.y, spriteSize.width, spriteSize.height);
216+
217+
[self addSpriteFrame:spriteFrame withTextureReference:texture key:frameDictKey rectInPixels:rectInPixels rotated:textureRotated offset:spriteOffset originalSize:spriteSourceSize];
218+
}
219+
183220
-(void) addSpriteFramesWithDictionary:(NSDictionary*)dictionary textureReference:(id)textureReference
184221
{
185222
/*
@@ -272,33 +309,38 @@ -(void) addSpriteFramesWithDictionary:(NSDictionary*)dictionary textureReference
272309
frameOffset = spriteOffset;
273310
originalSize = spriteSourceSize;
274311
}
275-
276-
NSString *textureFileName = nil;
277-
CCTexture * texture = nil;
278-
279-
if ( [textureReference isKindOfClass:[NSString class]] )
280-
{
281-
textureFileName = textureReference;
282-
}
283-
else if ( [textureReference isKindOfClass:[CCTexture class]] )
284-
{
285-
texture = textureReference;
286-
}
287-
288-
if ( textureFileName )
289-
{
290-
spriteFrame = [[CCSpriteFrame alloc] initWithTextureFilename:textureFileName rectInPixels:rectInPixels rotated:isRotated offset:frameOffset originalSize:originalSize];
291-
}
292-
else
293-
{
294-
spriteFrame = [[CCSpriteFrame alloc] initWithTexture:texture rectInPixels:rectInPixels rotated:isRotated offset:frameOffset originalSize:originalSize];
295-
}
296-
297-
// add sprite frame
298-
[_spriteFrames setObject:spriteFrame forKey:frameDictKey];
312+
313+
[self addSpriteFrame:spriteFrame withTextureReference:textureReference key:frameDictKey rectInPixels:rectInPixels rotated:isRotated offset:frameOffset originalSize:originalSize];
299314
}
300315
}
301316

317+
- (void)addSpriteFrame:(CCSpriteFrame *)spriteFrame withTextureReference:(id)textureReference key:(NSString *)key rectInPixels:(CGRect)rect rotated:(BOOL)rotated offset:(CGPoint)offset originalSize:(CGSize)originalSize
318+
{
319+
NSString *textureFileName = nil;
320+
CCTexture * texture = nil;
321+
322+
if ( [textureReference isKindOfClass:[NSString class]] )
323+
{
324+
textureFileName = textureReference;
325+
}
326+
else if ( [textureReference isKindOfClass:[CCTexture class]] )
327+
{
328+
texture = textureReference;
329+
}
330+
331+
if ( textureFileName )
332+
{
333+
spriteFrame = [[CCSpriteFrame alloc] initWithTextureFilename:textureFileName rectInPixels:rect rotated:rotated offset:offset originalSize:originalSize];
334+
}
335+
else
336+
{
337+
spriteFrame = [[CCSpriteFrame alloc] initWithTexture:texture rectInPixels:rect rotated:rotated offset:offset originalSize:originalSize];
338+
}
339+
340+
// add sprite frame
341+
[_spriteFrames setObject:spriteFrame forKey:key];
342+
}
343+
302344
-(void) addSpriteFramesWithDictionary:(NSDictionary*)dictionary textureFilename:(NSString*)textureFilename
303345
{
304346
return [self addSpriteFramesWithDictionary:dictionary textureReference:textureFilename];
@@ -376,6 +418,93 @@ -(void) addSpriteFramesWithFile:(NSString*)plist
376418

377419
}
378420

421+
-(void) addSpriteFramesFromSpriteAtlasAssetNamed:(NSString *)atlasAssetName
422+
{
423+
NSDictionary *dictionary = [self dictionaryForSpriteAtlasAssetNamed:atlasAssetName];
424+
if (!dictionary) {
425+
CCLOG(@"cocos2d: CCSpriteFrameCache: No sprite atlas asset found with name: %@", atlasAssetName);
426+
return;
427+
}
428+
if (dictionary != nil) {
429+
NSInteger version = [[dictionary objectForKey:@"version"] integerValue];
430+
if (version != 1) {
431+
CCLOG(@"cocos2d: WARNING: Unsupported version of sprite atlas asset file version: %ld filename: %@", (long)version, atlasAssetName);
432+
return;
433+
}
434+
435+
NSAssert([[dictionary objectForKey:@"format"] isEqualToString:@"APPL"], @"format is not supported for CCSpriteFrameCache addSpriteFramesFromSpriteAtlasAssetNamed:textureFilename:");
436+
437+
int scale = [[CCDirector sharedDirector] contentScaleFactor];
438+
NSString *scaleSuffix = scale == 1 ? @"" : [NSString stringWithFormat:@"@%dx",scale];
439+
440+
NSArray <NSDictionary *>*imageDicts = [dictionary objectForKey:@"images"];
441+
NSArray *imagePaths = [imageDicts valueForKeyPath:@"path"];
442+
443+
// Trying to find image paths for the current devices native resolution.
444+
NSMutableIndexSet *indexes = [self indexesForImagePaths:imagePaths forFilename:atlasAssetName withSuffix:scaleSuffix].mutableCopy;
445+
446+
if (indexes.count == 0) {
447+
// Falling back to using @1x graphics if the expected resolution is not found.
448+
[indexes addIndexes:[self indexesForImagePaths:imagePaths forFilename:atlasAssetName withSuffix:nil]];
449+
scaleSuffix = nil;
450+
}
451+
452+
// Only processing the image dictionaries that are using textures with the correct resolution.
453+
for (NSDictionary *imageDict in [imageDicts objectsAtIndexes:indexes]) {
454+
NSArray *spriteFrames = [imageDict objectForKey:@"subimages"];
455+
NSString *resourceName = [imageDict objectForKey:@"path"];
456+
NSString *resourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:[NSString stringWithFormat:@"/%@.atlasc/%@",atlasAssetName,resourceName]];
457+
if ([[NSFileManager defaultManager] fileExistsAtPath:resourcePath]) {
458+
// Loading the sprite atlas image from the file system
459+
NSData *imageData = [NSData dataWithContentsOfFile:resourcePath];
460+
CGDataProviderRef imgDataProvider = CGDataProviderCreateWithCFData( (__bridge CFDataRef) imageData);
461+
CGImageRef imageRef = CGImageCreateWithPNGDataProvider(imgDataProvider, NULL, true, kCGRenderingIntentDefault);
462+
463+
// Scale suffix will be an empty string if there wasn't any native resolution graphics in the sprite atlas.
464+
// In that case the @1x graphics is loaded as fallback.
465+
CCTexture *texture = [[CCTexture alloc] initWithCGImage:imageRef contentScale:scaleSuffix.length > 0 ? [[CCDirector sharedDirector] contentScaleFactor] : 1.0];
466+
467+
CGDataProviderRelease(imgDataProvider);
468+
CGImageRelease(imageRef);
469+
470+
// Loading the frames and connecting them with the texture.
471+
for (NSDictionary *frameDict in spriteFrames) {
472+
[self addSpriteFrameWithDictionary:frameDict texture:texture scaleSuffix:scaleSuffix];
473+
}
474+
} else {
475+
CCLOG(@"cocos2d: WARNING: image not found at file path: %@",resourcePath);
476+
}
477+
}
478+
}
479+
}
480+
481+
- (NSDictionary *) dictionaryForSpriteAtlasAssetNamed:(NSString *)assetName
482+
{
483+
// Looking for the file in resource root
484+
NSString *resourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:[NSString stringWithFormat:@"/%1$@.atlasc/%1$@.plist",assetName]];
485+
if ([[NSFileManager defaultManager] fileExistsAtPath:resourcePath]) {
486+
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:resourcePath];
487+
488+
return dict;
489+
}
490+
return nil;
491+
}
492+
493+
- (NSIndexSet *)indexesForImagePaths:(NSArray *)imagePaths forFilename:(NSString *)filename withSuffix:(NSString *)scaleSuffix
494+
{
495+
// Checking for indexes that has image paths with the provided suffix.
496+
NSMutableIndexSet *indexes = [[NSMutableIndexSet alloc] init];
497+
for (NSString * searchString in imagePaths) {
498+
NSString *strippedString = [searchString stringByDeletingPathExtension];
499+
strippedString = [strippedString stringByReplacingOccurrencesOfString:filename withString:@""];
500+
strippedString = [strippedString stringByReplacingCharactersInRange:NSMakeRange(0, 2) withString:@""];
501+
if ([strippedString isEqualToString:scaleSuffix]) {
502+
[indexes addIndex:[imagePaths indexOfObject:searchString]];
503+
}
504+
}
505+
return indexes;
506+
}
507+
379508
-(void) addSpriteFrame:(CCSpriteFrame*)frame name:(NSString*)frameName
380509
{
381510
[_spriteFrames setObject:frame forKey:frameName];

0 commit comments

Comments
 (0)