001/*
002
003*/
004
005package renderer.pipeline;
006import  renderer.scene.*;
007import  renderer.framebuffer.*;
008
009/**
010   Transform each {@link Vertex} of a {@link LineSegment} from
011   projected camera coordinates (i.e., image plane coordinates)
012   to viewport coordinates.
013
014
015<p>
016   The image plane contains a view rectangle with
017   <pre>{@code
018        -1 <= x <= 1,
019        -1 <= y <= 1,
020   }</pre>
021   The view rectangle has the important job of determining what part of the scene is visible to our renderer.
022<p>
023   In the previous pipeline stage, every line segment from the scene was projected onto the image plane. We want only that part of each projected line segment contained in the view rectangle to be visible to our renderer and rasterized into the framebuffer's viewport. To prepare for the rasterization step, we need to convert each vertex's x and y coordinates
024
025
026<pre>{@code
027                                                                        (w+1/2,h+1/2)
028        y-axis                       +----------------------------------------+
029          |                          |                                        |
030          |  (+1,+1)                 |                                        |
031    +-----|-----+                    |                                        |
032    |     |     |                    |                                        |
033    |     |     |                    |                                        |
034----------+----------- x-axis        |                                        |
035    |     |     |                    |                                        |
036    |     |     |                    |                                        |
037    +-----|-----+                    |                                        |
038 (-1,-1)  |                          |                                        |
039          |                          |                                        |
040                                     |                                        |
041    View Rectangle                   +----------------------------------------+
042  (in the view plane)            (1/2,1/2)
043                                                    Logical Viewport
044}</pre>
045
046
047
048Notice how the view rectangle is a square but the logical viewport is a reactangle (though it may be a square).
049
050The view rectangle always has -1.0 <= x <= 1.0 and -1.0 <= y <= 1.0.
051The logical viewport always has 0.5 <= x <= w+0.5 and 0.5 <= y <= h+0.5 where w and h are the width and height of the FrameBuffer's current viewport.
052
053If the aspect ratio, w/h, of the logical (and FrameBuffer) viewport is not 1, then the image in the view rectangle will be distorted when it is transformed to the logical viewport. (NOTE: Starting with Renderer 7,  the aspect ratio of the viewport will usually match the aspect ratio of the renderer's view volume, so the distortion caused by the viewport transformation will undo the distortion caused by the normalization transformation. If the view volume and viewport aspect ratios do not match, then the final image in the framebuffer's viewport will be a distortion of the image in the view volume's view rectangle.).
054
055
056
057   For each {@link Vertex} object in each {@link LineSegment} object,
058   transform the Vertex object from image plane coordinates to viewport
059   coordinates so that the view rectangle in the image plane with
060   <pre>{@code
061        -1 <= x <= 1,
062        -1 <= y <= 1,
063   }</pre>
064   transforms into a viewport where
065   <pre>{@code
066       0.5 <= x < w + 0.5,
067       0.5 <= y < h + 0.5,
068   }</pre>
069   where
070   <pre>{@code
071         w = number of horizontal pixels in the viewport,
072         h = number of vertical pixels in the viewport.
073   }</pre>
074<p>
075   The goal of this transformation is to put a logical pixel with
076   integer coordinates at the center of each square physical pixel.
077   The logical pixel with integer coordinates (m, n) represents the
078   square pixel with
079   <pre>{@code
080     m - 0.5 <= x < m + 0.5,
081     n - 0.5 <= y < n + 0.5.
082   }</pre>
083   Notice that logical pixel integer coordinates (m.n) have
084   <pre>{@code
085     1 <= m <= w
086     1 <= n <= h.
087   }</pre>
088<p>
089   Let us derive the formulas for the viewport transformation (we will
090   derive the x-coordinate formula; the y-coordinate formula is similar).
091<p>
092   Let x_p denote an x-coordinate in the image plane and let x_vp denote
093   an x-coordinate in the viewport. If a vertex is on the left edge of
094   the view rectangle (with x_p = -1), then it should be transformed to
095   the left edge of the viewport (with x_vp = 0.5). And if a vertex is on
096   the right edge of the view rectangle (with x_p = 1), then it should be
097   transformed to the right edge of the viewport (with x_vp =  w + 0.5).
098   These two facts are all we need to know to find the linear function
099   for the transformation of the x-coordinate.
100<p>
101   We need to calculate the slope m and intercept b of a linear function
102   <pre>{@code
103             x_vp = m * x_p + b
104   }</pre>
105   that converts image plane coordinates into viewport coordinates. We know,
106   from what we said above about the left and right edges of the view
107   rectangle, that
108   <pre>{@code
109              0.5 = (m * -1) + b,
110          w + 0.5 = (m *  1) + b.
111   }</pre>
112   If we add these last two equations together we get
113   <pre>{@code
114            w + 1 = 2*b
115   }</pre>
116   or
117   <pre>{@code
118            b = (w + 1)/2.
119   }</pre>
120   If we use b to solve for m we have
121   <pre>{@code
122              0.5 = (m * -1) + (w + 1)/2
123                1 = -2*m + w + 1
124              2*m = w
125                m = w/2.
126   }</pre>
127   So the linear transformation of the x-coordinate is
128   <pre>{@code
129          x_vp = (w/2) * x_p + (w+1)/2
130               = 0.5 + w/2 * (x_p + 1).
131   }</pre>
132   The equivalent formula for the y-coordinate is
133   <pre>{@code
134          y_vp = 0.5 + h/2 * (y_p + 1).
135   }</pre>
136*/
137public class Viewport
138{
139   /**
140      For each {@link LineSegment}, transform each {@link Vertex}
141      from image plane coordinates to viewport coordinates.
142
143      @param ls  LineSegment to transform into viewport coordinates
144      @param fb  FrameBuffer that holds the current viewport
145   */
146   public static void viewport(LineSegment ls, FrameBuffer fb)
147   {
148      // Get the viewport dimensions.
149      int w = fb.getWidthVP();
150      int h = fb.getHeightVP();
151
152      // Transform the line segment's endpoints from
153      // image plane coordinates to viewport coordinates.
154      ls.v[0].x = 0.5 + w/2.001 * (ls.v[0].x + 1);//x_vp = 0.5 + w/2 * (x_p+1)
155      ls.v[0].y = 0.5 + h/2.001 * (ls.v[0].y + 1);//y_vp = 0.5 + h/2 * (y_p+1)
156      ls.v[1].x = 0.5 + w/2.001 * (ls.v[1].x + 1);
157      ls.v[1].y = 0.5 + h/2.001 * (ls.v[1].y + 1);
158      // NOTE: Notice the 2.001 fudge factor in the last four equations.
159      // This is explained on page 142 of
160      //    "Jim Blinn's Corner: A Trip Down The Graphics Pipeline"
161      //     by Jim Blinn, 1996, Morgan Kaufmann Publishers.
162   }
163}