public class Render extends MISApplet {
	double zbuffer[][];
	int framebuffer[][][];
	Shape3D s = new Shape3D();

	public void initialize() {
		zbuffer = new double[W][H];
		framebuffer = new int[W][H][3];
		s.sphere();
	}

	public void initFrame(double t) {
		int px1, py1, px2, py2, px3, py3;
		double z1, z2, z3, z;

		for (int i = 0; i < W; i++) {
			for (int j = 0; j < H; j++) {
				zbuffer[i][j] = 0;
				framebuffer[i][j][0] = framebuffer[i][j][1] = framebuffer[i][j][2] = 0;
			}
		}

		for (int i = 0; i < s.faces.length; i++) {
			px1 = (int)(s.M.transform(s.vertices[s.faces[i][0]])[0]*W/2 + W/2.);
			py1 = (int)(s.M.transform(s.vertices[s.faces[i][0]])[1]*-H/2 + H/2.);
			z1 = s.M.transform(s.vertices[s.faces[i][0]])[2];
			px2 = (int)(s.M.transform(s.vertices[s.faces[i][1]])[0]*W/2 + W/2.);
			py2 = (int)(s.M.transform(s.vertices[s.faces[i][1]])[1]*-H/2 + H/2.);
			z2 = s.M.transform(s.vertices[s.faces[i][1]])[2];
			px3 = (int)(s.M.transform(s.vertices[s.faces[i][2]])[0]*W/2 + W/2.);
			py3 = (int)(s.M.transform(s.vertices[s.faces[i][2]])[1]*-H/2 + H/2.);
			z3 = s.M.transform(s.vertices[s.faces[i][2]])[2];

			if (px1 == px2 && px2 == px3) {
System.err.println("Horizontal Line");
				break;
			}

			if (py1 == py2 && py2 == py3) {
System.err.println("Vertical Line");
				break;
			}

			if (px1 == px2 && py1 == py2 || px1 == px3 && py1 == py3 || px2 == px3 && py2 == py3) {
System.err.println("Not a Triangle");
				break;
			}

			if (py1 > py2) {
				int tmp = py1;
				py1 = py2;
				py2 = tmp;
				tmp = px1;
				px1 = px2;
				px2 = tmp;
			}
			if (py2 > py3) {
				int tmp = py2;
				py2 = py3;
				py3 = tmp;
				tmp = px2;
				px2 = px3;
				px3 = tmp;
			}
			if (py1 > py2) {
				int tmp = py1;
				py1 = py2;
				py2 = tmp;
				tmp = px1;
				px1 = px2;
				px2 = tmp;
			}

			z = (z1 + z2 + z3)/3;

			if (px3 < px1 ? (py2 - py1)*(px3 - px1) > (px2 - px1)*(py3 - py1) :  (py2 - py1)*(px3 - px1) > (px2 - px1)*(py3 - py1)) {
				for (int py = py1; py < py2; py++) {
					for (int px = (int)((py - py1)*(double)(px2 - px1)/(py2 - py1) + px1); px < (int)((py - py1)*(double)(px3 - px1)/(py3 - py1) + px1); px++) {
						if (z > zbuffer[px][py]) {
							zbuffer[px][py] = z;
							framebuffer[px][py][0] = framebuffer[px][py][1] = framebuffer[px][py][2] = (int)((z + 1)*255/2.);
						}
					}
				}
				for (int py = py2; py < py3; py++) {
					for (int px = (int)((py - py3)*(double)(px2 - px3)/(py2 - py3) + px3); px < (py - py3)*(double)(px1 - px3)/(py1 - py3) + px3; px++) {
						if (z > zbuffer[px][py]) {
							zbuffer[px][py] = z;
							framebuffer[px][py][0] = framebuffer[px][py][1] = framebuffer[px][py][2] = (int)((z + 1)*255/2.);
						}
					}
				}
			} else {
				for (int py = py1; py < py2; py++) {
					for (int px = (int)((py - py1)*(double)(px3 - px1)/(py3 - py1) + px1); px < (int)((py - py1)*(double)(px2 - px1)/(py2  - py1) + px1); px++) {
						if (z > zbuffer[px][py]) {
							zbuffer[px][py] = z;
							framebuffer[px][py][0] = framebuffer[px][py][1] = framebuffer[px][py][2] = (int)((z + 1)*255/2.);
						}
					}
				}
				for (int py = py2; py < py3; py++) {
					for (int px = (int)((py - py3)*(double)(px1 - px3)/(py1 - py3) + px3); px < (py - py3)*(double)(px2 - px3)/(py2 - py3) + px3; px++) {
						if (z > zbuffer[px][py]) {
							zbuffer[px][py] = z;
							framebuffer[px][py][0] = framebuffer[px][py][1] = framebuffer[px][py][2] = (int)((z + 1)*255/2.);
						}
					}
				}
			}
		}

		s.M.rotateY(Math.PI/180);
	}

	public void setPixel(int x, int y, int rgb[]) {
		rgb[0] = framebuffer[x][y][0];
		rgb[1] = framebuffer[x][y][1];
		rgb[2] = framebuffer[x][y][2];
	}
}

