COCOS2d - v2.x
用以下代码替换 CCFileUtils.h 和 .m 并在委托内添加行:[sharedFileUtils setiPhone5DisplaySuffix:@"-568h"]; // >>>>>> iPhone 5 -568h
。H
/*
* cocos2d for iPhone: http://www.cocos2d-iphone.org
*
* Copyright (c) 2008-2010 Ricardo Quesada
* Copyright (c) 2011 Zynga Inc.
*
* 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.
*
*/
#import <Foundation/Foundation.h>
#import "../ccTypes.h"
/** Helper class to handle file operations */
@interface CCFileUtils : NSObject
{
NSFileManager *fileManager_;
NSBundle *bundle_;
NSMutableDictionary *fullPathCache_;
NSMutableDictionary *removeSuffixCache_;
#ifdef __CC_PLATFORM_IOS
BOOL enableFallbackSuffixes_;
NSString *iPhoneRetinaDisplaySuffix_;
NSString *iPhone5DisplaySuffix_; // <<<<<<<<<<<<< ADDED
NSString *iPadSuffix_;
NSString *iPadRetinaDisplaySuffix_;
#endif // __CC_PLATFORM_IOS
}
/** NSBundle used by CCFileUtils. By default it uses [NSBundle mainBundle].
@since v2.0
*/
@property (nonatomic, readwrite, retain) NSBundle *bundle;
/** NSFileManager used by CCFileUtils. By default it uses its own intance.
@since v2.0
*/
@property (nonatomic, readwrite, retain) NSFileManager *fileManager;
#ifdef __CC_PLATFORM_IOS
/** The iPhone RetinaDisplay suffixes to load resources.
By default it is "-hd" and "" in that order.
Only valid on iOS. Not valid for OS X.
@since v1.1
*/
@property (nonatomic,readwrite, copy, setter = setiPhoneRetinaDisplaySuffix:) NSString *iPhoneRetinaDisplaySuffix;
/** The iPhone 5 suffixes to load resources.
By default it is "-hd" and "" in that order.
Only valid on iOS. Not valid for OS X.
@since v1.1
*/
@property (nonatomic,readwrite, copy, setter = setiPhone5DisplaySuffix:) NSString *iPhone5DisplaySuffix;
/** The iPad suffixes to load resources.
By default it is "-ipad", "-hd", "", in that order.
Only valid on iOS. Not valid for OS X.
@since v1.1
*/
@property (nonatomic,readwrite, copy, setter = setiPadSuffix:) NSString *iPadSuffix;
/** Sets the iPad Retina Display suffixes to load resources.
By default it is "-ipadhd", "-ipad", "-hd", "", in that order.
Only valid on iOS. Not valid for OS X.
@since v2.0
*/
@property (nonatomic,readwrite, copy, setter = setiPadRetinaDisplaySuffix:) NSString *iPadRetinaDisplaySuffix;
/** Whether of not the fallback sufixes is enabled.
When enabled it will try to search for the following suffixes in the following order until one is found:
* On iPad HD : iPad HD suffix, iPad suffix, iPhone HD suffix, Without suffix
* On iPad : iPad suffix, iPhone HD suffix, Without suffix
* On iPhone HD: iPhone HD suffix, Without suffix
By default this functionality is off;
*/
@property (nonatomic, readwrite) BOOL enableFallbackSuffixes;
#endif // __CC_PLATFORM_IOS
/** returns the shared file utils instance */
+(CCFileUtils*) sharedFileUtils;
/** Purge cached entries.
Will be called automatically by the Director when a memory warning is received
*/
-(void) purgeCachedEntries;
/** Returns the fullpath of an filename.
If in iPhoneRetinaDisplay mode, and a RetinaDisplay file is found, it will return that path.
If in iPad mode, and an iPad file is found, it will return that path.
Examples:
* In iPad mode: "image.png" -> "/full/path/image-ipad.png" (in case the -ipad file exists)
* In iPhone RetinaDisplay mode: "image.png" -> "/full/path/image-hd.png" (in case the -hd file exists)
* In iPad RetinaDisplay mode: "image.png" -> "/full/path/image-ipadhd.png" (in case the -ipadhd file exists)
*/
-(NSString*) fullPathFromRelativePath:(NSString*) relPath;
/** Returns the fullpath of an filename including the resolution of the image.
If in RetinaDisplay mode, and a RetinaDisplay file is found, it will return that path.
If in iPad mode, and an iPad file is found, it will return that path.
Examples:
* In iPad mode: "image.png" -> "/full/path/image-ipad.png" (in case the -ipad file exists)
* In iPhone RetinaDisplay mode: "image.png" -> "/full/path/image-hd.png" (in case the -hd file exists)
* In iPad RetinaDisplay mode: "image.png" -> "/full/path/image-ipadhd.png" (in case the -ipadhd file exists)
If an iPad file is found, it will set resolution type to kCCResolutioniPad
If a RetinaDisplay file is found, it will set resolution type to kCCResolutionRetinaDisplay
*/
-(NSString*) fullPathFromRelativePath:(NSString*)relPath resolutionType:(ccResolutionType*)resolutionType;
#ifdef __CC_PLATFORM_IOS
/** removes the suffix from a path
* On iPhone RetinaDisplay it will remove the -hd suffix
* On iPad it will remove the -ipad suffix
* On iPad RetinaDisplay it will remove the -ipadhd suffix
Only valid on iOS. Not valid for OS X.
@since v0.99.5
*/
-(NSString *)removeSuffixFromFile:(NSString*) path;
/** Returns whether or not a given path exists with the iPhone RetinaDisplay suffix.
Only available on iOS. Not supported on OS X.
@since v1.1
*/
-(BOOL) iPhoneRetinaDisplayFileExistsAtPath:(NSString*)filename;
/** Returns whether or not a given path exists with the iPhone 5 suffix.
Only available on iOS. Not supported on OS X.
@since v1.1
*/
-(BOOL) iPhone5DisplayFileExistsAtPath:(NSString*)filename;
/** Returns whether or not a given filename exists with the iPad suffix.
Only available on iOS. Not supported on OS X.
@since v1.1
*/
-(BOOL) iPadFileExistsAtPath:(NSString*)filename;
/** Returns whether or not a given filename exists with the iPad RetinaDisplay suffix.
Only available on iOS. Not supported on OS X.
@since v2.0
*/
-(BOOL) iPadRetinaDisplayFileExistsAtPath:(NSString*)filename;
#endif // __CC_PLATFORM_IOS
@end
#ifdef __cplusplus
extern "C" {
#endif
/** loads a file into memory.
the caller should release the allocated buffer.
@returns the size of the allocated buffer
@since v0.99.5
*/
NSInteger ccLoadFileIntoMemory(const char *filename, unsigned char **out);
#ifdef __cplusplus
}
#endif
.m
/*
* cocos2d for iPhone: http://www.cocos2d-iphone.org
*
* Copyright (c) 2008-2010 Ricardo Quesada
* Copyright (c) 2011 Zynga Inc.
*
* 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.
*
*/
#import "CCFileUtils.h"
#import "../CCConfiguration.h"
#import "../ccMacros.h"
#import "../ccConfig.h"
#import "../ccTypes.h"
enum {
kCCiPhone,
kCCiPhoneRetinaDisplay,
kCCiPhone5Display,
kCCiPad,
kCCiPadRetinaDisplay,
};
#pragma mark - Helper free functions
NSInteger ccLoadFileIntoMemory(const char *filename, unsigned char **out)
{
NSCAssert( out, @"ccLoadFileIntoMemory: invalid 'out' parameter");
NSCAssert( &*out, @"ccLoadFileIntoMemory: invalid 'out' parameter");
size_t size = 0;
FILE *f = fopen(filename, "rb");
if( !f ) {
*out = NULL;
return -1;
}
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
*out = malloc(size);
size_t read = fread(*out, 1, size, f);
if( read != size ) {
free(*out);
*out = NULL;
return -1;
}
fclose(f);
return size;
}
#pragma mark - CCCacheValue
@interface CCCacheValue : NSObject
{
NSString *fullpath_;
ccResolutionType resolutionType_;
}
@property (nonatomic, readwrite, retain) NSString *fullpath;
@property (nonatomic, readwrite ) ccResolutionType resolutionType;
@end
@implementation CCCacheValue
@synthesize fullpath = fullpath_, resolutionType = resolutionType_;
-(id) initWithFullPath:(NSString*)path resolutionType:(ccResolutionType)resolutionType
{
if( (self=[super init]) )
{
self.fullpath = path;
self.resolutionType = resolutionType;
}
return self;
}
- (void)dealloc
{
[fullpath_ release];
[super dealloc];
}
@end
#pragma mark - CCFileUtils
#ifdef __CC_PLATFORM_IOS
@interface CCFileUtils()
-(NSString *) removeSuffix:(NSString*)suffix fromPath:(NSString*)path;
-(BOOL) fileExistsAtPath:(NSString*)string withSuffix:(NSString*)suffix;
-(NSInteger) runningDevice;
@end
#endif // __CC_PLATFORM_IOS
@implementation CCFileUtils
@synthesize fileManager=fileManager_, bundle=bundle_;
#ifdef __CC_PLATFORM_IOS
@synthesize iPhoneRetinaDisplaySuffix = iPhoneRetinaDisplaySuffix_;
@synthesize iPhone5DisplaySuffix = iPhone5DisplaySuffix_;
@synthesize iPadSuffix = iPadSuffix_;
@synthesize iPadRetinaDisplaySuffix = iPadRetinaDisplaySuffix_;
@synthesize enableFallbackSuffixes = enableFallbackSuffixes_;
#endif // __CC_PLATFORM_IOS
+ (id)sharedFileUtils
{
static dispatch_once_t pred;
static CCFileUtils *fileUtils = nil;
dispatch_once(&pred, ^{
fileUtils = [[self alloc] init];
});
return fileUtils;
}
-(id) init
{
if( (self=[super init])) {
fileManager_ = [[NSFileManager alloc] init];
fullPathCache_ = [[NSMutableDictionary alloc] initWithCapacity:30];
removeSuffixCache_ = [[NSMutableDictionary alloc] initWithCapacity:30];
bundle_ = [[NSBundle mainBundle] retain];
#ifdef __CC_PLATFORM_IOS
iPhoneRetinaDisplaySuffix_ = @"-hd";
iPhone5DisplaySuffix_ = @"-568h";
iPadSuffix_ = @"-ipad";
iPadRetinaDisplaySuffix_ = @"-ipadhd";
enableFallbackSuffixes_ = NO;
#endif // __CC_PLATFORM_IOS
}
return self;
}
-(void) purgeCachedEntries
{
[fullPathCache_ removeAllObjects];
[removeSuffixCache_ removeAllObjects];
}
- (void)dealloc
{
[fileManager_ release];
[bundle_ release];
[fullPathCache_ release];
[removeSuffixCache_ release];
#ifdef __CC_PLATFORM_IOS
[iPhoneRetinaDisplaySuffix_ release];
[iPhone5DisplaySuffix_ release];
[iPadSuffix_ release];
[iPadRetinaDisplaySuffix_ release];
#endif // __CC_PLATFORM_IOS
[super dealloc];
}
-(NSString*) pathForResource:(NSString*)resource ofType:(NSString *)ext inDirectory:(NSString *)subpath
{
return [bundle_ pathForResource:resource
ofType:ext
inDirectory:subpath];
}
-(NSString*) getPath:(NSString*)path forSuffix:(NSString*)suffix
{
NSString *newName = path;
// only recreate filename if suffix is valid
if( suffix && [suffix length] > 0)
{
NSString *pathWithoutExtension = [path stringByDeletingPathExtension];
NSString *name = [pathWithoutExtension lastPathComponent];
// check if path already has the suffix.
if( [name rangeOfString:suffix].location == NSNotFound ) {
NSString *extension = [path pathExtension];
if( [extension isEqualToString:@"ccz"] || [extension isEqualToString:@"gz"] )
{
// All ccz / gz files should be in the format filename.xxx.ccz
// so we need to pull off the .xxx part of the extension as well
extension = [NSString stringWithFormat:@"%@.%@", [pathWithoutExtension pathExtension], extension];
pathWithoutExtension = [pathWithoutExtension stringByDeletingPathExtension];
}
newName = [pathWithoutExtension stringByAppendingString:suffix];
newName = [newName stringByAppendingPathExtension:extension];
} else
CCLOGWARN(@"cocos2d: WARNING Filename(%@) already has the suffix %@. Using it.", name, suffix);
}
NSString *ret = nil;
// only if it is not an absolute path
if( ! [path isAbsolutePath] ) {
// pathForResource also searches in .lproj directories. issue #1230
NSString *imageDirectory = [path stringByDeletingLastPathComponent];
// If the file does not exist it will return nil.
ret = [self pathForResource:[newName lastPathComponent]
ofType:nil
inDirectory:imageDirectory];
}
else if( [fileManager_ fileExistsAtPath:newName] )
ret = newName;
if( ! ret )
CCLOGINFO(@"cocos2d: CCFileUtils: file not found: %@", [newName lastPathComponent] );
return ret;
}
-(NSString*) fullPathFromRelativePath:(NSString*)relPath resolutionType:(ccResolutionType*)resolutionType
{
NSAssert(relPath != nil, @"CCFileUtils: Invalid path");
CCCacheValue *value = [fullPathCache_ objectForKey:relPath];
if( value ) {
*resolutionType = value.resolutionType;
return value.fullpath;
}
// Initialize to non-nil
NSString *ret = @"";
#ifdef __CC_PLATFORM_IOS
NSInteger device = [self runningDevice];
// iPad HD ?
if( device == kCCiPadRetinaDisplay ) {
ret = [self getPath:relPath forSuffix:iPadRetinaDisplaySuffix_];
*resolutionType = kCCResolutioniPadRetinaDisplay;
}
// iPad ?
if( device == kCCiPad || (enableFallbackSuffixes_ && !ret) ) {
ret = [self getPath:relPath forSuffix:iPadSuffix_];
*resolutionType = kCCResolutioniPad;
}
// iPhone HD ?
if( device == kCCiPhoneRetinaDisplay || (enableFallbackSuffixes_ && !ret) ) {
ret = [self getPath:relPath forSuffix:iPhoneRetinaDisplaySuffix_];
*resolutionType = kCCResolutioniPhoneRetinaDisplay;
}
// If it is not Phone HD, or if the previous "getPath" failed, then use iPhone images.
if( device == kCCiPhone || !ret )
{
ret = [self getPath:relPath forSuffix:@""];
*resolutionType = kCCResolutioniPhone;
}
#elif defined(__CC_PLATFORM_MAC)
*resolutionType = kCCResolutionMac;
ret = [self getPath:relPath forSuffix:@""];
#endif // __CC_PLATFORM_MAC
if( ! ret ) {
CCLOGWARN(@"cocos2d: Warning: File not found: %@", relPath);
ret = relPath;
}
value = [[CCCacheValue alloc] initWithFullPath:ret resolutionType:*resolutionType];
[fullPathCache_ setObject:value forKey:relPath];
[value release];
return ret;
}
-(NSString*) fullPathFromRelativePath:(NSString*) relPath
{
ccResolutionType ignore;
return [self fullPathFromRelativePath:relPath resolutionType:&ignore];
}
#pragma mark CCFileUtils - Suffix (iOS only)
#ifdef __CC_PLATFORM_IOS
// XXX: Optimization: This should be called only once
-(NSInteger) runningDevice
{
NSInteger ret=-1;
if( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
if( CC_CONTENT_SCALE_FACTOR() == 2 )
ret = kCCiPadRetinaDisplay;
else
ret = kCCiPad;
}
else
{
if( CC_CONTENT_SCALE_FACTOR() == 2 )
if (([[UIScreen mainScreen] bounds].size.width == 640) || ([[UIScreen mainScreen] bounds].size.width == 1136))
{
ret = kCCiPhone5Display;
} else {
ret = kCCiPhoneRetinaDisplay;
}
else
ret = kCCiPhone;
}
return ret;
}
-(NSString *) removeSuffix:(NSString*)suffix fromPath:(NSString*)path
{
// quick return
if( ! suffix || [suffix length] == 0 )
return path;
NSString *name = [path lastPathComponent];
// check if path already has the suffix.
if( [name rangeOfString:suffix].location != NSNotFound ) {
CCLOGINFO(@"cocos2d: Filename(%@) contains %@ suffix. Removing it. See cocos2d issue #1040", path, suffix);
NSString *newLastname = [name stringByReplacingOccurrencesOfString:suffix withString:@""];
NSString *pathWithoutLastname = [path stringByDeletingLastPathComponent];
return [pathWithoutLastname stringByAppendingPathComponent:newLastname];
}
// suffix was not removed
return nil;
}
-(NSString*) removeSuffixFromFile:(NSString*) path
{
NSString *withoutSuffix = [removeSuffixCache_ objectForKey:path];
if( withoutSuffix )
return withoutSuffix;
// Initial value should be non-nil
NSString *ret = @"";
NSInteger device = [self runningDevice];
if( device == kCCiPadRetinaDisplay )
ret = [self removeSuffix:iPadRetinaDisplaySuffix_ fromPath:path];
if( device == kCCiPad || (enableFallbackSuffixes_ && !ret) )
ret = [self removeSuffix:iPadSuffix_ fromPath:path];
if( device == kCCiPhoneRetinaDisplay || (enableFallbackSuffixes_ && !ret) )
ret = [self removeSuffix:iPhoneRetinaDisplaySuffix_ fromPath:path];
if( device == kCCiPhone5Display || (enableFallbackSuffixes_ && !ret) )
ret = [self removeSuffix:iPhone5DisplaySuffix_ fromPath:path];
if( device == kCCiPhone || !ret )
ret = path;
if( ret )
[removeSuffixCache_ setObject:ret forKey:path];
return ret;
}
-(BOOL) fileExistsAtPath:(NSString*)relPath withSuffix:(NSString*)suffix
{
NSString *fullpath = nil;
// only if it is not an absolute path
if( ! [relPath isAbsolutePath] ) {
// pathForResource also searches in .lproj directories. issue #1230
NSString *file = [relPath lastPathComponent];
NSString *imageDirectory = [relPath stringByDeletingLastPathComponent];
fullpath = [bundle_ pathForResource:file
ofType:nil
inDirectory:imageDirectory];
}
if (fullpath == nil)
fullpath = relPath;
NSString *path = [self getPath:fullpath forSuffix:suffix];
return ( path != nil );
}
-(BOOL) iPhoneRetinaDisplayFileExistsAtPath:(NSString*)path
{
return [self fileExistsAtPath:path withSuffix:iPhoneRetinaDisplaySuffix_];
}
-(BOOL) iPhone5DisplayFileExistsAtPath:(NSString*)path
{
return [self fileExistsAtPath:path withSuffix:iPhoneRetinaDisplaySuffix_];
}
-(BOOL) iPadFileExistsAtPath:(NSString*)path
{
return [self fileExistsAtPath:path withSuffix:iPadSuffix_];
}
-(BOOL) iPadRetinaDisplayFileExistsAtPath:(NSString*)path
{
return [self fileExistsAtPath:path withSuffix:iPadRetinaDisplaySuffix_];
}
#endif // __CC_PLATFORM_IOS
@end