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


/* Obvyklý svět s šachovnicí a uživatelem řízený 3D-sprite
   (turista), jehož pohyb je animovaný.

   Kamera turisty se pohybuje nad rovinou XZ, nemůže však
   uniknout z šachovnice.

   Nevyskytuje se zde scenérie ani překážky, je však snadné
   vypůjčit si potřebný kód z adresáře Tour3D/.

   Tento soubor je kombinací souborů AnimTour3D.java a WrapAnimTour3D,
   upravených tak, aby používaly výhradní celoobrazovkový režim. Nicméně,
   stále používáme pasivní vykreslování a držíme se retained-módu knihovny
   Java 3D.

   Dále demonstrujeme, jak lze změnit bitovou hloubku pomocí třídy DisplayMode.

   Všechny změny se nacházejí v konstruktoru.
   Jako okno na nejvyšší úrovni používáme AWT-rám.

   Tento program se musí spouštět s parametrem -Dsun.java2d.noddraw=true
   (viz AnimTourFS.bat)

   Více informací o výhradním celoobrazovkovém režimu najdete v tutoriálu Javy:
      <JAVA_HOME>\tutorial\extra\fullscreen\index.html
*/

import java.awt.*;
import java.awt.event.*;
import java.io.*;

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.*;
import com.sun.j3d.utils.image.TextureLoader;



public class AnimTourFS
{
  // 3D-canvas, na němž se zobrazuje načtený obraz
  private GraphicsDevice gd;
  private DisplayMode origDM = null;

  private SimpleUniverse su;
  private BranchGroup sceneBG;
  private BoundingSphere bounds;   // pro uzly prostředí

  private Frame win;   // potřebné při ukončování aplikace



  public AnimTourFS()
  // vytvoří 3D-canvas
  {
    GraphicsConfiguration config =
          SimpleUniverse.getPreferredConfiguration();

    win = new Frame("AnimTourFS", config);   // použij konfiguraci preferovanou třídou SimpleUniverse
    win.setUndecorated(true) ;
	       // bez lišty s menu, okrajů a prvků knihovny Swing
    win.setResizable(false);    // rozměry okna jsou pevně dány


    GraphicsEnvironment ge =
			GraphicsEnvironment.getLocalGraphicsEnvironment();
    gd = ge.getDefaultScreenDevice();
    if (! gd.isFullScreenSupported()) {
      System.out.println("Výhradní celoobrazovkový režim není podporován.") ;
      System.out.println("Device = " + gd) ;
      System.exit(0) ;
    }

    Canvas3D canvas3D = new Canvas3D(config);    // připrav objekt canvas3D
    win.add(canvas3D); 
    canvas3D.setFocusable(true);
    canvas3D.requestFocus();

	canvas3D.addKeyListener( new KeyAdapter() {
	// pro snadné ukončení z celoobrazovkové konfigurace
	// naslouchej klávesám esc, q, end, ctrl-c na herní obrazovce
       public void keyPressed(KeyEvent e)
       { int keyCode = e.getKeyCode();
         if ((keyCode == KeyEvent.VK_ESCAPE) || (keyCode == KeyEvent.VK_Q) ||
             (keyCode == KeyEvent.VK_END) ||
             ((keyCode == KeyEvent.VK_C) && e.isControlDown()) ) {
           if (origDM != null)  // původní byl uložen
             gd.setDisplayMode(origDM);
           gd.setFullScreenWindow(null);  // ukonči celoobrazovkový režim
           win.dispose();
           System.exit(0);  // volání samotné exit() často není dostačující
         }
       }
     });

    gd.setFullScreenWindow(win); // nastav výhradní celoobrazovkový režím
    if (gd.getFullScreenWindow() == null)
      System.out.println("Nemáme výhradní celoobrazovkový režim");
    else
      System.out.println("Máme výhradní celoobrazovkový režim") ;

    // Použij objekt typu DisplayMode ke snížení barevné hloubky z 32 na 16

    if (gd.isDisplayChangeSupported()) {
      origDM = gd.getDisplayMode();    
      gd.setDisplayMode(
           new DisplayMode( origDM.getWidth(), origDM.getHeight(),
                    origDM.getBitDepth()/2,     
                    origDM.getRefreshRate()  ));
    }

    su = new SimpleUniverse(canvas3D);

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


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

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

    addTourist();         // přidej uživatelem ovládaný animovaný 3D-sprite

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



  private void lightScene()
  /* Jedno ambientní světlo, 2 směrová světla */
  {
    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, dolů, dopředu

    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()
  // modrou obhlohu s mraky vytvoříme pomocí škálované textury
  {
    TextureLoader bgTexture = new TextureLoader("models/bigSky.jpg", null);
	Background back = new Background(bgTexture.getImage());
    back.setImageScaleMode(Background.SCALE_FIT_MAX);
    // back.setImageScaleMode(Background.SCALE_REPEAT);   // dlaždicový přístup
    back.setApplicationBounds( bounds );

    sceneBG.addChild( back );
  } // konec metody: addBackground()



  // --------------------- turista ---------------------------


  private void addTourist()
  /*  Turista (bob) je reprezentován několika modely pomocí objektů
      typu AnimSprite3D.

      Vstup klávesnice zachytává objekt typu KeyBehavior a předává jej 
      ke zpracování objektu typu Animator.

      Animator přidává animační sekvenci do animačního rozvrhu.
      Animace je na boba aplikována každých 75 ms, a obvykle sestává
      ze změny pozice a vzhledu.
  */
  { // sprite
    AnimSprite3D bob = new AnimSprite3D();
    bob.setPosition(2.0, 1.0);
    sceneBG.addChild( bob.getTG() );

    // uzel TG pro výhled
    ViewingPlatform vp = su.getViewingPlatform();
    TransformGroup viewerTG = vp.getViewPlatformTransform(); 

    // animátor spritu
    Animator animBeh = new Animator(20, bob, viewerTG); 
    animBeh.setSchedulingBounds( bounds );
    sceneBG.addChild( animBeh );

    // vstupní klávesy spritu
    KeyBehavior kb = new KeyBehavior(animBeh); 
    kb.setSchedulingBounds( bounds );
    sceneBG.addChild( kb );
  } // konec metody: addTourist()


  // -------------------------------------------------

  public static void main(String[] args)
  { new AnimTourFS(); }


} // konec třídy: AnimTourFS



