DNESS / cocos2d-iphone

Automatically exported from code.google.com/p/cocos2d-iphone
1 stars 0 forks source link

When Retina is enabled we should scale up images that don't have the -hd suffix #1118

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Enable Retina
2. Add file.png to project
3. Run on a retina and non-retina device - image is scaled down on the retina 
device
4. Add file-hd.png
5. Run on retina / non retina device - looks fine

What is the expected output? What do you see instead?
The expected behaviour is for cocos2d games to have a consistent user 
experience between retina and non-retina, even if all art assets do not have a 
-hd.png included.

If we're on a retina device, and the -hd image is not present, the low res 
image should be used and scaled up.

THis is so that when we make a game in low res and we decide to add retina 
support, we should just be able to drop in "-hd.png" for art assets and cocos 
should automatically use the high res images which exist, and continue to use 
the low res ones for those that don't have a -hd.png.

What cocos2d version / SVN revision are you using ?
0.99.5

What iPhoneSDK are you using ?
4.2.1

Debug or Release ?
Both

Does this happens on device ? or on the simulator ? or on both ?
Both

Please provide any additional information below.

Original issue reported on code.google.com by asad.reh...@gmail.com on 25 Feb 2011 at 10:07

GoogleCodeExporter commented 9 years ago
Hello! Why don't you scale the sprite image, with a formula based on the screen 
size. Something like: 

scaleRatio =  screen.width / image.width;

Or you can mantain the aspect ratio, to fill the width or the heigth;

scaleRatio =  MAX(screen.width / image.width, screen.heigth / image.heigth);

Original comment by conradci...@gmail.com on 26 Feb 2011 at 5:58

GoogleCodeExporter commented 9 years ago

Original comment by ricardoq...@gmail.com on 26 Feb 2011 at 10:05

GoogleCodeExporter commented 9 years ago
We can scale using CC_CONTENT_SCALE_FACTOR() for all low res CCSprites, but 
since the -hd suffix check is in the CCFileUtils class, neither CCTextureCache, 
CCTexture2D or CCSprite know whether the loaded image was -hd or not.

Original comment by asad.reh...@gmail.com on 26 Feb 2011 at 11:37

GoogleCodeExporter commented 9 years ago
I've posted my experiences with auto upscaling here:

http://www.cocos2d-iphone.org/forum/topic/13935

Note though this is more of a dirty hack described there that only covers 
certain configurations, and is only meant as a reference to people trying to 
role out their own version.

Original comment by patr...@subzero.eu on 1 Mar 2011 at 9:49

GoogleCodeExporter commented 9 years ago
The current implementation is bugged.  CCFileUtils's fullPathFromRelativePath 
is the *wrong* place to be adding the -hd suffix.  This method is used for many 
more things than just image resources.

I propose fullPathFromRelativePath stops doing the getDoubleResolutionImage 
call, and instead, whomever uses it should check whether content scaling is 
desired, and if so, try to find a scaled image resource.  If no scaled image 
resource can be found, it should load the sd resource and scale it up 
accordingly.  This can only be done by the class that handles the resource's 
data, NOT by a genericish file utils class.

Here's a quick and dirty and incomplete patch which fixes this issue for me:

diff --git a/cocos2d/CCTextureCache.m b/cocos2d/CCTextureCache.m
index 52a5678..73af45b 100644
--- a/cocos2d/CCTextureCache.m
+++ b/cocos2d/CCTextureCache.m
@@ -34,6 +34,7 @@
 #import "Support/CCFileUtils.h"
 #import "CCDirector.h"
 #import "ccConfig.h"
+#import "UIImage_Scaling.h"

 // needed for CCCallFuncO in Mac-display_link version
 #import "CCActionManager.h"
