Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Understanding Letterbox Scalling
Started by RicardoGraca Mar 12 2012 03:03 AM

- - - - -
91 replies to this topic
[TOPIC CONTROLS]
Page 1 of 4 1 2 3 »
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

RicardoGraca

[GLOBAL: userInfoPane.html]
RicardoGraca
  • Contributor

  • 190 posts
  • Corona SDK

Hi all,

I've replied to a post recently about how letterbox scalling works and since then I've bumped into a lot of people having trouble with the subject to whom I've been linking that old post.
As I came to the realization that it is quite an important subject and one that people don't understand too well, I'm creating a thread of its own, so here it goes:

<< Start of repost >>

Let's assume you're coding on portrait orientation.

You set your config.lua for a screen of 320x480 pixels, letterbox scalling, and position centered both vertical and horizontal.

application = {
    content = {
        width = 320,
        height = 480,
        scale = "letterbox",
        xAlign = "center",
        yAlign = "center",
    }
}

Now, when you create a background for the game, and you want to target iOS devices, so resolutions 320x480, 640x960 and 768x1024, you should do it like:

local bg = display.newImageRect("bg.png",360,480)
bg.x = display.contentWidth/2
bg.y = display.contentHeight/2

The resolution of the image files should be:

bg.png - 360x480
bg@2.png - 720x960, or even 768x1024 if you want it to look really good on iPad.

Why this 360 pixel width?

Well, the thing is that with letter box, the images on higher resolutions than defined on config.lua will be scaled to fit the screen, but they won't lose their aspect ratio, and that 320x480 rectangle you define on config.lua never goes out off screen.

Let's see some examples. Start by assuming we did things the "normal" way. You call background images as 320x480, what would happen is:

iPhone - No scalling, config.lua already defines a rectangle of the size of the screen, so it would look fine.

iPhone4 - Scaling by a factor of 2, so the ratio is the same. Would look fine too, it would use double resolution image (640x960)

iPad - the 320x480 rect would grow by a factor of 2.1333.., ending up at a size of 682x1024. Since the iPad has a 768x1024 screen, you would notice some black bars on the sides.

Now lets assume you did as I said and called background images as 360x480.

iPhone - No scalling since config.lua defines a rectangle of screen size. The background though is a bit bigger for the screen and has some extra width compared to screen size. Since the background is centered, you would actualy not see some pixels to the sides. More exactly, 360-320 = 40, so 20 pixels to each side.

iPhone4 - Exactly the same case but on higher resolution, scalling by a factor of 2, usage of high res images.

iPad - Once again it will grow by a factor of 2.133, so a 360x480 images would grow to 768x1024, completely filling the iPad screen. No black bars. Usage of high resolution images.

Basically, using this you create the backgrounds with some extra areas that will only be shown when the screen has a different ratio. The screen will always be filled. You have to keep in mind though that anything out of the 320x480 center rectangle of an image (considering low res images), will not show on some devices, so don't base you game in that areas, use it just for filling.

On Android the case is a bit different since the screen is actually taller (on portrait). So instead of having to increase width of background images from 320 to 360, you have to increase their height, from 480 to...
Well, considering all available android devices that number is 570.

In the case you want to completely support all resolutions of all phones/tablets available today, you should:

config.lua:

application = {
    content = {
        width = 320,
        height = 480,
        scale = "letterbox",
        xAlign = "center",
        yAlign = "center",
    }
}

Instantiation of images for backgrounds:
local bg = display.newImageRect("bg.png",360,570)
bg.x = display.contentWidth/2
bg.y = display.contentHeight/2

Low res images: 360x570 pixels
High res images: 720x1120 pixels
Remember that when you're coding though, you're coding for the rect defined on config.lua, so you're coding for a screen of 320x480. If for example on iPad you want to refer to the left of the screen it will not be 0, as 0 is a bit distant from the border, as iPad is wider and this 320x480 rect preserves aspect ratio. So you should actualy rely on some corona defined values to help you. For any device you can define the top, left, right and bottom points as:

