<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">/*
 * ChaseApplet.java
 *
 * (C) 2004, Alex S.
 */
 
import java.awt.*;
import java.util.Vector;

public class ChaseApplet extends BufferedApplet
{
	pMatrix matrix = new pMatrix();
	pMatrix pmatrix = new pMatrix();

	// points/colors that are rendered.
	Vector points = new Vector();
	Vector colors = new Vector();

	// for z sorting
	double[] avgz;
	int[] polyorder;

	// pre-computed points.	
	Vector curve_points = new Vector();
	Vector object_points = new Vector();

	// current rendering color
	Color currentColor = Color.red;

	int detail = 64; //256;

	private double v1_angle = 0;
	private double v1_speed = Math.PI/41;


	// angle, mouse state
	private double m_anglex,m_angley;
	private int m_mousex,m_mousey;


	private double m_xrotspeed = Math.PI/768;
	private double m_yrotspeed = Math.PI/512; 
	

	/**
	 * initialize things
	 */
	public void init(){
		super.init();
		
		m_mousex = m_mousey = 0;
		m_anglex = m_angley = Math.PI/4;
		
		pmatrix.translate(bounds().width/2,bounds().height/2,0);
		pmatrix.perspective(bounds().width,-1);
		
		// initialize curve
		Vector v_points = new Vector();
		Vector v_faces = new Vector();
	
		for(int i=0;i&lt;detail+1;i++){

			double angle = (double)i / (double)detail * Math.PI * 2.0;
			double angle2 = (double)i / (double)detail * Math.PI;
		
			matrix.push();
 
			matrix.rotatez(angle);
			matrix.translate(15,0,0);
			matrix.rotatez(Math.PI/2);
			matrix.rotatey(Math.PI/2);
			matrix.rotatez(angle / 2);
			
			v_points.addElement(matrix.mult(new double[]{3,-1,0,1}));
			v_points.addElement(matrix.mult(new double[]{3,1,0,1}));
			v_points.addElement(matrix.mult(new double[]{-3,1,0,1}));
			v_points.addElement(matrix.mult(new double[]{-3,-1,0,1}));

			matrix.pop();
	
			int j = (i+1) % (detail+1);
			int ir = i * 4;
			int jr = j * 4;

			v_faces.addElement(new int[]{ir+0,jr+0,jr+1,ir+1});
			v_faces.addElement(new int[]{ir+1,jr+1,jr+2,ir+2});
			v_faces.addElement(new int[]{ir+3,jr+3,jr+0,ir+0});
			v_faces.addElement(new int[]{ir+2,jr+2,jr+3,ir+3});
		}
		for(int i=0;i&lt;v_faces.size();i++){
			int[] face = (int[])v_faces.elementAt(i);
			for(int j=0;j&lt;4;j++){
				curve_points.addElement(v_points.elementAt(face[j]));
			}
		}

		v_points.removeAllElements();
		v_faces.removeAllElements();
		
		v_points.addElement(new double[]{1,-1,1.5,1});
		v_points.addElement(new double[]{1,1,1.5,1});
		v_points.addElement(new double[]{-1,1,1.5,1});
		v_points.addElement(new double[]{-1,-1,1.5,1});
		
		v_points.addElement(new double[]{1,-1,-1.5,1});
		v_points.addElement(new double[]{1,1,-1.5,1});
		v_points.addElement(new double[]{-1,1,-1.5,1});
		v_points.addElement(new double[]{-1,-1,-1.5,1});
				
		v_faces.addElement(new int[]{0,1,2,3});
		v_faces.addElement(new int[]{4,7,6,5});
		v_faces.addElement(new int[]{0,4,5,1});
		v_faces.addElement(new int[]{7,3,2,6});
		v_faces.addElement(new int[]{1,5,6,2});
		v_faces.addElement(new int[]{0,3,7,4});
		
		
		for(int i=0;i&lt;v_faces.size();i++){
			int[] face = (int[])v_faces.elementAt(i);
			for(int j=0;j&lt;4;j++){
				object_points.addElement(v_points.elementAt(face[j]));
			}
		}

		v_points.removeAllElements();
		v_faces.removeAllElements();


		
	}

	/**
	 * similar to glVertex
	 */
	private void addVertex(double x,double y,double z){
		points.addElement(matrix.mult(new double[]{x,y,z,1}));
		colors.addElement(currentColor);
	}

