//handles low level rendering class RasterizerApplet extends MISApplet { protected int[][][] framebuffer, bgbuffer; //2D array of RGB values protected double[][] zbuffer; public void initialize() { super.initialize(); framebuffer = new int[H][W][3]; //rgb values bgbuffer = new int[H][W][3]; //rgb values zbuffer = new double[H][W]; } public void initFrame(long time) { //clear z-buffer for (int w=0; w c[1]) { if (d[0] > b[0]) { renderTrapezoid(a, a, b, d); renderTrapezoid(b, d, c, c); } else { renderTrapezoid(a, a, d, b); renderTrapezoid(d, b, c, c); } } else { if (d[0] > b[0]) { renderTrapezoid(c, c, b, d); renderTrapezoid(b, d, a, a); } else { renderTrapezoid(c, c, d, b); renderTrapezoid(d, b, a, a); } } } protected void renderTriangle(double[][] triangle) { //dumpVertices(triangle); double[] a = triangle[0], b = triangle[1], c = triangle[2]; //are any of the vertices on the same y? Then it's already a trapezoid if (a[1] == b[1]) { if (a[1] > c[1]) //a & b above c { if (a[0] < b[0]) //a left of b renderTrapezoid(a, b, c, c); else //b left of a renderTrapezoid(b, a, c, c); } else //c above a & b { if (a[0] < b[0]) //a left of b renderTrapezoid(c, c, a, b); else //b left of a renderTrapezoid(c, c, b, a); } } else if (a[1] == c[1]) { if (a[1] > b[1]) //a & c above b { if (a[0] < c[0]) //a left of c renderTrapezoid(a, c, b, b); else //c left of a renderTrapezoid(c, a, b, b); } else //b above a & c { if (a[0] < c[0]) //a left of c renderTrapezoid(b, b, a, c); else //c left of a renderTrapezoid(b, b, c, a); } } else if (b[1] == c[1]) { if (a[1] > b[1]) //a above b & c { if (b[0] < c[0]) //b left of c renderTrapezoid(a, a, b, c); else //c left of b renderTrapezoid(a, a, c, b); } else //b & c above a { if (b[0] < c[0]) //b left of c renderTrapezoid(b, c, a, a); else //c left of b renderTrapezoid(c, b, a, a); } } else //split triangle into 2 { //which vertex is in the middle? if ((a[1] >= b[1] && a[1] <= c[1]) || (a[1] <= b[1] && a[1] >= c[1])) splitTriangle(c, a, b); //maintain relative order (ccw) else if ((b[1] >= a[1] && b[1] <= c[1]) || (b[1] <= a[1] && b[1] >= c[1])) splitTriangle(a, b, c); else if ((c[1] >= a[1] && c[1] <= b[1]) || (c[1] <= a[1] && c[1] >= b[1])) splitTriangle(b, c, a); } } private void renderTrapezoid(double[] tl, double[] tr, double[] bl, double[] br) { //System.err.println("in renderTrapezoid"); //System.err.println("tl = ("+tl[0]+", "+tl[1]+", "+tl[2]+") - (" + tl[3]+", "+tl[4]+", "+tl[5]+")"); //System.err.println("tr = ("+tr[0]+", "+tr[1]+", "+tr[2]+") - (" + tr[3]+", "+tr[4]+", "+tr[5]+")"); //System.err.println("bl = ("+bl[0]+", "+bl[1]+", "+bl[2]+") - (" + bl[3]+", "+bl[4]+", "+bl[5]+")"); //System.err.println("br = ("+br[0]+", "+br[1]+", "+br[2]+") - (" + br[3]+", "+br[4]+", "+br[5]+")"); //bounds checking - make sure trapezoid is at least somewhat inside screen if (bl[0] > W && tl[0] > W) return; //both left x-coords off the screen? if (br[0] < 0 && tr[0] < 0) return; //both right x-coords off the screen? if (br[1] > H && bl[1] > H) return; //both bottom y-coords off the screen? if (tl[1] < 0 && tr[1] < 0) return; //both top y-coords off the screen? int top = (int)tl[1], bottom = (int)bl[1]; int height = top - bottom; if (height == 0) //don't want divide by zeros { renderLine(tl, tr); renderLine(bl, br); return; } double xLeft = (int)tl[0], xRight = (int)tr[0]; //how much to go left and right for each scanline double dxLeft = (bl[0] - tl[0])/height; // dy = -1/height => -(tl - bl) double dxRight = (br[0] - tr[0])/height; //System.err.println("dxLeft = " + dxLeft + ", dxRight = " + dxRight); //each scanline for (int y = top; y >= bottom; y--) { if (y >= H || y < 0) continue; //vert bounds checking for pixel //System.err.println("y = " + y); //System.err.println("xLeft = " + xLeft + ", xRight = " + xRight); //how far down are we double u = (double)(y - bottom)/(top - bottom); double zLeft = lerp(u, bl[2], tl[2]), zRight = lerp(u, br[2], tr[2]); double rLeft = lerp(u, bl[3], tl[3]), rRight = lerp(u, br[3], tr[3]); double gLeft = lerp(u, bl[4], tl[4]), gRight = lerp(u, br[4], tr[4]); double bLeft = lerp(u, bl[5], tl[5]), bRight = lerp(u, br[5], tr[5]); //each pixel in scanline for (int x = (int)xLeft; x <= (int)xRight; x++) { if (x >= W || x < 0) continue; //horiz bounds checking for pixel //System.err.println("x = " + x); double v = ((double)x - xLeft)/(xRight - xLeft); //interpolate z value at current pixel double z = lerp(v, zLeft, zRight); //System.err.println("z = " + z); if (z < zbuffer[y][x]) { //interpolate rgb int r = (int)lerp(v, rLeft, rRight); int g = (int)lerp(v, gLeft, gRight); int b = (int)lerp(v, bLeft, bRight); //System.err.println("(x,y,z,r,g,b) = (" +x+ "," +y+ "," +z+ "," +r+ "," +g+ "," +b+ ")"); zbuffer[y][x] = z; //interpolate rgb framebuffer[y][x][0] = r; framebuffer[y][x][1] = g; framebuffer[y][x][2] = b; } } xLeft += dxLeft; xRight += dxRight; } } protected void renderLine(double[] a, double[] b, int[] color) { for (double t = 0; t < 1.0; t += 0.01) { int x = (int)lerp(t, a[0], b[0]); if (x >= W || x < 0) continue; //horiz bounds checking for pixel int y = (int)lerp(t, a[1], b[1]); if (y >= H || y < 0) continue; //vert bounds checking for pixel double z = lerp(t, a[2], b[2]); if (z < zbuffer[y][x]) { zbuffer[y][x] = z; framebuffer[y][x][0] = color[0]; framebuffer[y][x][1] = color[1]; framebuffer[y][x][2] = color[2]; } } } //same as renderLine but with gradient of colors protected void renderLine(double[] a, double[] b) { for (double t = 0; t < 1.0; t += 0.01) { int x = (int)lerp(t, a[0], b[0]); if (x >= W || x < 0) continue; //horiz bounds checking for pixel int y = (int)lerp(t, a[1], b[1]); if (y >= H || y < 0) continue; //vert bounds checking for pixel double z = lerp(t, a[2], b[2]); if (z > zbuffer[y][x]) { zbuffer[y][x] = z; framebuffer[y][x][0] = (int)lerp(t, a[3], b[3]); framebuffer[y][x][1] = (int)lerp(t, a[4], b[4]); framebuffer[y][x][2] = (int)lerp(t, a[5], b[5]); } } } public double lerp(double t, double a, double b) { return a + t*(b-a); } public void dumpVertices(double[][] vertices) { System.err.println("vertices:"); for (int i = 0; i < vertices.length; i++) System.err.println("("+vertices[i][0]+", "+vertices[i][1]+", "+vertices[i][2]+") - ("+vertices[i][3]+", "+vertices[i][4]+", "+vertices[i][5]+")"); } }