//
// SHOW CLOSE-PACKING OF SPHERES

import java.awt.*;
import render.*;

public class packing extends RenderApplet
{
   Geometry spheres, links;
   Material pearl, bronze, steel;
   double radius = .5, fov = .3;
   boolean showLinks = true;

   // INITIALIZE EVERYTHING

   public void initialize() {

      // SET BACKGROUND COLOR, FIELD OF VIEW AND FOCAL LENGTH

      setBgColor(.4,.4,.8);
      setFOV(fov);
      setFL(20);

      // DEFINE X,Y,Z AND RED,GREEN,BLUE FOR EACH LIGHT SOURCE

      addLight( 1, 1, 1,  .5 ,.4  ,.3 );
      addLight(-1, 1,-1,  .1  ,.07,.35);
      addLight( 1, 1,-1,  .012,.02,.22);
      addLight(.5, 1,-1,  .012,.02,.22);
      addLight(.0,-1,-1,  .22 ,.12,.02);

      // CREATE SURFACE MATERIALS

      pearl  = (new Material()).setColor(.8,.8,.8, 1,1,1,10, .4,.4,.4);
      bronze = (new Material()).setColor(.5,.35,.25, 1,1,1,3, .2,.14,.1);
      steel  = (new Material()).setColor(.5,.5,.5, 1.5,1.5,1.5,20, .1,.1,.25);

      pearl.noiseF = 2;
      pearl.noiseA = 1;
      bronze.noiseF = 3;
      bronze.noiseA = .5;

      spheres = world.add();
      links = world.add();

      // MAKE THE CENTRAL (WHITE) SPHERE

      Geometry s = spheres.add().setMaterial(pearl).add().ball(16);

      // PLACE THE 12 SURROUNDING (RED) SPHERES AS FOLLOWS:

      for (int i = 0 ; i < 12 ; i++) {
	 push();

         // TRAVEL AROUND THE EQUATOR IN 12 EQUAL STEPS

	    rotateY(i * Math.PI / 6);

         // ODD NUMBERED SPHERE: REMAIN ON THE EQUATOR
         // ODD MULTIPLE OF TWO: TILT UP BY .955 RADIANS
         // MULTIPLE OF FOUR:    TILT DOWN  .955 RADIANS

	    rotateX(i % 2 != 0 ? 0 : i % 4 != 0 ? -.955 : .955);

         // CREATE AND POSITION THE SPHERE OBJECT

            translate(0,0,2);
            transform(s = spheres.add());

         // - CREATE THE (RE-SIZABLE) SPHERICAL BALL

            s.add().ball(12).setMaterial(bronze);

         // - CREATE A CYLINDER LINKING TO THE CENTER SPHERE

            translate(0,0,-1);
            scale(.07,.07,1);
	    transform(links.add().cylinder(16).setMaterial(steel));

	 pop();
      }

      // SET THE INITIAL SIZE FOR EACH SPHERE

      scaleSpheres(radius);
   }

   // SCALE ALL SPHERES

   void scaleSpheres(double r) {
      radius = Math.max(.2, Math.min(1, r));
      scale(radius,radius,radius);
      for (int i = 0 ; i <= 12 ; i++)
         transform(spheres.child[i].child[0]);
   }

   // RESPOND TO USER KEYBOARD COMMANDS

   public boolean keyUp(Event e, int key) {
      super.keyUp(e, key);
      switch (key) {
      case ' ':                     // SPACE KEY:   TOGGLE LINKS
         showLinks = ! showLinks;
	 steel.setTransparency(showLinks ? 0 : 1);
	 break;
      case 1004:                    // UP ARROW:    NARROW VIEW
         setFOV(fov = Math.max(.1,fov-.05));
	 break;
      case 1005:                    // DOWN ARROW:  WIDEN VIEW
         setFOV(fov = Math.min(.5,fov+.05));
	 break;
      case 1006:                    // LEFT ARROW:  SHRINK SPHERES
         scaleSpheres(radius-.1);
         break;
      case 1007:                    // RIGHT ARROW: GROW SPHERES
         scaleSpheres(radius+.1);
         break;
      }
      damage();
      return true;
   }
}