	/**
	 * dumps the scene
	 */
	public void dumpScene(){

		m_anglex += m_xrotspeed; //Math.PI/768;
		m_angley += m_yrotspeed; //Math.PI/512; 
		
		int i,j=curve_points.size();
		currentColor = Color.yellow;
		for(i=0;i&lt;j;i++){
			double[] point = (double[])curve_points.elementAt(i);
			addVertex(point[0],point[1],point[2]);
		}
		
		
		matrix.push();

		v1_angle += v1_speed;
		
		currentColor = Color.blue;
		
		matrix.rotatez(v1_angle);
		matrix.translate(15,0,0);
		matrix.rotatez(Math.PI/2);
		matrix.rotatey(Math.PI/2);
		matrix.rotatez(v1_angle / 2);
		matrix.translate(0,1.7,0);
		matrix.scale(1,0.5,1);
		
		j=object_points.size();
		for(i=0;i&lt;j;i++){
			double[] point = (double[])object_points.elementAt(i);
			addVertex(point[0],point[1],point[2]);
		}

		matrix.translate(0,1,0.5);
		matrix.scale(0.5,1,0.5);

		j=object_points.size();
		for(i=0;i&lt;j;i++){
			double[] point = (double[])object_points.elementAt(i);
			addVertex(point[0],point[1],point[2]);
		}
		
		matrix.pop();


		matrix.push();

		currentColor = Color.green;
		
		matrix.rotatez(v1_angle + Math.PI/2);
		matrix.translate(15,0,0);
		matrix.rotatez(Math.PI/2);
		matrix.rotatey(Math.PI/2);
		matrix.rotatez((v1_angle + Math.PI/2) / 2);
		matrix.translate(0,1.7,0);
		matrix.scale(1,0.5,1);
		
		j=object_points.size();
		for(i=0;i&lt;j;i++){
			double[] point = (double[])object_points.elementAt(i);
			addVertex(point[0],point[1],point[2]);
		}
		matrix.translate(0,1,0.5);
		matrix.scale(0.5,1,0.5);

		j=object_points.size();
		for(i=0;i&lt;j;i++){
			double[] point = (double[])object_points.elementAt(i);
			addVertex(point[0],point[1],point[2]);
		}
		
		matrix.pop();


		matrix.push();

		currentColor = Color.red;
		
		matrix.rotatez(v1_angle + Math.PI);
		matrix.translate(15,0,0);
		matrix.rotatez(Math.PI/2);
		matrix.rotatey(Math.PI/2);
		matrix.rotatez((v1_angle + Math.PI) / 2);
		matrix.translate(0,1.7,0);
		matrix.scale(1,0.5,1);
		
		j=object_points.size();
		for(i=0;i&lt;j;i++){
			double[] point = (double[])object_points.elementAt(i);
			addVertex(point[0],point[1],point[2]);
		}
		matrix.translate(0,1,0.5);
		matrix.scale(0.5,1,0.5);

		j=object_points.size();
		for(i=0;i&lt;j;i++){
			double[] point = (double[])object_points.elementAt(i);
			addVertex(point[0],point[1],point[2]);
		}
		
		matrix.pop();


		
	}

	/**
	 * sort via average z 
	 */
	public void sort(){
 		int i,j;
		int e1;
        double e2;
        for(i=1;i&lt;polyorder.length;i++){
            e1 = polyorder[i];
            e2 = avgz[i];
			
            for(j=i-1;j&gt;=0 &amp;&amp; avgz[j] &gt; e2;j--){
                avgz[j+1] = avgz[j];
				polyorder[j+1] = polyorder[j];
			}
			polyorder[j+1] = e1;			
            avgz[j+1] = e2;
        }
	}

