001package pipeline;
002import scene.*;
003import framebuffer.*;
004
005import java.awt.Color;
006
007/**
008   Rasterize each line segment into pixels in the framebuffer.
009
010   This rasterization algorithm is based on
011     "Fundamentals of Computer Graphics", 3rd Edition,
012      by Peter Shirley, pages 163-165.
013*/
014public class Rasterize
015{
016   public static boolean debug = false;
017
018   /**
019      Rasterize each line segment into pixels in the framebuffer.
020
021      @param ls LineSegment to rasterize into the framebuffer
022      @param fb FrameBuffer to hold rasterized pixels
023   */
024   public static void rasterize(LineSegment ls, FrameBuffer fb)
025   {
026      int w = fb.getWidthVP();
027      int h = fb.getHeightVP();
028
029      // Get the colors from the two vertices.
030      double r0 = ls.v[0].r;
031      double g0 = ls.v[0].g;
032      double b0 = ls.v[0].b;
033      double r1 = ls.v[1].r;
034      double g1 = ls.v[1].g;
035      double b1 = ls.v[1].b;
036
037      // Round the line segment's two endpoints to the nearest
038      // logical pixel. This makes the algorithm a lot simpler,
039      // but it can cause a slight, but noticable, shift of the
040      // line segment.
041      double x0 = Math.round( ls.v[0].x );
042      double y0 = Math.round( ls.v[0].y );
043      double x1 = Math.round( ls.v[1].x );
044      double y1 = Math.round( ls.v[1].y );
045
046      if (Math.abs(y1 - y0) <= Math.abs(x1 - x0)) // if abs(slope) <= 1
047      {
048         if (x1 < x0) // swap (x0, y0) with (x1, y1)
049         {
050            double tempX = x0;
051            double tempY = y0;
052            x0 = x1;
053            y0 = y1;
054            x1 = tempX;
055            y1 = tempY;
056            // swap the colors too
057            double tempR = r0;
058            double tempG = g0;
059            double tempB = b0;
060            r0 = r1;
061            g0 = g1;
062            b0 = b1;
063            r1 = tempR;
064            g1 = tempG;
065            b1 = tempB;
066         }
067
068         // Compute this line segment's slope.
069         double      m = (y1 - y0) / (x1 - x0);
070         double slopeR = (r1 - r0) / (x1 - x0);
071         double slopeG = (g1 - g0) / (x1 - x0);
072         double slopeB = (b1 - b0) / (x1 - x0);
073
074         // In the following loop, as x moves across the logical
075         // horizontal pixels, we will compute a y value for each x.
076         double y = y0;
077
078         // Rasterize this line segment.
079         for (int x = (int)x0; x <= (int)x1; x++, y += m)
080         {
081            // Interpolate this pixel's color between the two endpoint's colors.
082            float r = (float)Math.abs(r0 + slopeR*(x - x0));
083            float g = (float)Math.abs(g0 + slopeG*(x - x0));
084            float b = (float)Math.abs(b0 + slopeB*(x - x0));
085            // We need the Math.abs() because otherwise, we sometimes get -0.0.
086
087            // The value of y will almost always be between
088            // two vertical pixel coordinates. By rounding off
089            // the value of y, we are choosing the nearest logical
090            // vertical pixel coordinate.
091            fb.setPixelVP(x - 1, h - (int)Math.round(y), new Color(r, g, b));
092
093            // log interesting information to standard output
094            if (debug) logPixel(w, h, x, y, r, g, b);
095
096            // Advance (x,y) to the next pixel. Since delta_x = 1, we need delta_y = m.
097         }
098      }
099      else  // abs(slope) > 1
100      {
101         if (y1 < y0) // swap (x0, y0) with (x1, y1)
102         {
103            double tempX = x0;
104            double tempY = y0;
105            x0 = x1;
106            y0 = y1;
107            x1 = tempX;
108            y1 = tempY;
109            // swap the colors too
110            double tempR = r0;
111            double tempG = g0;
112            double tempB = b0;
113            r0 = r1;
114            g0 = g1;
115            b0 = b1;
116            r1 = tempR;
117            g1 = tempG;
118            b1 = tempB;
119         }
120
121         // Compute this line segment's slope.
122         double      m = (x1 - x0) / (y1 - y0);
123         double slopeR = (r1 - r0) / (y1 - y0);
124         double slopeG = (g1 - g0) / (y1 - y0);
125         double slopeB = (b1 - b0) / (y1 - y0);
126
127         // In the following loop, as y moves across the logical
128         // vertical pixels, we will compute a x value for each y.
129         double x = x0;
130
131         // Rasterize this line segment.
132         for (int y = (int)y0; y <= (int)y1; x += m, y++)
133         {
134            // Interpolate this pixel's color between the two endpoint's colors.
135            float r = (float)Math.abs(r0 + slopeR*(y - y0));
136            float g = (float)Math.abs(g0 + slopeG*(y - y0));
137            float b = (float)Math.abs(b0 + slopeB*(y - y0));
138            // We need the Math.abs() because otherwise, we sometimes get -0.0.
139
140            // The value of x will almost always be between
141            // two horizontal pixel coordinates. By rounding off
142            // the value of x, we are choosing the nearest logical
143            // horizontal pixel coordinate.
144            fb.setPixelVP((int)Math.round(x) - 1, h - y, new Color(r, g, b));
145
146            // log interesting information to standard output
147            if (debug) logPixel(w, h, x, y, r, g, b);
148
149            // Advance (x,y) to the next pixel. Since delta_y = 1, we need delta_x = m.
150         }
151      }
152   }
153
154
155   private static void logPixel(int w, int h, int x, double y, double r, double g, double b)
156   {
157      System.out.printf("[w=%d, h=%d]  x=%d, y=%f, r=%f, g=%f, b=%f\n", w, h, x, y, r, g, b);
158   }
159
160   private static void logPixel(int w, int h, double x, int y, double r, double g, double b)
161   {
162      System.out.printf("[w=%d, h=%d]  x=%f, y=%d, r=%f, g=%f, b=%f\n", w, h, x, y, r, g, b);
163   }
164}