Cocos2d/Cocos2d-x Retina Issues - iphone

I have a multiplatform iOS/Android game that I programmed in Cocos2d-x. I have only one set of images to use (I'm only after high res devices) that get scaled according to the device's resolution. For example all images are for the iPad but if you are using a Galaxy S then the image locations and scaling are affected by GalaxyS_screenWidth/iPadscreenWidth.
This works fine for all Android devices and on iPad, iPad2 and old iPhones, but with Retina iPhone there is a problem. On the iPhone 4 all my images look extremely pixelated, a result from the images being scaled to iPhone non-retina resolution then scaled back up to fill the screen.
I tried enabling Retina Mode and the images are half of their intended size (maybe due to the usage of get winsize() which uses points) and scaling manually causes other sorts of problems. I tried playing with a lot of options and attributes but to no avail, so what should I do now?
EDIT:
This is not only a graphics issue, as text gets automatically scaled down then up and appears pixelated.
EDIT 2:
Fonts are bitmaps so my bad. But I don't want to use retina as all images are already retina by default. All of my images are set up for the iPad so for iPhone 4 I just scale them down a bit. This works with Android phones.
For example I have an image, depending on screen resolution obtained through getwinsize():
If current resolution width is 1024 then image stays the same.
If current resolution width is 900 then image gets scaled by 900/1024, no problem.
If device is iPhone 4 resolution width is 480, so image gets scaled by 480/1024, then cocos2d-x automatically scales the resulting image by 2 thus the pixelation. I tried using getwinsizeinpixels, I tried multiplying the screen size, I tried many things but nothing worked out of the box unless I am to redo many of my code.
So the question is, how can I just let the damn engine treat the iPhone 4 as an Android phone with resolution of 960x640?

If you want Retina resolution images to look like Retina resolution images, then those images need to be in Retina resolution (960x480).
If you first scale down the image to 480x320 and then upscale it on the device, it will of course look blurred. You can't magically make the Retina pixels appear from a lower resolution image by scaling it up.

SI couldn't get to the bottom of it so I employed a hack. I enabled Retina Display then I scaled everything x2 through code except for the text. Sounds stupid, but it worked, and pixelation is gone. Thanks everyone who spent time trying to help me.

I tried enabling Retina Mode and the images are half of their intended size
when you enable retina support, cocos2d gets images by appending #"-hd" to their provided filenames. Such images are meant to be double the "visual" size (in iOS terms, pixels vs. points), so that they can be sort of scaled down to make full use of device resolution.
If you have a look at the CCDirectorIOS class, you will find there a couple of methods dealing with this, especially those dealing with the scalingFactor. I don't know what kind of changes you should do to make it work, but if you step into those methods and look at the value of various objects, you might find a way to modify cocos2D default behavior for your specific case.
If this seems to complicated, one thing you could try is changing the CC_RETINA_DISPLAY_FILENAME_SUFFIX so that cocos2d will not look for specially-named files for the retina iPhone, but just use the normal ones.
For example all images are for the iPad but if you are using a Galaxy S then the image locations and scaling are affected by GalaxyS_screenWidth/iPadscreenWidth.
Another thing you might try is not using winSize, but winSizeInPixels, so that when you scale down, you down do it down to the point resolution, but just to the pixel resolution (which is double the point resolution).
Hope this helps.

Related

Use only retina images in cocos2d

I am using 2 images: image.png and image-hd.png and it works fine for retina and non-retina too.
But what I want to do now is to remove all non-retina images and leave only retina images. I heard that a non-retina device will scale the image down itself. I tried it but it didn't work :( How I do this? What name should I give to the image that it will show picture its actually size on retina and for non-retina will be scaled down?
No, Retina images are not scaled down automatically.
Only using Retina images and using them scaled down on standard resolution display devices is a bad idea.
Non-Retina devices have far less memory than Retina devices, but you're forcing them to load the Retina resolution images. In other words: device has half the memory, but is forced to load images that consume four times as much texture memory as need be.
Non-Retina devices have slower GPU & CPU. But you're forcing them to work on four times the number of pixels. Performance suffers.
You probably need to scale it down manually. I'm not sure if thats the best idea.
But I think you can just scale down the images to 0.5 if in retina device.
About images, its important to remember that each image is taking memory according to the size of the next power 2 dimensions. Which means that 20X20 pic will take the same memory as 32X32, and 130X260 will take 256X512.
So sometimes just handling your image sizes better or using something like Sprite Sheet.

What happens if #2x image is available but not regular resolution image?

I'm wondering what will happen on a non-retina display device if only the #2x image is copied to the resources? Will it scale down the retina display image by 0.5 to accommodate the frame of the UIImageView?
I hope this isn't a silly question!
The high resolution #2x images are not automatically down-sampled on non-retina devices.
Apple did not implement such feature because non-retina devices generally don't have enough memory to load and down-sample many high resolution images during initialization, it might cause trouble in case too many images need to be initialized.
EDIT (Based on answer by WendiKidd)
Non-retina devices will however down-size and display the high resolution #2x images, but without down-samling them, which causes poor image quality.
I know for a fact that it will use the #2x images if no regular image is available, because I have tested it myself. (Though I agree with David's comment--this is rather easy to test yourself.) Now the image quality is decreased, because it's trying to resize an image that is much larger than the space you're trying to put it in. But it absolutely will work. Go give it a try and you'll see :)

Not including non-retina display images in an iPhone project

I have an iPhone Xcode project that currently only contains images for retina display (twice the size as normal and with a #2x.png suffix). When I run the app on the iPhone Simulator (non retina) the images are still being displayed. Does this mean I don't need to worry about including two sets of images: retina and non-retina?
This all seems a bit odd. I would assume that no images would appear on a non retina device if there are no non-#2x files included.
Note: I have not tested my app on a non retina device. Just the simulator.
I'm pretty sure that iOS will just use the #2x and scale it down if you don't have a non-retina graphic. Although that's sub-optimal since you're letting iOS do the scaling at runtime which will be slower than including the non-retina graphic and also iOS might not do as good a job as scaling as your graphics editor of choice.
Even if it works, it's not good practice, and if you have a media heavy app definitely it would impact performance and battery life and memory foot print and ....
By the way, is it just that you don't have the 1x graphics available to you or you are concerned about your apps (download size) or ...
If you are assigning the images in Interface Builder, and you set the image property on a UIImageView to image#2x.png, for example, iOS will not know that it's a high resolution "2x" image. In fact, on a retina display, iOS will look for an image named image#2x#2x.png. Since it won't find it, it will set the scale factor of the image to 1.0.
The contentMode property (just "mode" in XCode) will decide if any scaling of the image occurs to fit the constraints of the UIImageView. You may wish to set the mode to "Aspect Fit" to get the high resolution image to scale as needed for both retina and non-retina displays. In general, the image will display as seen in Interface Builder.
If you are using UIImage's imageNamed or similar function to load the image, and just specify image (where "image.png" doesn't exist, but "image#2x.png" does), then iOS will actually find the image on a non-retina display, though the scale factor will be 1.0. As previously, you'll need to scale it to fit your view. The image will work normally on a retina device, and the scale factor will be set to 2.0, since iOS looks for a "2x" image first, and it doesn't matter if the other file exists or not.
This is from Apple's documentation on imageNamed:
On a device running iOS 4 or later, the behavior is identical if the
device’s screen has a scale of 1.0. If the screen has a scale of 2.0,
this method first searches for an image file with the same filename
with an #2x suffix appended to it. For example, if the file’s name is
button, it first searches for button#2x. If it finds a 2x, it loads
that image and sets the scale property of the returned UIImage object
to 2.0. Otherwise, it loads the unmodified filename and sets the scale
property to 1.0. See iOS App Programming Guide for more information on
supporting images with different scale factors.
If at all possible, you really should include both retina and non-retina images. Using higher-resolution images than necessary negatively affects memory and performance.

iPhone memory warning for high resolution images

I have an app which display images in full Screen. Some of the images are 1952x3680 pixels and these images are raising memory warning level=1 and level=2.
How should i handle these image?
Scale your images down considerably. There is absolutely no reason you need images at that resolution in an iPhone app.
Don't use them. Either get your server to deliver a thumbnail version of the image (maybe using a thumb.php/jsp/asp/... file with GET params x=<width>&y=<height>), or scale the image down on the iPhone and discard the original data. The former method is vastly preferred as it saves on both bandwidth and large memory allocations client-side.
The largest images you should be working with are 480x320 (iPhone 3GS and earlier) and 960x640 (iPhone 4).
EDIT: The other situation I didn't think of is if you're bundling these images with the app. Please, please don't do that. If you have images that big, scale them down in Apple's Preview or any image editor to the sizes noted, and ideally have two copies, image.png and image#2x.png which are shown depending on the scale of the device's screen.
The screen itself is only 320x460 (not considering the clock bar on top), and 640x960 for retina display. There is no reason to have images this large to begin with. Scale them down. It'll both prevent the memory warnings and stymie unnecessary image size.
As said before, scale it down if you only want to show the image without zooming in fullscreen.
If you need to zoom and show it detailed, google for CATiledLayer. There are good examples around.

Upgrading a cocos2d iPhone game to work at iPhone4 resolution using #2x

I am trying to add art to my game for the iPhone4 resolution. The images i am using are twice the original and i have added the #2x suffix to the image names.
When i load in a sprite like this:
[CCSprite spritewithFile:#"example.png"];
where example.png is the original image and example#2x.png is the scaled up version. When running on the original iPhone it loads the low res image and when running on the iPHone4 it loads the high res image, but it doubles the size of the image. So the high res image appears the same on the iPhone4 as on the original iPhone. Each pixel on the image takes up 4 pixels on the screen.
Any idea why this might be happening? Is there something I am supposed to do to tell the app not to double the size of the art?
Are you using the latest version of cocos2d?
The entire cocos2d API was converted
to Points. Previous versions were
using Pixels.
If your using v0.99.4:
cocos2d v0.99.4 has RetinaDisplay
support, however it required you to
use two different sets of positions
depending on the device , since the
API was in Pixels. (more)
If your using >= v0.99.5-rc0
But in v0.99.5-rc0 (and newer) the only thing that you have to do is[...] (more)
Have you read the "Retina Display in cocos2d" section of the cocos2d for iPhone wiki? (It pretty much tells you all you need to know.)