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}