Top:
local topY = display.screenOriginY

Right:
local rightX = display.contentWidth - display.screenOriginX

Bottom:
local bottomY = display.contentHeight - display.screenOriginY

Left:
local rightX = display.screenOriginX

Hope this helps everyone to understand letterbox a bit better!

<< End of repost >>

--
Manuel
uid: 61899 topic_id: 23200 reply_id: 323200

  • lsoaresesilva7, alzaabi98, elifares and 1 other like this

[TOPIC: post.html]
#2

@RSCdev

[GLOBAL: userInfoPane.html]
@RSCdev
  • Corona Geek

  • 1,489 posts
  • Corona SDK

Clap, clap, clap...

I thank you for such explanation @CluelessIdeas.
Cheers,
Rodrigo.
uid: 89165 topic_id: 23200 reply_id: 92834


[TOPIC: post.html]
#3

peach pellen

[GLOBAL: userInfoPane.html]
peach pellen
  • Corona Geek

  • 8,866 posts
  • Alumni

Fantastic share! I imagine this will help a lot of developers :)
uid: 52491 topic_id: 23200 reply_id: 92965


[TOPIC: post.html]
#4

topthat

[GLOBAL: userInfoPane.html]
topthat
  • Observer

  • 24 posts
  • Corona SDK

So far, this seems to be a brilliant solution. Is there a way to make this more prominent in the documentation? It seems to me that it would be an ideal framework for people to work with
uid: 87911 topic_id: 23200 reply_id: 94731


[TOPIC: post.html]
#5

topthat

[GLOBAL: userInfoPane.html]
topthat
  • Observer

  • 24 posts
  • Corona SDK

I've been playing with this code a bit, and wondered if there was any fault in the following globals (useful for positioning)
screenWidth = display.contentWidth - (display.screenOriginX*2)screenHeight = display.contentHeight - (display.screenOriginY*2)screenTop = display.screenOriginY + display.screenOriginYscreenRight = display.contentWidth - display.screenOriginXscreenBottom = display.contentHeight - display.screenOriginYscreenLeft = display.screenOriginXscreenCentreX = display.contentWidth/2screenCentreY = display.contentHeight/2
uid: 87911 topic_id: 23200 reply_id: 95707


[TOPIC: post.html]
#6

RicardoGraca

[GLOBAL: userInfoPane.html]
RicardoGraca
  • Contributor

  • 190 posts
  • Corona SDK

There just one wrong:

screenTop = display.screenOriginY

Everything else seems fine.

By the way, if for any reason you want to have screenWidth and screenHeight in real pixels, instead of the abstraction created by what you define in config.lua, you can do it like:

screenWidth = display.contentWidth - (display.screenOriginX*2)
screenRealWidth = screenWidth / display.contentScaleX

screenHeight = display.contentHeight - (display.screenOriginY*2)
screenRealHeight = screenHeight / display.contentScaleY
uid: 61899 topic_id: 23200 reply_id: 95753


[TOPIC: post.html]
#7

topthat

[GLOBAL: userInfoPane.html]
topthat
  • Observer

  • 24 posts
  • Corona SDK

AH well spotted. I think I copy-pasted a bit too much.

Is there a reason why xAlign & yAlign are better set to "center" rather than "left" / "top"? Is this just to keep as much content on screen as possible?

Likewise, is letterbox used over zoomEven because of problems with physics (I read that zoomEven can mess up the physics object positions - perhaps not in the more recent builds of the SDK)

I'm trying to build up a basic project skeleton and want to ensure that it's likely to work on as many devices as possible.
uid: 87911 topic_id: 23200 reply_id: 95757

  • elifares likes this

[TOPIC: post.html]
#8

RicardoGraca

[GLOBAL: userInfoPane.html]
RicardoGraca
  • Contributor

  • 190 posts
  • Corona SDK

That x and y alignment is for the box you define on config.lua, namely the 320x480 I defined in my examples. If you set them to left and top, for example on an iPad, instead of having an extra 20 (virtual) pixels on each side, you'll have 40 extra pixels on the right.

