// VidScope - Gyrating 2D images
// Copyright (C) June 2004 Neil Fraser
// http://neil.fraser.name

// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General
// Public License as published by the Free Software Foundation.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// http://www.gnu.org/

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

public class vidscope extends java.applet.Applet implements Runnable {

    private int xPoints[];
    private int yPoints[];
    private Color bgcolor = Color.white;
    private Color color = Color.black;
    private int maxX = Integer.MIN_VALUE;
    private int maxY = Integer.MIN_VALUE;
    private int minX = Integer.MAX_VALUE;
    private int minY = Integer.MAX_VALUE;
    private double magXY;
    private int dx, dy;
    private int height, width;
    private double rotX=0, rotY=0, rotZ=0;
    int speed = 100;
    Thread clock;

    public void init() {

        super.init();

        // Read the colour data from the HTML parameters.
        String colorparam = getParameter("bgcolor");
        if (colorparam != null)
            try {
                bgcolor = new Color(Integer.parseInt(colorparam, 16));
            } catch(Exception e) {
                System.out.print("Invalid bgcolor: ["+colorparam+"]\n");
            }
        colorparam = getParameter("color");
        if (colorparam != null)
            try {
                color = new Color(Integer.parseInt(colorparam, 16));
            } catch(Exception e) {
                System.out.print("Invalid color: ["+colorparam+"]\n");
            }

        // Read the data string from the HTML parameters.
        String dataString = getParameter("data");
        if (dataString == null)
            dataString = "1,1,2,1,1,2,2,2";

        // Split the data string into integers.
        int i;
        dataString = dataString+",";
        String datumString;
        int datumInt;
        Vector data = new Vector();
        while ((i = dataString.indexOf(",")) != -1) {
            datumString = dataString.substring(0, i).trim();
            try {
                datumInt = Integer.parseInt(datumString);
                data.addElement(new Integer(datumInt));
            } catch (Exception e) {
                System.out.print("Invalid data: ["+datumString+"]\n");
                return;
            }
            dataString = dataString.substring(i+1);
        }

        // Build a list of xPoints and yPoints
        // Also find out the image boundries.
        xPoints = new int[data.size()/2];
        yPoints = new int[data.size()/2];
        for (i = 0; i < data.size()/2; i++) {
            xPoints[i] = ((Integer) data.elementAt(i*2)).intValue();
            yPoints[i] = ((Integer) data.elementAt(i*2+1)).intValue();
            if (maxX < xPoints[i])
                maxX = xPoints[i];
            if (maxY < yPoints[i])
                maxY = yPoints[i];
            if (minX > xPoints[i])
                minX = xPoints[i];
            if (minY > yPoints[i])
                minY = yPoints[i];
            System.out.print("Data point #"+i+" ["+xPoints[i]+", "+yPoints[i]+"]\n");
        }

        // Calculate the static magnification.
        width = size().width;
        height = size().height;
        double magX = width / (maxX - minX);
        double magY = height / (maxY - minY);
        magXY = (magX < magY) ? magX : magY;
        magXY = magXY / Math.sqrt(2);  // Squeeze so that square edges don't go out of frame when rotated.

        // Calculate the static offsets.
        dx = (int) ((width - ((maxX - minX)*magXY)) / 2 - minX*magXY);
        dy = (int) ((height - ((maxY - minY)*magXY)) / 2 - minY*magXY);
        System.out.print("minX="+minX+"   maxX="+maxX+"   minY="+minY+"   maxY="+maxY+"\n");
        System.out.print("width="+width+"   height="+height+"\n");
        System.out.print("dx="+dx+"   dy="+dy+"   magXY="+magXY+"\n");
    }

    public void paint(Graphics g) {
        // Redraw the entire screen from scratch.
        double rotXc = Math.cos(rotX);
        double rotYc = Math.cos(rotY);
        double rotZs = Math.sin(rotZ);
        double rotZc = Math.cos(rotZ);
        int xDistorted[] = new int[xPoints.length];
        int yDistorted[] = new int[xPoints.length];
        int tempX;
        for (int i = 0; i < xPoints.length; i++) {
            xDistorted[i] = (int) (((xPoints[i] * magXY + dx) - width/2.0) * rotXc);
            yDistorted[i] = (int) (((yPoints[i] * magXY + dy) - height/2.0) * rotYc);
            tempX = (int) (xDistorted[i] * rotZc - yDistorted[i] * rotZs + width/2.0);
            yDistorted[i] = (int) (xDistorted[i] * rotZs + yDistorted[i] * rotZc + height/2.0);
            xDistorted[i] = tempX;
        }
        setBackground(bgcolor);
        setForeground(color);
        g.fillPolygon(xDistorted, yDistorted, xDistorted.length);
    }

    public void start() {
        clock = new Thread(this);
        clock.start();
    }
    public void stop() {
        clock.stop();
    }

    public void run() {
        while (true) {
            try {Thread.currentThread().sleep(speed);} catch (InterruptedException e){}
            rotX+=0.04;
            rotY+=0.03;
            rotZ+=0.02;
            repaint();
        }
    }
}
