Monday, August 10, 2026

Can you explain the real reason for this flipping of ratios in reshape function?

```public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h)

  {
    GL2 gl = drawable.getGL().getGL2();
 
    gl.glViewport(0, 0, w, h);
    gl.glMatrixMode(GL2.GL_PROJECTION);
    gl.glLoadIdentity();
    if (w <= h) //
    gl.glOrtho(-1.0, 1.8, -1.0 * (float) h / (float) w, //
        1.0 * (float) h / (float) w, -1.0, 1.0);
    else gl.glOrtho(-1.0 * (float) w / (float) h, //
        1.8 * (float) w / (float) h,//
        -1.0, 1.0, -1.0, 1.0);
    gl.glMatrixMode(GL2.GL_MODELVIEW);
    gl.glLoadIdentity(); 

}


This is the classic aspect-ratio-``` correction pattern for glOrtho, and the "flipping" is just making sure the shorter screen dimension keeps the fixed [-1, 1]-ish range while the longer dimension gets stretched by the aspect ratio — so that objects don't get squished or stretched when the window isn't square.

The core idea

glOrtho defines a clipping box in world coordinates. If you always used a fixed box like (-1, 1, -1, 1) regardless of window shape, then:

  • A square in world space would render as a rectangle whenever the viewport (window) isn't square, because OpenGL maps that fixed clipping box onto whatever pixel dimensions w × h you gave glViewport.

So you need the ratio of your ortho box's width to height to match the ratio of the viewport's width to height (w/h), otherwise you get non-uniform scaling (distortion).

Why the branch on w <= h

  • When w <= h (window taller than wide, or square): the x-range is kept fixed at (-1, 1) (well, here -1.0 to 1.8, slightly asymmetric, but same idea), and the y-range is expanded by h/w, which is ≥ 1. So the y clipping range grows to match how much taller the window is relative to its width.

  • When w > h (window wider than tall): the y-range stays fixed at (-1, 1), and the x-range is expanded by w/h, which is ≥ 1.

In both cases, the multiplier used is always ≥ 1 — that's the "flipping ratio > 1" you're noticing. That's intentional: you always scale up the longer screen dimension's corresponding world-coordinate range, rather than shrinking the shorter one. This guarantees:

  1. The world-space region you can see along the "short" screen dimension never shrinks below the fixed range you defined (so nothing gets clipped away that you expect to always be visible).
  2. The "long" screen dimension gets extra world-space range proportionally, so a circle stays a circle, a square stays a square — no squash/stretch distortion.

Why not just always divide instead of conditionally choosing which axis to scale?

You could write it as always computing aspect = w/h and 

scaling x by aspect (or scaling y by 1/aspect), 

but that would mean when aspect < 1 (tall window) 

you'd be scaling x by something less than 1

shrinking your visible x-range below your intended baseline — 

content could go out of view on the sides. 

The if (w<=h) ... else ... branch avoids ever having a shrinking multiplier; 

it always picks whichever axis needs to grow to preserve the fixed axis's minimum extent, and always multiplies (never divides) by a ratio ≥ 1.

In short: the branching + always-≥1 multiplier is just a clean way to implement "preserve aspect ratio without ever clipping your baseline view region" — the fixed dimension stays constant, 

and the other dimension's ortho range is stretched by however much wider/taller the window is, so nothing distorts and nothing you expect to see gets cut off.