
   Aspect ratios, scaling, letterboxing, cropping, scrolling

These demo programs demonstrate several ways that a graphics program
can react to a user changing the shape of the program's window. Each
demo program is displaying a rotating wheel. The rotating wheel image
has an aspect ratio of 1 and it starts out with dimensions 512 pixels
by 512 pixels. When the user changes the dimension of the program's
window (which is the same thing as changing the dimensions of the program's
framebuffer) the issue is how the program should display the 512-by-512
wheel image in the new window. The new window might be larger or smaller
than the original 512 pixels by 512 pixels. Should the wheel be magnified,
or maybe letterboxed, into a larger window? Should the original image be
scaled down, or maybe cropped, into a smaller window? If you crop the
original image, which part of it is cropped off? If the image is letterboxed,
where in the framebuffer is the letterboxed viewport placed (that is, where
should the "empty" spaces go)?

To see some answers to the last few questions, look at the source code
to the examples Circle_v2_Letterbox.java and Circle_v3_Crop.java. In
particular, notice that when we letterbox the viewport within the
framebuffer, there are nine locations in the framebuffer where we can
place the viewport (think of a tic-tack-toe grid placed on the framebuffer).
Similarly, if we use the view rectangle to crop a source image, the view-
rectangle can be situated at nine different locations within the source
image (think of the same tic-tac-toe grid but placed this time on the
source image). If we are both cropping and letterboxing, then we could
even choose different grid locations for the cropping of the view rectangle
and the letterboxing of the viewport (see Circle_v6_CropAndLetterbox.java).


In general, letterboxing an image into a FrameBuffer is done by either
setting the default Viewport using the
   setViewport(int x, int y, int widthVP, int heightVP)
method in the FrameBuffer class, or by creating a new
Viewport using the
   Viewport(int x, int y, int widthVP, int heightVP)
constructor in the Viewport class.

Cropping a source image is done by changing the camera's view rectangle
in the image-plane using either the
   projOrtho(double left, double right, double bottom, double top)
or the
   projPerspective(double left, double right, double bottom, double top)
method in the Camera class.

There are two illustrations in this folder that try to visualize the
relationship between cropping, letterboxing, and the parameters to the
projOrtho() and setViewport() methods,
   API-view-rectangle-to-viewport.png,
   API-view-rectangle-to-viewport_distorted.png,


Scaling an image is done automatically by the renderer when it maps
the whole of the camera's view rectangle onto the framebuffer's
viewport. If the aspect ratios of the camera's view rectangle and
the framebuffer's viewport do not agree, then the renderer will
distort the final image in the viewport. Most of the time, we want
to make sure that the view rectangle and the viewport have the same
aspect ratio so that we get scaling without distortion.


When we crop an image in an interactive program, we can give the user
the option to "scroll" the image. In other words, we can give the user
the choice of which part of the original image gets cropped off.
Scrolling is part of the Java GUI system, it is not part of the renderer
or part of our FrameBuffer or Viewport. To allow a user to scroll through
a cropped image, we give the user a scrolling GUI component (a Scrollbar,
or JScrolBar, or JSlider) and use the value generated by the scrolling GUI
component to set the view rectangle in the camera's image-plane. See the
example programs,
   Circle_v5_PanAndScan_JScrollBar.java
   Circle_v5_PanAndScan_JSlider.java
   Circle_v5_PanAndScan_Scrollbar.java
There is a version using each of JSlider, JScrolBar, and Scrollbar because
the three components act differently when it comes to keyboard focus. Play
with all three programs and be sure to activate the scrolling components
using the keyboard's arrow keys and switching keyboard focus between the
components by using the Tab key.
