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

/* Objekt typu LaserBeam tvoří červený válec, který se otáčí
   směrem k bodu, který zvolil uživatel na šachovnici.
   Třída FireBeam volá metodu shootBeam() pro přesun paprsku
   krok za krokem k cílovému místu, čímž simuluje letící střelu.
   S paprskem ej také spojen zvuk, který se s ním pohybuje.

   BG-->uzel typu TG paprsku -->červený válec
				|
				-->objekt beamPS typu PointSound
*/

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


public class LaserBeam
{
  private static final Vector3d ORIGIN = new Vector3d(0, 0, 0);
  private static final double STEP_SIZE = 1.0;  // vzdálenost uražená po každém kroku
  private static final long SLEEP_TIME = 100;   // prodleva v ms mezi pohyby paprsku

  private BranchGroup beamBG;
  private TransformGroup beamTG;
  private PointSound beamPS;
  private Vector3d startVec, currVec, stepVec;
  private Point3d startPt;

  // pro opakované výpočty
  private Transform3D beamT3d = new Transform3D();
  private Vector3d currTrans = new Vector3d();
  private Transform3D rotT3d = new Transform3D();



  public LaserBeam(Vector3d start, PointSound snd)
  {
    startVec = start;
    startPt = new Point3d(start.x, start.y, start.z);
    beamPS = snd;

    currVec = new Vector3d();    // pro výpočty pohybu
    stepVec = new Vector3d();

    makeBeam();
  } // konec metody: LaserBeam()


  private void makeBeam()
  // sestaví větev grafu scény pro laserový paprsek
  {
    // vytvoří transformační skupinu pro válec laserového paprsku
    beamTG = new TransformGroup();
    beamTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    beamTG.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

    // umístí laserový paprsek
    beamT3d.set(startVec);   // aby byl uvnitř kužele
    beamTG.setTransform(beamT3d);

    // inicializuj červený vzhled
    Appearance apRed = new Appearance();
    ColoringAttributes redCA = new ColoringAttributes();
    Color3f medRed = new Color3f(0.8f, 0.4f, 0.3f);
    redCA.setColor( medRed );
    apRed.setColoringAttributes( redCA );

    Cylinder beam = new Cylinder(0.1f, 0.5f, apRed);  // tenký červený válec
    beam.setPickable(false);

    // přidej paprsek a zvuk do uzlu typu TransformGroup
    beamTG.addChild( beam );
    beamTG.addChild(beamPS);

    // uzel branchGroup uchovávající uzel typu TG
    beamBG = new BranchGroup();
    beamBG.addChild(beamTG);
  }  // konec metody: makeBeam()


  public BranchGroup getBeamBG()
  {  return beamBG;  }



  public void shootBeam(Point3d intercept)
  /* Přesune paprsek s prodlevou mezi jednotlivými pohyby, dokud
     nedosáhne svého cíle. Spustí explozi.
     Volá se ze třídy FireBeam.
  */
  { double travelDist = startPt.distance(intercept);
    calcStepVec(intercept, travelDist);

    beamPS.setEnable(true);         // zapni zvuk laserového paprsku

    double currDist = 0.0;
    currVec.set(startVec);
    beamTG.getTransform(beamT3d);   // získej aktuální transformaci paprsku

    while (currDist <= travelDist) {  // dosud nejsme u cíle
      beamT3d.setTranslation(currVec);  // přesuň laserový paprsek
      beamTG.setTransform(beamT3d);
      currVec.add(stepVec);
      currDist += STEP_SIZE;
      try {
        Thread.sleep(SLEEP_TIME);    // chvíli posečkej
      } 
      catch (Exception ex) {}
    }

    // vynuluj beam to its orignal coordinates
    beamT3d.setTranslation(startVec);
    beamTG.setTransform(beamT3d);

    beamPS.setEnable(false);   // vypnout laser beam sound
  }  // konec metody: shootBeam()



  private void calcStepVec(Point3d intercept, double travelDist)
  /* Vypočítá vektor stepVec pro daný krok pohybu válce od 
     počáteční do cílové pozice.
  */
  { double moveFrac = STEP_SIZE / travelDist;
    double incrX = (intercept.x - startPt.x) * moveFrac;
    double incrY = (intercept.y - startPt.y) * moveFrac;
    double incrZ = (intercept.z - startPt.z) * moveFrac;
    stepVec.set(incrX, incrY, incrZ);  // store as a vector
  } // konec metody: calcStepVec()
  


  public void makeRotation(AxisAngle4d rotAxis)
  // otoč laserový paprsek. Called by ShootingBehaviour.
  {
    beamTG.getTransform( beamT3d );        // získej aktuální transformaci
    // System.out.println("Start beamT3d: " + beamT3d);
    beamT3d.get( currTrans );              // získej aktuální posun
	beamT3d.setTranslation( ORIGIN );      // posuň počátek

	rotT3d.setRotation( rotAxis );         // aplikuj rotaci
    beamT3d.mul(rotT3d);

	beamT3d.setTranslation( currTrans );   // přesuň zpět
    beamTG.setTransform( beamT3d );
    // System.out.println("Konec beamT3d: " + beamT3d);
  } // konec metody: makeRotation()

} // konec třídy: LaserBeam