I am designing my (Android/OpenGL ES 2.0) app on one device and want it to run all all other devices while keeping the screen ratio of the development device (so the image doesn't stretch / squash), by altering the GLViewport ratio of the current device to match the development device, thus having either pillarboxing or letterboxing.

The only values I know for sure, are the physical screen ratio of the development device (in landscape) and the current device (regardless of orientation).

Please refer to my other question (which was regarding centering the viewport once I'd set it's size here: Centering GLViewport position within physical screen ) - on further study I see that my maths is somewhat incorrect (maybe too simplistic?) and the viewport doesn't seem to be getting sized correctly on all targets.

Is there a 'formula' for doing what I'm trying to do?

I get my ratio by doing the following:

float ratio = width / height;

Then I simply want to set my viewport like so:

GLES20.glViewport(0+offsetX, 0-offsetY, widthToUse, heightToUse);

The offsetX and Y values I think I'm OK with as per my previous Q. It's the 'widthToUse' and 'HeightToUse' that I can't seem to work out properly.

You can see from my other question, that I'm working out the 'widthToUse' value my multiplying the current device's height by the [development devices] ratio. However, this doesn't work on all devices as the resulting figure could actually be larger (wider) than the physical screen.

Here are some examples of what I'm trying to achieve, for illustration (ratio's much exaggerated here)

In the pics, the black outter-box is the physical screen of the devices and the blue square is the viewport.

enter image description here

Side note: I realise that my game will most likely be locked to a particular orientation (the one I'm currently developing will, eventually be locked to landscape mode) so I probably don't need to handle orientation changes, however, I would like to know, if possible, how to display at a particular ratio in either orientation in case this is required in the future. So in other words, I may develop an app for landscape, but 'allow' it to run in portrait (albeit with large letterboxing).

Also I know there are similar questions on here, but I've read them over and over and they either don't apply to my situation (or way of doing things), or I'm otherwise not able to get my answer from them.


2 Answers 2


Pretty simple, there are two candidate solutions, one where the full width is used and one where the full height is used, you must always pick the smaller of those:

widthToUse = Math.min(screenWidth, screenHeight * ratio)
heightToUse = Math.min(screenHeight, screenWidth / ratio)
offsetX = (screenWidth - widthToUse) / 2
offsetY = (screenHeight - heightToUse) / 2

I'm using code similar to the following:

public static final float NOMINAL_WIDTH = 1700;
public static final float NOMINAL_HEIGHT = 1000;

float aspectRatio = width / height;
if (aspectRatio < NOMINAL_ASPECT_RATIO) {
    viewportHeight = height;
    viewportWidth = width/height*NOMINAL_HEIGHT;
} else { // aspectRatio >= NOMINAL_ASPECT_RATIO
    viewportHeight = height/width*NOMINAL_WIDTH;
    viewportWidth = width;
  • \$\begingroup\$ You probably meant to write viewportWidth = height*NOMINAL_ASPECT_RATIO and viewportHeight = width/NOMINAL_ASPECT_RATIO. \$\endgroup\$ May 2, 2013 at 20:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .