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

/* Ukázkový příklad střílečky z vlatního pohledu (FPS) ve světě
   s šachovnicí.

   Model cíle načítáme pomocí třídy PropManager v metodě createSceneGraph().
   
   Metoda initUserControls() provádí většinu věcí, souvisejících s FPS.
    * připraví obrázek ruky se zbraní
    * pohybuje výhledem uživatele
    * volá metody třídy AmmoManager pro vytvoření paprsků a explozí
    * vytvoří objekt typu KeyBehavior určený ke zpracování vstupu z klávesnice
*/

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

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



public class WrapFPShooter3D extends JPanel
// Uchovává 3D-canvas, na nemž se zobrazuje nactený obrázek
{
  private static final int PWIDTH = 512;   // velikost panelu
  private static final int PHEIGHT = 512; 
  // info used to position initial viewpoint
  private final static double Z_START = 9.0;

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

  private static final String TARGET = "Coolrobo.3ds";  // robot jako 3DS-model
  private static final String GUN_PIC = "images/gunDoom.gif";


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


  public WrapFPShooter3D()
  // zkonstruuje 3D-canvas
  {
    setLayout( new BorderLayout() );
    setOpaque( false );
    setPreferredSize( new Dimension(PWIDTH, PHEIGHT));

    GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
    Canvas3D canvas3D = new Canvas3D(config);
    add("Center", canvas3D);

    canvas3D.setFocusable(true);
    canvas3D.requestFocus();    // vstup od klávesnice je náš, přijímáme tedy její události

    su = new SimpleUniverse(canvas3D);

    createSceneGraph();
    su.addBranchGraph( sceneBG );
  } // konec metody: WrapFPShooter3D()


  private void createSceneGraph() 
  // inicializuje scénu
  { 
    sceneBG = new BranchGroup();
    bounds = new BoundingSphere(new Point3d(0,0,0), BOUNDSIZE); 

    lightScene();         // přidej světla
    addBackground();      // přidej oblohu
    sceneBG.addChild( new CheckerFloor().getBG() );  // přidej podlahu

    // přidej cíl
    PropManager propMan = new PropManager(TARGET, true);
    sceneBG.addChild( propMan.getTG() );
    Vector3d targetVec = propMan.getLoc();
    System.out.println("Lokace cíle: " + targetVec );

    initUserControls(targetVec);

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



  private void lightScene()
  /* Jedno ambientní svetlo, 2 smerová svetla */
  {
    Color3f white = new Color3f(1.0f, 1.0f, 1.0f);

    // priprav ambientní svetlo
    AmbientLight ambientLightNode = new AmbientLight(white);
    ambientLightNode.setInfluencingBounds(bounds);
    sceneBG.addChild(ambientLightNode);

    // priprav smerová svetla
    Vector3f light1Direction  = new Vector3f(-1.0f, -1.0f, -1.0f);
       // vlevo, dolů, dozadu 
    Vector3f light2Direction  = new Vector3f(1.0f, -1.0f, 1.0f);
       // vpravo, dolu, dopredu

    DirectionalLight light1 = 
            new DirectionalLight(white, light1Direction);
    light1.setInfluencingBounds(bounds);
    sceneBG.addChild(light1);

    DirectionalLight light2 = 
        new DirectionalLight(white, light2Direction);
    light2.setInfluencingBounds(bounds);
    sceneBG.addChild(light2);
  }  // konec metody: lightScene()


  private void addBackground()
  // modrá obhloha
  { Background back = new Background();
    back.setApplicationBounds( bounds );
    back.setColor(0.17f, 0.65f, 0.92f);    // barva oblohy
    sceneBG.addChild( back );
  } // konec metody: addBackground()



// --------------------- ovládací prvky uživatele ----------------------------------


  private void initUserControls(Vector3d targetVec)
  /* Připraví obrázek ruky se zbraní a umístí výhled.
     Zavolá metodu třídy AmmoManager pro vytvoření paprsků a explozí.
     Vytvoří objekt typu KeyBehavior pro zpracování vstupu z klávesnice.
  */
  { 
    // přidej k výhledu obrázek zbraně v ruce
    ViewingPlatform vp = su.getViewingPlatform();
    PlatformGeometry pg = gunHand();
    vp.setPlatformGeometry(pg);

    // umísti výhled
    TransformGroup steerTG = vp.getViewPlatformTransform();
    Transform3D t3d = new Transform3D();
    steerTG.getTransform( t3d );
    t3d.setTranslation( new Vector3d(0, 1, Z_START) );
    steerTG.setTransform(t3d);

    // vytvoř náboje (paprsky a exploze)
    AmmoManager ammoMan = new AmmoManager(steerTG, sceneBG, targetVec);

    // připrav ovládací prvky klávesnice
    KeyBehavior keyBeh = new KeyBehavior( ammoMan );
         // objekt keyBeh se může požádat objekt ammoManager 
  // o vystřelení paprsku
    keyBeh.setSchedulingBounds(bounds);
    vp.setViewPlatformBehavior(keyBeh);
  }  // konec metody: initUserControls()


  private PlatformGeometry gunHand()
  // Přidá obrázek ruky se zbraní k uzlu typu PlatformGeometry
  {
    PlatformGeometry pg = new PlatformGeometry();
    Point3f p1 = new Point3f(-0.1f, -0.3f, -0.7f);
    Point3f p2 = new Point3f(0.1f, -0.3f, -0.7f);
    Point3f p3 = new Point3f(0.1f, -0.1f, -0.7f);
    Point3f p4 = new Point3f(-0.1f, -0.1f, -0.7f);
    TexturedPlane tp = new TexturedPlane(p1, p2, p3, p4, GUN_PIC);
    pg.addChild( tp );
    return pg;
  } // konec metody: gunHand()


} // konec třídy: WrapFPShooter3D