@@ -266,13 +267,24 @@ static CCTextureCache *sharedTextureCache;
                  ( [lowerCase hasSuffix:@".jpg"] || [lowerCase hasSuffix:@".jpeg"] ) 
                 ) {
            // convert jpg to png before loading the texture
-           
+            BOOL scaleToHD = NO;
            NSString *fullpath = [CCFileUtils fullPathFromRelativePath: path ];
-                       
+#if CC_IS_RETINA_DISPLAY_SUPPORTED
+            if( CC_CONTENT_SCALE_FACTOR() == 2 ) {
+                NSString *fullpathHD = [CCFileUtils 
getDoubleResolutionImage:fullpath];
+                if (fullpathHD)
+                    fullpath = fullpathHD;
+                else
+                    // Only SD version available for this image, scale it up.
+                    scaleToHD = YES;
+            }
+#endif // CC_IS_RETINA_DISPLAY_SUPPORTED
+           
            UIImage *jpg = [[UIImage alloc] initWithContentsOfFile:fullpath];
-           UIImage *png = [[UIImage alloc] initWithData:UIImagePNGRepresentation(jpg)];
+           UIImage *png = [[[UIImage alloc] 
initWithData:UIImagePNGRepresentation(jpg)] autorelease];
+            if (scaleToHD)
+                png = [png 
imageByScalingAndCroppingToSize:CGSizeApplyAffineTransform(png.size, 
CGAffineTransformMakeScale(2, 2))];
            tex = [ [CCTexture2D alloc] initWithImage: png ];
-           [png release];
            [jpg release];

            if( tex )
@@ -286,11 +298,23 @@ static CCTextureCache *sharedTextureCache;
        else {

            // prevents overloading the autorelease pool
+            BOOL scaleToHD = NO;
            NSString *fullpath = [CCFileUtils fullPathFromRelativePath: path ];
-
-           UIImage *image = [ [UIImage alloc] initWithContentsOfFile: fullpath ];
+#if CC_IS_RETINA_DISPLAY_SUPPORTED
+            if( CC_CONTENT_SCALE_FACTOR() == 2 ) {
+                NSString *fullpathHD = [CCFileUtils 
getDoubleResolutionImage:fullpath];
+                if (fullpathHD)
+                    fullpath = fullpathHD;
+                else
+                    // Only SD version available for this image, scale it up.
+                    scaleToHD = YES;
+            }
+#endif // CC_IS_RETINA_DISPLAY_SUPPORTED
+
+           UIImage *image = [[ [UIImage alloc] initWithContentsOfFile: fullpath ] 
autorelease];
+            if (scaleToHD)
+                image = [image 
imageByScalingAndCroppingToSize:CGSizeApplyAffineTransform(image.size, 
CGAffineTransformMakeScale(2, 2))];
            tex = [ [CCTexture2D alloc] initWithImage: image ];
-           [image release];

            if( tex )
                [textures_ setObject: tex forKey:path];
@@ -303,12 +327,24 @@ static CCTextureCache *sharedTextureCache;
        // Only in Mac
 #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
        else {
+            BOOL scaleToHD = NO;
            NSString *fullpath = [CCFileUtils fullPathFromRelativePath: path ];
+#if CC_IS_RETINA_DISPLAY_SUPPORTED
+            if( CC_CONTENT_SCALE_FACTOR() == 2 ) {
+                NSString *fullpathHD = [CCFileUtils 
getDoubleResolutionImage:fullpath];
+                if (fullpathHD)
+                    fullpath = fullpathHD;
+                else
+                    // Only SD version available for this image, scale it up.
+                    scaleToHD = YES;
+            }
+#endif // CC_IS_RETINA_DISPLAY_SUPPORTED

            NSData *data = [[NSData alloc] initWithContentsOfFile:fullpath];
            NSBitmapImageRep *image = [[NSBitmapImageRep alloc] initWithData:data];
            tex = [ [CCTexture2D alloc] initWithImage:[image CGImage]];
-           
+            if (scaleToHD)
+                tex.scale = 2;
            [data release];
            [image release];

diff --git a/cocos2d/Support/CCFileUtils.h b/cocos2d/Support/CCFileUtils.h
index d906c69..c261fb7 100644
--- a/cocos2d/Support/CCFileUtils.h
+++ b/cocos2d/Support/CCFileUtils.h
@@ -32,6 +32,8 @@
 {
 }

++(NSString*) getDoubleResolutionImage:(NSString*)path;
+
 /** Returns the fullpath of an filename.

  If this method is when Retina Display is enabled, then the
diff --git a/cocos2d/Support/CCFileUtils.m b/cocos2d/Support/CCFileUtils.m
index ff0be83..3083230 100644
--- a/cocos2d/Support/CCFileUtils.m
+++ b/cocos2d/Support/CCFileUtils.m
@@ -99,45 +99,36 @@ NSString *ccRemoveHDSuffixFromFile( NSString *path )

 +(NSString*) getDoubleResolutionImage:(NSString*)path
 {
-#if CC_IS_RETINA_DISPLAY_SUPPORTED
-
-   if( CC_CONTENT_SCALE_FACTOR() == 2 )
-   {
-       
-       NSString *pathWithoutExtension = [path stringByDeletingPathExtension];
-       NSString *name = [pathWithoutExtension lastPathComponent];
-       
-       // check if path already has the suffix.
-       if( [name rangeOfString:CC_RETINA_DISPLAY_FILENAME_SUFFIX].location != 
NSNotFound ) {
-       
-           CCLOG(@"cocos2d: WARNING Filename(%@) already has the suffix %@. Using 
it.", name, CC_RETINA_DISPLAY_FILENAME_SUFFIX);         
-           return path;
-       }
-
-       
-       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];
-       }
-       
-       
-       NSString *retinaName = [pathWithoutExtension 
stringByAppendingString:CC_RETINA_DISPLAY_FILENAME_SUFFIX];
-       retinaName = [retinaName stringByAppendingPathExtension:extension];
-
-       if( [__localFileManager fileExistsAtPath:retinaName] )
-           return retinaName;
-
-       CCLOG(@"cocos2d: CCFileUtils: Warning HD file not found: %@", [retinaName 
lastPathComponent] );
-   }
-   
-#endif // CC_IS_RETINA_DISPLAY_SUPPORTED
-   
-   return path;
+    NSString *pathWithoutExtension = [path stringByDeletingPathExtension];
+    NSString *name = [pathWithoutExtension lastPathComponent];
+    
+    // check if path already has the suffix.
+    if( [name rangeOfString:CC_RETINA_DISPLAY_FILENAME_SUFFIX].location != 
NSNotFound ) {
+    
+        CCLOG(@"cocos2d: WARNING Filename(%@) already has the suffix %@. Using 
it.", name, CC_RETINA_DISPLAY_FILENAME_SUFFIX);         
+        return path;
+    }
+
+    
+    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];
+    }
+    
+    
+    NSString *retinaName = [pathWithoutExtension 
stringByAppendingString:CC_RETINA_DISPLAY_FILENAME_SUFFIX];
+    retinaName = [retinaName stringByAppendingPathExtension:extension];
+
+    if( [__localFileManager fileExistsAtPath:retinaName] )
+        return retinaName;
+
+    CCLOG(@"cocos2d: CCFileUtils: Warning HD file not found: %@", [retinaName 
lastPathComponent] );
+   return nil;
 }

 +(NSString*) fullPathFromRelativePath:(NSString*) relPath
@@ -160,8 +151,6 @@ NSString *ccRemoveHDSuffixFromFile( NSString *path )
    if (fullpath == nil)
        fullpath = relPath;

-   fullpath = [self getDoubleResolutionImage:fullpath];
-   
    return fullpath;    
 }

Original comment by lhunath on 18 May 2011 at 10:26

GoogleCodeExporter commented 9 years ago
Note: the patch uses UIImage_Scaling.  See: 
http://stackoverflow.com/questions/603907/uiimage-resize-then-crop/605385#605385

Original comment by lhunath on 18 May 2011 at 10:28

GoogleCodeExporter commented 9 years ago
Ideally, a class method should be added to TextureCache that does up-scaling of 
images (removing the need for UIImage_Scaling) and the logic for addImage 
should be sanitized so it's not full of copy-paste duplicate code which makes 
it a PITA to add logic to it.

Original comment by lhunath on 18 May 2011 at 10:29

GoogleCodeExporter commented 9 years ago
cocos2d should have a class that loads the correct assest (image, spritesheet 
metadata, tmx map, etc.) for the correct resolution. For the moment CCFileUtils 
is doing it.
If I understood your patch correctly, only upscales images, and leaves behind 
other assets like TMX maps, Spritesheets metadata, etc.

Original comment by ricardoq...@gmail.com on 18 May 2011 at 10:57

GoogleCodeExporter commented 9 years ago
workarounded in v1.1.

CCTexture2D has resolutionType.

<pseudo code>

ccResolutionType res = texture.resolutionType;
if( res == kCCResolutionRetinaDisplay )
 do_something();
else if( res == kCCResolutioniPad )
 do_something_else();

</pseudo code>

Original comment by ricardoq...@gmail.com on 4 Aug 2011 at 3:00