import java.awt.*;

public class Assignment4 extends BufferedApplet {
	final double rads_per_deg = Math.PI/180;
	final int f = 1;

	int w,
	    h;

	Assembly world = new Assembly();
	Matrix3D cam = new Matrix3D();
	int t = 0;
	double a[] = new double[3],
	       b[] = new double[3];

	public void init() {
		animating = true;

		w = bounds().width;
		h = bounds().height;

		world.addShape3D();
		world.shapes[0].sphere();	// large sphere
		world.addAssembly();
		world.assemblies[0].addShape3D();
		world.assemblies[0].shapes[0].sphere();	// medium sphere
		world.assemblies[0].addAssembly();
		world.assemblies[0].assemblies[0].addShape3D();
		world.assemblies[0].assemblies[0].shapes[0].sphere();	// small sphere
	}

	public void animate(int t) {
		cam.identityMatrix();
		cam.translate(0, 0, 2);
		cam.rotateX(-0.25*t*rads_per_deg);
		cam.invert();

		world.identityMatrix();
		world.scale(0.5, 0.5, 0.5);
		world.assemblies[0].scale(0.5, 0.5, 0.5);
		world.assemblies[0].assemblies[0].scale(0.5, 0.5, 0.5);
		world.assemblies[0].translate(1.25*Math.cos(t*rads_per_deg), 0, 1.25*Math.sin(t*rads_per_deg));
		world.assemblies[0].assemblies[0].translate(0.5*Math.cos(2*t*rads_per_deg), 0, 0.5*Math.sin(2*t*rads_per_deg));
		world.multiply(cam);
	}

	public void render(Graphics g) {
		// Draw background:
		g.setColor(Color.white);
		g.fillRect(0, 0, w, h);

		animate(t++);

		// Draw subject:
		g.setColor(Color.black);
		draw(g, world);
	}

	public void draw(Graphics g, Assembly assembly) {
		if (assembly.assemblies != null) {
			// Draw assemblies:
			for (int i = 0; i < assembly.assemblies.length; i++) {	// for each assembly
				draw(g, assembly.assemblies[i]);
			}
		}

		if (assembly.shapes != null) {
			// Draw shapes:
			for (int i = 0; i < assembly.shapes.length; i++) {	// for each shape
				for (int j = 0; j < assembly.shapes[i].faces.length; j++) {	// for each face
					a = assembly.shapes[i].M.transform(assembly.shapes[i].vertices[assembly.shapes[i].faces[j][0]]);
					for (int k = 1; k < assembly.shapes[i].faces[j].length; k++) {	// for each vertex except the first
						b = assembly.shapes[i].M.transform(assembly.shapes[i].vertices[assembly.shapes[i].faces[j][k]]);
						g.drawLine(x((-f/a[2])*a[0]), y((-f/a[2])*a[1]), x((-f/b[2])*b[0]), y((-f/b[2])*b[1]));
						a = b;
					}
					b = assembly.shapes[i].M.transform(assembly.shapes[i].vertices[assembly.shapes[i].faces[j][0]]);
					g.drawLine(x((-f/a[2])*a[0]), y((-f/a[2])*a[1]), x((-f/b[2])*b[0]), y((-f/b[2])*b[1]));
				}
			}
		}
	}

	int x(double t) {
		return w/2 + (int)(t*w/4);
	}

	int y(double t) {
		return h/2 - (int)(t*w/4);
	}
}