If you do this, when creating a background you can't set it's position for center (or else you'll have some bleeding areas going off screen to the left), you would have to set topleft reference and 0,0 position. This means that the bleeding area you create on your images for background would all have to be on the right (and bottom for androids). This would be extremely assymetrical. You would be positioning the focus of your game to the right, and to the top, instead of making people focus on the center of the device which I suppose makes more sense.

And imagine that you would want to set an element to the center of the screen. I don't even know if that would be possible. You would have to set the X of the element to be in the middle of the 320x480 rect, and then sum some ammount to actualy center it. How much would you have to sum? In this scenario screenOriginX would be 0, so you don't even know dynamicaly how large is the bleeding area to the right.

The problem with zoomEven is that on different ratios, some of the content from the 320x480 rect can go offscreen. What if some important content goes offscreen? The game becomes unplayable! With letterbox you guarantee that nothing inside that rect goes offscreen, so you have a region in which you can base your game, and you're sure that no matter how strange the ratio may be, it can even be 1000:1, nothing important will ever be offscreen.
uid: 61899 topic_id: 23200 reply_id: 95858

  • elifares likes this

[TOPIC: post.html]
#9

Sassa

[GLOBAL: userInfoPane.html]
Sassa
  • Observer

  • 4 posts
  • Corona SDK

Thanks! That post really helped me!
Can i use the same configuration for "landscape" scale?
uid: 76774 topic_id: 23200 reply_id: 98348


[TOPIC: post.html]
#10

RicardoGraca

[GLOBAL: userInfoPane.html]
RicardoGraca
  • Contributor

  • 190 posts
  • Corona SDK

@danillo.vellozo Yes of course. You just have to swap the dimensions of the images when creating them on your game logic. E.g.:
display.newImageRect("bg.png", 570, 360)
instead of what you see in the examples above.
uid: 61899 topic_id: 23200 reply_id: 98485


[TOPIC: post.html]
#11

Omnigeek Media

[GLOBAL: userInfoPane.html]
Omnigeek Media
  • Corona Geek

  • 2,975 posts
  • Corona SDK

This is a most brilliant and well explained post!!!
uid: 19626 topic_id: 23200 reply_id: 98501


[TOPIC: post.html]
#12

davemikesell

[GLOBAL: userInfoPane.html]
davemikesell
  • Contributor

  • 527 posts
  • Corona SDK

First, thanks for taking the time to write this. Math makes my head hurt, so I like "magic recipes". I'm doing almost what you recommend for my landscape app, except I'm using the 570x380 formula recommended here, since the actual size of my normal image is 570x380 pixels.

http://blog.anscamobile.com/2010/11/content-scaling-made-easy/

However, when I call

background = newImageRect("bg.png", 570, 380)
background.x = display.contentWidth/2
background.y = display.contentHeight/2

The image is blown up all the way and bleeds off the edges of the screen, like I called display.newImage("bg.png", true). Is this a bug in build 773? I have to scale it manually:

background.xScale = display.contentWidth / background.contentWidth
background.yScale = display.contentHeight / background.contentHeight

Another question to anyone and everyone. My client is providing me with the graphics, and most screens have the buttons burned into the background image. I'm creating invisible rectangles with touch listeners to get those areas to respond to button clicks, but I'm hardcoding the top, left, width, and height. Is that bad practice and should I be using the predefined Corona constants * a certain factor? If I ever changed my 320x480 in the config.lua, I suppose I would get badly burned by these hardcoded numbers.

uid: 58455 topic_id: 23200 reply_id: 98859


[TOPIC: post.html]
#13

RicardoGraca

[GLOBAL: userInfoPane.html]
RicardoGraca
  • Contributor

  • 190 posts
  • Corona SDK

@davemikesell It should be bleeding by exactly 570 - 480 = 90px or 45px on each side, and 380 - 320 = 60px or 30px on the top and bottom, if you done everything correctly. You seem to be making the same mistake most people do when dealing with image scaling. You're expecting to see the whole image all the time on all devices. That's not what you want. It's supposed to have bleed areas that aren't visible on all devices (e.g. iPhone). The background image is supposed to be bigger than the display.contentWidth and Height. If you scale it down like you do then you're loosing all the benefits of this approach and might as well just use newImageRect("img.png", 480, 320) because that's what you end up with by doing it like you do.

Also, if you followed the guides correctly and have everything working as expected then there's no need to use 380px tall images because the extra 20px will never be seen on any device.
uid: 61899 topic_id: 23200 reply_id: 98928

  • elifares likes this

[TOPIC: post.html]
#14

davemikesell

[GLOBAL: userInfoPane.html]
davemikesell
  • Contributor

  • 527 posts
  • Corona SDK

Actually, it is what I want in this case, as my client is providing me background images with buttons baked into them. I think I either need to get them to stop doing that and send a larger plain background and separate button images, or I'm stuck with this approach, or even using zoomStretch to make sure everything is visible.

Thanks again for this thread, though - I'm learning a lot. I do understand your explanation, I just have a special case with this client.
uid: 58455 topic_id: 23200 reply_id: 98972


[TOPIC: post.html]
#15

davemikesell

[GLOBAL: userInfoPane.html]
davemikesell
  • Contributor

  • 527 posts
  • Corona SDK

One more thing I don't quite understand. Are you saying that if you use newImageRect with an image larger than the resolution set up in config.lua, it won't be scaled at all? That's what you appear to be saying when describing the bleed areas above on the 570x360 image.

Other images on the screen - text, logos, buttons - are scaled depending on which device I render to in the simulator. You can see this for yourself in the DynamicImageResolution sample by getting rid of the suffixes. The 200x200 image is displayed on iPad Retina and other large devices scaled up.

Why would backgrounds be different?
uid: 58455 topic_id: 23200 reply_id: 99747


[TOPIC: post.html]
#16

FortyFourDigital

[GLOBAL: userInfoPane.html]
FortyFourDigital
  • Enthusiast

  • 57 posts
  • Corona SDK

@davemikesell I managed to get these settings working. I found it easiest to draw out an image with pixel markers on it to see how they are displayed on different devices.

As @CluelessIdeas explained, the images are designed to display on iOS with some bleed (the edges of the background image are off the screen) and then on Android, you would see more of this background. The area defined in the settings is more of a "safe zone" that scales inside the device (keeping the aspect ratio). Rather than have black rectangles for any area outside of the safe zone, the bleed area on the background image will be visible instead. If you used a 320x480 background image, you would see the black rectangles.
uid: 140429 topic_id: 23200 reply_id: 99751


[TOPIC: post.html]
#17

RicardoGraca

[GLOBAL: userInfoPane.html]
RicardoGraca
  • Contributor

  • 190 posts
  • Corona SDK

Sorry for the confusion. It will always be scaled if you use a scaling mode on your config.lua. I forgot to mention that the bleed areas I mentioned are in "Corona" units, i.e. in relation to your stage width and height as defined in config.lua.

BTW, you can use buttons baked in using the method mentioned here (instead of the zoom method you seem to be using) as long as the buttons are inside the "safe area". What's the safe area you ask? Take your 570x360 image, put a 480x320 rectangle centered in the middle of it and there you have your safe area. Using the method outlined in this post everything inside this area will always be visible at all times in all devices no matter what the resolution or aspect ratio are.
uid: 61899 topic_id: 23200 reply_id: 99752

  • elifares likes this

[TOPIC: post.html]
#18

FortyFourDigital

[GLOBAL: userInfoPane.html]
FortyFourDigital
  • Enthusiast

  • 57 posts
  • Corona SDK

@CluelessIdeas - that also helped me to see this safe area - made 2 red background images (360x570 and @2x 720x1120) and put a green"safe zone" rectangle right in the middle (320x480 and 640x960 respectively)
uid: 140429 topic_id: 23200 reply_id: 99753

  • elifares likes this

[TOPIC: post.html]
#19

RicardoGraca

[GLOBAL: userInfoPane.html]
RicardoGraca
  • Contributor

  • 190 posts
  • Corona SDK

Just a little bonus for people using this method:

Instead of using 360x570 (and 720x1140) images you can scale those assets to 360x512 (720x1024) after creating them in the proper resolution (360x570) and you won't loose much detail. Remember that you only change the image assets, not the newImageRect values, because you want the Rect to be constant. This will save you a considerable amount of texture memory.
uid: 61899 topic_id: 23200 reply_id: 99754

  • elifares likes this

[TOPIC: post.html]
#20

davemikesell

[GLOBAL: userInfoPane.html]
davemikesell
  • Contributor

  • 527 posts
  • Corona SDK

Thanks for the clarification. If I had my client "bake in" the images in the background in the "safe area", won't the size of the borders look larger/smaller relative to the various device sizes?

Another reason I want to get away from this approach is because I don't want director disposing/creating a full size background image on every screen change.
uid: 58455 topic_id: 23200 reply_id: 99764


[TOPIC: post.html]
#21

rakoonic2

[GLOBAL: userInfoPane.html]
rakoonic2
  • Contributor

  • 503 posts
  • Corona SDK

Regarding letterbox scaling - if you move stuff in and out of the area you define and there are borders, you may not want them to be visible. A quick hack I did to hide this is a function located here:

You call it (passing a { r=, g=, b= } table should you wish to set hte colour) and it will return either false (which means no borders were needed) or a display group containing bars that block the area you wouldn't normally see.

http://pastebin.com/w2x90vUT
uid: 46639 topic_id: 23200 reply_id: 111447


[TOPIC: post.html]
#22

rxmarccall

[GLOBAL: userInfoPane.html]
rxmarccall
  • Contributor

  • 751 posts
  • Corona SDK

So for a all around iOS and Android build, the aspect ratio of 360 x 570 is correct? I read on the old "Content Scaling Made Easy" post to do 380 x 570. Which do you guys suggest?

http://www.coronalabs.com/blog/2010/11/20/content-scaling-made-easy/
uid: 19620 topic_id: 23200 reply_id: 113948


[TOPIC: post.html]
#23

RicardoGraca

[GLOBAL: userInfoPane.html]
RicardoGraca
  • Contributor

  • 190 posts
  • Corona SDK

If you follow the instructions on this post 360x570 is all that is needed. If you make your images 380x570 you will never see those extra pixels in any device available today. There's no harm in using it, it's just wasted work.
uid: 61899 topic_id: 23200 reply_id: 113952


[TOPIC: post.html]
#24

rxmarccall

[GLOBAL: userInfoPane.html]
rxmarccall
  • Contributor

  • 751 posts
  • Corona SDK

Ok thank you for the reply, just trying to wrap my head around this for my new app i'm working on. So if I am only wanting to really do image resolutions for iphone 4 and above.. would you think that doing a set of 720x1140(for iphone 4 and ipad) and 1440x2280 (for ipad 3) would be good?
uid: 19620 topic_id: 23200 reply_id: 113953


[TOPIC: post.html]
#25

RicardoGraca

[GLOBAL: userInfoPane.html]
RicardoGraca
  • Contributor

  • 190 posts
  • Corona SDK

If you don't plan on supporting 16:9 or 16:10 resolutions you can make your images 360x480 or multiples of that. That's all that's needed for all the current iOS devices available. Note that the rumors say the next iPhone will have a 16:9 aspect ratio so if you plan on supporting it you should use the recommended image sizes. The benefit of that is that you will gain almost automatic Android support. If you only plan to support high resolution devices you can do as you say and make the base resolution 720x1140.
uid: 61899 topic_id: 23200 reply_id: 113957

  • elifares likes this


[topic_controls]
Page 1 of 4 1 2 3 »
 
[/topic_controls]