	/**
  	 * function that gets called whenever something needs to be
	 * rendered.
	 */
    public void render(Graphics g) {		
		if (true || damage) {		
         	g.setColor(Color.lightGray);
         	g.fillRect(0, 0, bounds().width, bounds().height);

			matrix.push();
			
			matrix.translate(0,0,-144);
			matrix.scale(3);
			matrix.rotatey(m_angley);
			matrix.rotatex(m_anglex);

			dumpScene();


			// calculate average z for all points.
			avgz = new double[points.size() / 4];
			polyorder = new int[points.size() / 4];
						

			int k,i=0,j=points.size();
			double[] plane = new double[4];

			for(i=0;i&lt;j;i+=4){
				double sum = 0;
				for(k=0;k&lt;4;k++){
					double[] point = (double[])points.elementAt(i+k);
					sum += point[2];
				}
				avgz[i/4] = sum / 4;
				polyorder[i/4] = i/4;
			}
			sort(); // sort polyorder by avgz

			int[] x = new int[4];
			int[] y = new int[4];
			
			j = polyorder.length;
			for(i=0;i&lt;j;i++){
				int poly = polyorder[i] * 4;
				
				double[] p0 = (double[])points.elementAt(poly+0);
				double[] p1 = (double[])points.elementAt(poly+1);
				double[] p2 = (double[])points.elementAt(poly+2);
				double[] p3 = (double[])points.elementAt(poly+3);
				
				planeFromPoints(plane,p0,p1,p2);
				double d = plane[3];

				//if(d &gt; 0){
				
					for(k=0;k&lt;4;k++){
						double[] point = (double[])points.elementAt(poly+k);
						point = pmatrix.mult(point);
						x[k] = (int)(point[0] / point[3]);
						y[k] = (int)(point[1] / point[3]);
					}
					Color c = (Color)colors.elementAt(poly);
					
					double color1 = dotProduct(plane,new double[]{0,0,-1});
					
					if(color1 &lt; 0)
						color1 = 0;
						
					g.setColor(
						new Color(
							(float)(((c.getRed()+50) * color1)/306.0),
							(float)(((c.getGreen()+50) * color1)/306.0),
							(float)(((c.getBlue()+50) * color1)/306.0)
						)
					);
					g.fillPolygon(x,y,x.length);
					//g.setColor(c);
					//g.drawPolygon(x,y,x.length);
				//}
			}
			
			avgz = null;
			polyorder = null;
			matrix.pop();
			points.removeAllElements();
			colors.removeAllElements();
      	}
    }


	/**
	 * given 2 points, find their difference
	 */
	void vectorSubtract (double[] va, double[] vb, double[] out){
		out[0] = va[0]-vb[0];
		out[1] = va[1]-vb[1];
		out[2] = va[2]-vb[2];
	}
	
	/**
	 * cross product of two vectors
	 */
	void crossProduct(double[] v1, double[] v2, double[] cross ) {
		cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
		cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
		cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
	}

	/**
	 * normalize
	 */
	double vectorNormalize(double[] in, double[] out ) {
		double	length, ilength;
		length = Math.sqrt(in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
		if (length == 0){
			return 0;
		}
		ilength = 1.0/length;
		out[0] = in[0]*ilength;
		out[1] = in[1]*ilength;
		out[2] = in[2]*ilength;
		return length;
	}	

	/**
	 * dot product
	 */
	double dotProduct (double[] v1, double[] v2){
		return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
	}
		
	/**
	 * gets plane equation from three points on plane
	 */
	boolean planeFromPoints(double[] plane, double[] a, double[] b,double[] c ){
		double[] d1 = new double[4];
		double[] d2 = new double[4];
		vectorSubtract( b, a, d1 );
		vectorSubtract( c, a, d2 );
		crossProduct( d2, d1, plane );
		if ( vectorNormalize( plane, plane ) == 0 ) {
			return false;
		}
		plane[3] = dotProduct( a, plane );
		return true;
	}
	

	/**
	 * mouse event handler: let the user move things
	 */
	public boolean mouseDown(Event evt, int x, int y){
		m_xrotspeed = m_yrotspeed = 0.0; 
		return true;
	}
	public boolean mouseUp(Event evt, int x, int y){
		m_xrotspeed = Math.PI/768;
		m_yrotspeed = Math.PI/512; 
		return true;
	}
	
	/**
	 * mouse event handler: let the user move things
	 */
	public boolean mouseDrag(Event evt, int x, int y){
		if((m_mousey - y) &lt; 0)
			m_anglex += Math.PI/45;
		if((m_mousey - y) &gt; 0)
			m_anglex -= Math.PI/45;

		if((m_mousex - x) &lt; 0)
			m_angley -= Math.PI/45;
		if((m_mousex - x) &gt; 0)
			m_angley += Math.PI/45;
		m_mousex = x;
		m_mousey = y;

		damage = true;
		return true;
	}	
}
</pre></body></html>