
// WrapNetFBF.java
// Andrew Davison, April 2005, ad@fivedots.coe.psu.ac.th

/* Obsahuje 16 holí, z nichž každá má 4 kuličky. Hráč
   provádí tah klepnutím na některou z nich, čímž ji změní
   na červenou kuličku nebo modrou kostičku v závislosti na tom,
   o kterého hráče se jedná. 

   Hra se zobrazuje pomocí rovnoběžné projekce, takže hole vzadu 
   nejsou menší než ty vpředu -- neexistuje perspektiva.

   Hra používá vlastní objekt pro řízení chování myši, realizovaný
   třídou PickDragBehavior, který slouží pro volbu pozice na herní
   desce a k její rotaci.

   Změny v síťové verzi:
       * deska je globální a obsahuje novou metodu setPosn()
       * používá OverlayCanvas() místo OverlayCanvas
*/


import javax.swing.*;
import java.awt.*;

import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
import javax.media.j3d.*;
import javax.vecmath.*;



public class WrapNetFBF extends JPanel
// Uchovává 3D-canvas, na němž se hra objevuje 
{
  private static final int PWIDTH = 400;   // velikost panelu
  private static final int PHEIGHT = 400; 

  private static final int BOUNDSIZE = 100;  // větší než svět

  private SimpleUniverse su;
  private BranchGroup sceneBG;
  private BoundingSphere bounds;   // pro uzly prostredí

  private Board board;

  public WrapNetFBF(NetFourByFour fbf)
  {
    setLayout( new BorderLayout() );
    setOpaque( false );
    setPreferredSize( new Dimension(PWIDTH, PHEIGHT));

    GraphicsConfiguration config =
					SimpleUniverse.getPreferredConfiguration();
    OverlayCanvas OverlayCanvas = new OverlayCanvas(config, fbf);
    add("Center", OverlayCanvas);
    OverlayCanvas.setFocusable(true);     // předej focus herní obrazovce
    OverlayCanvas.requestFocus();

    su = new SimpleUniverse(OverlayCanvas);

    createSceneGraph(OverlayCanvas, fbf);
    initUserPosition();        // nastav stanoviště pozorovatele
    
    su.addBranchGraph( sceneBG );
  } // konec metody: WrapNetFBF()



  private void createSceneGraph(OverlayCanvas OverlayCanvas, NetFourByFour fbf)
  { sceneBG = new BranchGroup();
    bounds = new BoundingSphere(new Point3d(0,0,0), BOUNDSIZE);   

    // Vytvoř transformační skupinu pro pohyb celé hry
    TransformGroup tg = new TransformGroup();
    tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    sceneBG.addChild(tg);

    lightScene();         // přidej světla
    addBackground();      // přidej pozadí

    tg.addChild( makePoles() );       // přidej hole

    // posns uchovává kuličky/kostičky, které označují tah hráče
    // Zpočátku zobrazuje sérii malých bílých kuliček.
    Positions posns = new Positions();

    // objekt board sleduje tahy hráčů na herní desce
    board = new Board(posns, fbf);

    gameTG.addChild( posns.getChild() );  // přidej značky pozic

    mouseControls(OverlayCanvas, fbf, tg);

    sceneBG.compile();   // zafixuj scénu
  } // konec metody: createSceneGraph()



  private void lightScene()
  // jedno ambientní a jedno směrové světlo
  {
    Color3f white = new Color3f(1.0f, 1.0f, 1.0f);

    // vytvoř ambientní světlo
    AmbientLight ambLight = new AmbientLight(white);
    ambLight.setInfluencingBounds(bounds);
    sceneBG.addChild(ambLight);

    // vytvoř směrové světlo
    Vector3f dir = new Vector3f(-1.0f, -1.0f, -1.0f);
    DirectionalLight dirLight = new DirectionalLight(white, dir);
    dirLight.setInfluencingBounds(bounds);
    sceneBG.addChild(dirLight);
  }  // konec metody: lightScene()


  private void addBackground()
  { 
    Background back = new Background();
    back.setApplicationBounds( bounds );
    back.setColor(0.05f, 0.05f, 0.2f);  // dark blue
    sceneBG.addChild( back );
  }  // konec metody: addBackground()


  private void mouseControls(OverlayCanvas c, Board board, TransformGroup tg)
  // Vytvoří objekt chování pro vybírání a tažení myší
  {
    PickDragBehavior mouseBeh =  
        new PickDragBehavior(c, fbf, sceneBG, tg);
    mouseBeh.setSchedulingBounds(bounds);
    sceneBG.addChild(mouseBeh);
  }  // konec metody: mouseControls()



  private void initUserPosition()
  // Nastaví počáteční výhled uživatele
  { 
    View view = su.getViewer().getView();
    view.setProjectionPolicy(View.PARALLEL_PROJECTION);  // nastav rovnoběžnou projekci

    // posuň výhled o něco zpět
    TransformGroup steerTG = 
         su.getViewingPlatform().getViewPlatformTransform();
    Transform3D t3d = new Transform3D();
    t3d.set(65.0f, new Vector3f(0.0f, 0.0f, 400.0f));
    steerTG.setTransform(t3d);
  }  // konec metody: initUserPosition()



  // ------------------------ herní hole -------------------


  private BranchGroup makePoles()
  /* Vytvoří 16 holí (válečků), které se objeví podél 4 pozičních značek (kuliček). */
  {
     Color3f grey = new Color3f(0.25f, 0.25f, 0.25f);
     Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
     Color3f diffuseWhite = new Color3f(0.7f, 0.7f, 0.7f);
     Color3f specularWhite = new Color3f(0.9f, 0.9f, 0.9f);

     // Vytvoř vzhled hole
     Material poleMaterial =
        new Material(grey, black, diffuseWhite, specularWhite, 110.f);  // a její lesk
     poleMaterial.setLightingEnable(true);
     Appearance poleApp = new Appearance();
     poleApp.setMaterial(poleMaterial);
 
     BranchGroup bg = new BranchGroup();
     float x = -30.0f;
     float z = -30.0f;

     for(int i=0; i<4; i++) {
       for(int j=0; j<4; j++) {
         Transform3D t3d = new Transform3D();
         t3d.set( new Vector3f(x, 0.0f, z) );
         TransformGroup tg = new TransformGroup(t3d);
         Cylinder cyl = new Cylinder(1.0f, 60.0f, poleApp);
         cyl.setPickable(false);  // uživatel nemůže zvolit hole
         tg.addChild( cyl );
         bg.addChild(tg);
         x += 20.0f;
       }
       x = -30.0f;
       z += 20.0f;
     }
     return bg;
  }  // konec metody: makePoles()


  // -------------------- metody pro práci s pozicí

  public void tryPosn(int posn, int pid)
  // volá se z nejvyšší úrovně přes okno typu JFrame
  {  board.tryPosn(posn, pid);  }

} // konec třídy: WrapNetFBF