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

import java.awt.*;
import java.util.*;

/*
class BodyNode {

    public Vector children;
    public pMatrix matrix;

    public BodyNode(){
        children = new Vector();
        matrix = new pMatrix();
    }
}
*/

public class PuppetApplet 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 cube = new Vector();

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

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

    /**
     * dumps phere to rendering pipeline
     */
    public void dumpCube(){
        int i,j;
        j=cube.size();
        for (i=0;i&lt;j;i++) {
            double[] point = (double[])cube.elementAt(i);
            addVertex(point[0],point[1],point[2]);
        }
    }

    /**
     * initialize things
     */
    public void init(){
        super.init();

        m_mousex = m_mousey = 0;
        m_anglex = m_angley = 0;

        pmatrix.translate(bounds().width/2,bounds().height/2,0);
        pmatrix.perspective(bounds().width/1.5,-1);

        // initialize cube
        Vector v_points = new Vector();
        Vector v_faces = new Vector();

        v_points.addElement(new double[]{1,-1,1,1});
        v_points.addElement(new double[]{1,1,1,1});
        v_points.addElement(new double[]{-1,1,1,1});
        v_points.addElement(new double[]{-1,-1,1,1});

        v_points.addElement(new double[]{1,-1,-1,1});
        v_points.addElement(new double[]{1,1,-1,1});
        v_points.addElement(new double[]{-1,1,-1,1});
        v_points.addElement(new double[]{-1,-1,-1,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++) {
                cube.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);
    }

    public void dumpModel(){
        double a,b,c;

        // dump something interesting...
        /*
        matrix.push();
        matrix.scale(16);
        currentColor = null;
        dumpCube();
        matrix.pop();
        */

        double s = 3.8;

        a = -s * 4;
        for(int i=0;i&lt;9;i++){
            b = -s * 4;
            for(int j=0;j&lt;9;j++){
                c = -s * 4;
                for(int k=0;k&lt;9;k++){
                    if((i ^ j ^ k) % 2 == 0){
                        currentColor = new Color((int)(0xFF*i/9.0),(int)(0xFF*j/9.0),(int)(0xFF*k/9.0));
                        matrix.push();
                        matrix.translate(a,b,c);
                        dumpCube();
                        matrix.pop();
                    }                    
                    c += s;
                }
                b += s;
            }
            a += s;
        }
    }

    /**
     * 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;
        }
    }

    pMatrix camera = new pMatrix();

    /**
     * function that gets called whenever something needs to be
     * rendered.
     */
    public void render(Graphics g) {
        if (damage) {

            g.setColor(Color.lightGray);
            g.fillRect(0, 0, bounds().width, bounds().height);

            matrix.push();

            matrix.translate(0,0,-144);

            matrix.scale(2.6);
            
            /*
            g.setColor(Color.black);
            g.drawString("sin: "+m_angley+"; cos: "+(m_anglex)+"; ang: "+ Math.atan2(m_anglex,m_angley),10,10);
            */

            if(m_angley != 0 || m_anglex != 0){                
                pMatrix nm = new pMatrix();                
                nm.rotatex(m_anglex);
                nm.rotatey(m_angley);
                nm.mult(camera);
                camera = nm;
                m_anglex = m_angley = 0;
            }
            matrix.mult(camera);

            dumpModel();

            // 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);

                Color c = (Color)colors.elementAt(poly);

                if(c != null){

                    planeFromPoints(plane,p0,p1,p2,p3);
                    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]);
                        }

                        double color1 = Math.max(0,dotProduct(plane,new double[]{0,0,-1}));

                        g.setColor(
                            new Color(
                                (float)Math.min( ((c.getRed()+50) * color1)/255.0, 1.0  ),
                                (float)Math.min( ((c.getGreen()+50) * color1)/255.0, 1.0 ),
                                (float)Math.min( ((c.getBlue()+50) * color1)/255.0, 1.0 )
                            )
                        );
                        g.fillPolygon(x,y,x.length);
                        g.setColor(Color.black);
                        g.drawPolygon(x,y,x.length);
                    }
                }else{
                    
                    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]);
                    }
                    g.setColor(Color.black);
                    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[] d ){

        double[] d1 = new double[4];
        double[] d2 = new double[4];
        vectorSubtract( b, a, d1 );
        if (dotProduct(d1,d1) &lt; 0.02) {
            vectorSubtract( c, a, d1 );
            vectorSubtract( d, a, d2 );
        } else {
            vectorSubtract( c, a, d2 );
            if (dotProduct(d2,d2) &lt; 0.02) {
                vectorSubtract( d, 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_mousex = x;
        m_mousey = y;
        return true;
    }
    public boolean mouseUp(Event evt, int x, int y){
        return true;
    }

    /**
     * mouse event handler: let the user move things
     */
    public boolean mouseDrag(Event evt, int x, int y){
        m_angley = m_angley + .015 * (double)(x - m_mousex);
        m_anglex = m_anglex + .015 * (double)(y - m_mousey);

        m_mousex = x;
        m_mousey = y;

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