The source code:
import java.applet.*; import java.awt.*; import java.awt.event.*; import java.lang.Math; class Point3D { public int x, y, z; public Point3D( int X, int Y, int Z ) { x = X; y = Y; z = Z; } } class Edge { public int a, b; public Edge( int A, int B ) { a = A; b = B; } } public class WireframeViewer extends Applet implements MouseListener, MouseMotionListener { int width, height; int mx, my; // the most recently recorded mouse coordinates Image backbuffer; Graphics backg; int azimuth = 35, elevation = 30; Point3D[] vertices; Edge[] edges; public void init() { width = getSize().width; height = getSize().height; vertices = new Point3D[ 8 ]; vertices[0] = new Point3D( -1, -1, -1 ); vertices[1] = new Point3D( -1, -1, 1 ); vertices[2] = new Point3D( -1, 1, -1 ); vertices[3] = new Point3D( -1, 1, 1 ); vertices[4] = new Point3D( 1, -1, -1 ); vertices[5] = new Point3D( 1, -1, 1 ); vertices[6] = new Point3D( 1, 1, -1 ); vertices[7] = new Point3D( 1, 1, 1 ); edges = new Edge[ 12 ]; edges[ 0] = new Edge( 0, 1 ); edges[ 1] = new Edge( 0, 2 ); edges[ 2] = new Edge( 0, 4 ); edges[ 3] = new Edge( 1, 3 ); edges[ 4] = new Edge( 1, 5 ); edges[ 5] = new Edge( 2, 3 ); edges[ 6] = new Edge( 2, 6 ); edges[ 7] = new Edge( 3, 7 ); edges[ 8] = new Edge( 4, 5 ); edges[ 9] = new Edge( 4, 6 ); edges[10] = new Edge( 5, 7 ); edges[11] = new Edge( 6, 7 ); backbuffer = createImage( width, height ); backg = backbuffer.getGraphics(); drawWireframe( backg ); addMouseListener( this ); addMouseMotionListener( this ); } void drawWireframe( Graphics g ) { // compute coefficients for the projection double theta = Math.PI * azimuth / 180.0; double phi = Math.PI * elevation / 180.0; float cosT = (float)Math.cos( theta ), sinT = (float)Math.sin( theta ); float cosP = (float)Math.cos( phi ), sinP = (float)Math.sin( phi ); float cosTcosP = cosT*cosP, cosTsinP = cosT*sinP, sinTcosP = sinT*cosP, sinTsinP = sinT*sinP; // project vertices onto the 2D viewport Point[] points; points = new Point[ vertices.length ]; int j; int scaleFactor = width/4; float near = 3; // distance from eye to near plane float nearToObj = 1.5f; // distance from near plane to center of object for ( j = 0; j < vertices.length; ++j ) { int x0 = vertices[j].x; int y0 = vertices[j].y; int z0 = vertices[j].z; // compute an orthographic projection float x1 = cosT*x0 + sinT*z0; float y1 = -sinTsinP*x0 + cosP*y0 + cosTsinP*z0; // now adjust things to get a perspective projection float z1 = cosTcosP*z0 - sinTcosP*x0 - sinP*y0; x1 = x1*near/(z1+near+nearToObj); y1 = y1*near/(z1+near+nearToObj); // the 0.5 is to round off when converting to int points[j] = new Point( (int)(width/2 + scaleFactor*x1 + 0.5), (int)(height/2 - scaleFactor*y1 + 0.5) ); } // draw the wireframe g.setColor( Color.black ); g.fillRect( 0, 0, width, height ); g.setColor( Color.white ); for ( j = 0; j < edges.length; ++j ) { g.drawLine( points[ edges[j].a ].x, points[ edges[j].a ].y, points[ edges[j].b ].x, points[ edges[j].b ].y ); } } public void mouseEntered( MouseEvent e ) { } public void mouseExited( MouseEvent e ) { } public void mouseClicked( MouseEvent e ) { } public void mousePressed( MouseEvent e ) { mx = e.getX(); my = e.getY(); e.consume(); } public void mouseReleased( MouseEvent e ) { } public void mouseMoved( MouseEvent e ) { } public void mouseDragged( MouseEvent e ) { // get the latest mouse position int new_mx = e.getX(); int new_my = e.getY(); // adjust angles according to the distance travelled by the mouse // since the last event azimuth -= new_mx - mx; elevation += new_my - my; // update the backbuffer drawWireframe( backg ); // update our data mx = new_mx; my = new_my; repaint(); e.consume(); } public void update( Graphics g ) { g.drawImage( backbuffer, 0, 0, this ); showStatus("Elev: "+elevation+" deg, Azim: "+azimuth+" deg"); } public void paint( Graphics g ) { update( g ); } }
Notice that the compiler generates 3 .class files: one for each of the classes defined.
Click and drag on the applet to rotate the cube.