import java.util.*;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class SphereDemoJ extends Applet {
    public SphereDemoJ() {}

    Random        r = new Random();
    Color3f   black = new Color3f(0.0f, 0.0f, 0.0f);
    Color3f   white = new Color3f(1.0f, 1.0f, 1.0f);
    Behavior  rotator;
    Label     framerate = new Label("frame rate or time per frame");

    public BranchGroup createSceneGraph() {
        BranchGroup    objRoot  = new BranchGroup();
        TransformGroup objTrans = new TransformGroup();
        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        objRoot.addChild(objTrans);

        for (int i=0;i<10;i++) {
            Color3f   oc = new Color3f(r.nextFloat(),r.nextFloat(),r.nextFloat());
            Material   m = new Material(oc,black,oc,white, 100.0f);
            Appearance a = new Appearance();
            m.setLightingEnable(true);
            a.setMaterial(m);

            Sphere sph = new Sphere((r.nextFloat())/2,
                                    Sphere.GENERATE_NORMALS, 30, a);
            Transform3D t = new Transform3D();
            t.set(new Vector3f(r.nextFloat()-.5f,
                               r.nextFloat()-.5f,
                               r.nextFloat()-.5f));
            TransformGroup tg = new TransformGroup(t);
            tg.addChild(sph);
            objTrans.addChild(tg);
        }

        BoundingSphere bnd = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);

        rotator = new FrameBasedRotator((float)Math.PI*2.0f/360*4,objTrans,framerate);
        rotator.setEnable(false);
        rotator.setSchedulingBounds(bnd);
        objRoot.addChild(rotator);

        Vector3f lDir1  = new Vector3f(0.0f, -.5f, -1.0f);
        DirectionalLight lgt1 = new DirectionalLight(white, lDir1);
        lgt1.setInfluencingBounds(bnd);

        objRoot.addChild(lgt1);
        objRoot.compile();
        return objRoot;
    }

    public void init() {
        setLayout(new BorderLayout());

        Canvas3D c = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
        SimpleUniverse u = new SimpleUniverse(c);
        u.getViewingPlatform().setNominalViewingTransform();
        u.addBranchGraph(createSceneGraph());
        add("Center", c);

        Panel jp = new Panel();
        Button rs = new Button("run/stop");
        rs.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                rotator.setEnable(!rotator.getEnable());
            }
        });
        jp.add(rs);
        jp.add(framerate);
        add("South",jp);
    }
    public static void main(String[] args) {
        new MainFrame(new SphereDemoJ(), 300, 350);
    }
}



/**
 *  Java by default provides time-based rotators (i.e.
 *  this object rotate 360 degrees every 4 seconds).
 *
 *  The curl example used a frame-based one (i.e.
 *  rotate 4 degrees every frame).  In my opinion,
 *  this shouldn't be counted against Java in the 
 *  code-complexity measure merely because they picked
 *  different default behaviors.
 */
    class FrameBasedRotator extends Behavior {
        TransformGroup tg;
        Transform3D    rAxis = new Transform3D(); // silly java local var.
        float          delta,ang;
        int            framecount;
        public long    frametime,now,last,avg;
        Label          framerate;

        WakeupOnElapsedFrames wkup = new WakeupOnElapsedFrames(0);
        FrameBasedRotator(float delta,TransformGroup tg,Label l) {
            this.tg    = tg;
            this.delta = delta;
            framerate = l;
            last=now=new Date().getTime();
        }
        public void initialize() {
            wakeupOn(wkup);
        }
        public void processStimulus(java.util.Enumeration criteria) {
            last=now;now=new Date().getTime();frametime=now-last;
            avg=(3*avg + frametime)/4;
            framerate.setText(""+avg+" ms/frame");
            rAxis.rotY(ang += delta);
            tg.setTransform(rAxis);
            wakeupOn(wkup);
        }
    }
