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

/* Vytvoří obvyklou scénu a v metodě makeGun() přidá dělo, 
   laserový paprsek, explozi a zvuky.
*/

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

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


public class WrapShooter3D 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; 
  private static final int BOUNDSIZE = 100;  // větší než virtuální svět

  private static final Point3d USERPOSN = new Point3d(0,5,20);
    // počáteční pozice uživatele

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


  public WrapShooter3D()
  // 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);     // předej focus herní obrazovce
    canvas3D.requestFocus();

    su = new SimpleUniverse(canvas3D);

    // vytvoř zvukové zařízení
    AudioDevice audioDev = su.getViewer().createAudioDevice();
    
    createSceneGraph(canvas3D);
    initUserPosition();        // nastav stanoviště pozorovatele
    orbitControls(canvas3D);   // ovládací prvky pro pohyb tohoto stanoviště

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



  private void createSceneGraph(Canvas3D canvas3D) 
  // inicializuje scénu
  { 
    sceneBG = new BranchGroup();
/*  // pro ladění vybírání
    sceneBG.setUserData("uzel sceneBG");
    sceneBG.setCapability(BranchGroup.ENABLE_PICK_REPORTING);    
*/
    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

    makeGun(canvas3D);
  } // konec metody: createSceneGraph()


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

    // připrav ambientní světlo
    AmbientLight ambientLightNode = new AmbientLight(white);
    ambientLightNode.setInfluencingBounds(bounds);
    sceneBG.addChild(ambientLightNode);

    // připrav směrová světla
    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()


  private void orbitControls(Canvas3D c)
  /* Třída OrbitBehaviour umožňuje uživateli otáčet, přibližovat a oddalovat scénu. */
  { OrbitBehavior orbit = 
		new OrbitBehavior(c, OrbitBehavior.REVERSE_ALL);
    orbit.setSchedulingBounds(bounds);
    ViewingPlatform vp = su.getViewingPlatform();
    vp.setViewPlatformBehavior(orbit);	    
  }  // konec metody: orbitControls()



  private void initUserPosition()
  // Pomocí metody lookAt() nastaví počáteční výhled uživatele
  {
    ViewingPlatform vp = su.getViewingPlatform();
    TransformGroup steerTG = vp.getViewPlatformTransform();

    Transform3D t3d = new Transform3D();
    steerTG.getTransform(t3d);

    // argumenty jsou: pozice pozorovatele, kam se dívá, směr nahoru
    t3d.lookAt( USERPOSN, new Point3d(0,0,0), new Vector3d(0,1,0));
    t3d.invert();

    steerTG.setTransform(t3d);
  }  // konec metody: initUserPosition()



  // ---------------------- dělo -----------------


  private void makeGun(Canvas3D canvas3D)
  /* Dělo je válec s kuželem na konci, které se může otáčet.
     Uvnitř kužele je malý červený válec, se kterého se pomocí
     animace stane laserový paprsek.
     Když uživatel klepne na šachovnici, dojde k vystřelení
     paprsku směrem k místu, kam klepnul. Jakmile zasáhne cíl,
     spustí se exploze.
     Let paprsku a explozi doprovázejí patřičné zvuky.
  */
  { // počáteční vektor pro kužel děla a paprsek
    Vector3d startVec = new Vector3d(0, 2, 0);

    // dělo
    GunTurret gun = new GunTurret(startVec);
    sceneBG.addChild( gun.getGunBG() );

    // exploze a zvuk
    PointSound explPS = initSound("Explo1.wav");
    ExplosionsClip expl = new ExplosionsClip( startVec, explPS);
    sceneBG.addChild( expl.getExplBG() );

    // laserový paprsek a jeho zvuk
    PointSound beamPS = initSound("laser2.wav");
    LaserBeam laser = new LaserBeam( startVec, beamPS);
    sceneBG.addChild( laser.getBeamBG() );

    // chování ovládající střelbu
    ShootingBehaviour shootBeh = new ShootingBehaviour(canvas3D, sceneBG, bounds, 
                                           new Point3d(0,2,0), expl, laser, gun );
    sceneBG.addChild(shootBeh);
  } // konec metody: makeGun()



  private PointSound initSound(String filename)
  // vytvoř bodový zvuk pomocí souboru filename (umístěného v bodu (0,0,0))
  {
    MediaContainer soundMC = null;
    try {
      soundMC = new MediaContainer("file:sounds/" + filename);
      soundMC.setCacheEnable(true);   // načti zvuk do kontejnéru pro média
    }
    catch (Exception ex)
    {  System.out.println(ex); }

    // vytvoř bodový zvuk
    PointSound ps = new PointSound();
    ps.setSchedulingBounds( bounds );
    ps.setSoundData( soundMC );

    ps.setInitialGain(1.0f);  // zvuk bude od začátku naplno

    ps.setCapability(PointSound.ALLOW_ENABLE_WRITE);    // lze jej vypnouta zapnout
    ps.setCapability(PointSound.ALLOW_POSITION_WRITE);  // pozici lze upravit

    System.out.println("PointSound vytvořen ze sounds/" + filename);
    return ps;
  } // konec metody: initSound()


} // konec třídy: WrapShooter3D