//Contains common 3D stuff //clipping, perspective, etc import java.awt.*; import graphics.Matrix3D; import graphics.MatrixStack; import graphics.ClipPlane; import graphics.Light; public class ThreeDApplet extends RasterizerApplet { //perspective value private double F = 10; private MatrixStack stack; private ClipPlane clipper = new ClipPlane(0, 0, 1, 0.001); //Pz + eps //can be overridden by child applet Light[] lights; protected int[] ambient = {0,0,0}; //EXTEND THIS public void initialize() { super.initialize(); stack = new MatrixStack(); } public void initFrame(long time) { super.initFrame(time); try { animate(time); } catch (Exception e) { e.printStackTrace(); stop(); return; } draw(); } //OVERRIDE THESE void draw() {} void animate(long time) {} protected void applyPerspective(double f, double[][] vertices) { for (int i = 0; i< vertices.length; i++) { double[] v = vertices[i]; double z = v[2]; double fz = f/z; v[0] *= fz; v[1] *= fz; //scale x, y v[2] = fz; } } public void drawShape(graphics.Shape s) { s.shade(lights, ambient); //apply vertex shading int vlength = s.getVertex(0).length; //length of each vertex //loop through each face for (int fi = 0; fi < s.numFaces(); fi++) { int[] face = s.getFace(fi); //copy from vertices to points double[][] points = new double[face.length][vlength]; for (int i = 0; i3, 3->0, 0->2) drawLine(lines[2], lines[3], color); drawLine(lines[3], lines[0], color); drawLine(lines[0], lines[2], color); } } } //draws normals for all a shape's vertices public void drawNormals(graphics.Shape s, int[] color) {drawNormals(s, color, 1.0);} public void drawNormals(graphics.Shape s, int[] color, double scale) { for (int vi=0; vi1, 1->2, 2->0) System.arraycopy(quad[0], 0, triangle[0], 0, 6); //1st point of triangle System.arraycopy(quad[1], 0, triangle[1], 0, 6); //2nd point of triangle System.arraycopy(quad[2], 0, triangle[2], 0, 6); //3rd point of triangle drawTriangle(triangle, doClip); //(2->3, 3->0, 0->2) System.arraycopy(quad[2], 0, triangle[0], 0, 6); //1st point of triangle System.arraycopy(quad[3], 0, triangle[1], 0, 6); //2nd point of triangle System.arraycopy(quad[0], 0, triangle[2], 0, 6); //3rd point of triangle drawTriangle(triangle, doClip); } public void drawLine(double[] a, double[] b, int[] color) { //System.err.println("in drawLine:"); //System.err.println("("+a[0]+", "+a[1]+", "+a[2]+")"); //System.err.println("("+b[0]+", "+b[1]+", "+b[2]+")"); double[][] line = new double[2][a.length]; System.arraycopy(a, 0, line[0], 0, a.length); System.arraycopy(b, 0, line[1], 0, b.length); //if clipline returns false it means don't draw the line boolean doDraw = clipper.clipLine(line[0], line[1]); if (!doDraw) return; applyPerspective(F, line); //viewport transformation line[0][0] = (double)x(line[0][0]); line[0][1] = (double)y(line[0][1]); line[1][0] = (double)x(line[1][0]); line[1][1] = (double)y(line[1][1]); renderLine(line[0], line[1], color); //send to RasterizerApplet } //Viewport transformations int x(double t) { return W/2 + (int)(t*W/4); } int y(double t) { return H/2 - (int)(t*W/4); } //applies matrix at the top of the stack to a shape public void transform(graphics.Shape shape) { shape.matrix.copy(stack.peek()); shape.transform(); } //applies matrix at the top of the stack to a vertex public void transform(double[] src, double[] dst) { stack.peek().transform(src, dst); } //convenience methods for stack operations protected void push() { stack.push(); } protected Matrix3D pop() { return stack.pop(); } public void rotateX(double theta) { stack.peek().rotateX(theta); } public void rotateY(double theta) { stack.peek().rotateY(theta); } public void rotateZ(double theta) { stack.peek().rotateZ(theta); } public void translate(double x, double y, double z) { stack.peek().translate(x, y, z); } public void scale(double x, double y, double z) { stack.peek().scale(x, y, z); } }