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

/* Na pozadí obvyklého šachovnicového světa demonstruje, jak lze vytvořit 
   lathe-tvary. Podívejte se na příklady v metodě addLatheShapes() na konci
   tohoto souboru.
*/


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



public class WrapLathe3D 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,7,20);
    // počáteční pozice uživatele

  private static final Color3f white = new Color3f(1.0f, 1.0f, 1.0f);

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


  public WrapLathe3D()
  // Panel uchovávající 3D-canvas: obvyklý způsob propojení knihoven Java 3D a Swing
  {
    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);

    createSceneGraph();
    initUserPosition();        // nastav stanoviště pozorovatele

    orbitControls(canvas3D);   // ovládací prvky pro pohyb tohoto stanoviště
    
    su.addBranchGraph( sceneBG );
  } // konec metody: WrapLathe3D()



  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

    addLatheShapes();

    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()



  private void orbitControls(Canvas3D c)
  /* Objekt typu OrbitBehaviour umožňuje uživateli otáčet, připližovat a oddalovat 
     výhled na 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()


  // ---------------------- tvary -----------------

  private void addLatheShapes()
  // řada příkladů použití instancí třídy LatheShape3D (a jejích podtříd)
  {
    // použij výchozí barvy (růžovou, temně růžovou)
    double xsIn1[] = {0, 1, 0};
    double ysIn1[] = {0, 1.5, 2.5};
    LatheShape3D ls1 = new LatheShape3D( xsIn1, ysIn1, null);  // velký růžový balón
    displayLathe(ls1, -7.0f, -5.0f, "egg");


    // --------------------- načtení textur  -------------
    System.out.println("Načítám R texturu");
    TextureLoader texLd1 = new TextureLoader("textures/r.gif", null);
	Texture rTex = texLd1.getTexture();

    System.out.println("Načítám texturu kůže");
    TextureLoader texLd2 = new TextureLoader("textures/skin.jpg", null);
	Texture skinTex = texLd2.getTexture();

    System.out.println("Načítám texturu vody");
    TextureLoader texLd3 = new TextureLoader("textures/water.jpg", null);
	Texture waterTex = texLd3.getTexture();

    System.out.println("Načítám texturu kovového plátu");
    TextureLoader texLd4 = new TextureLoader("textures/plate.jpg", null);
	Texture plateTex = texLd4.getTexture();

    System.out.println("Načítám cihličkovou texture");
    TextureLoader texLd5 = new TextureLoader("textures/brick.gif", null);
	Texture brickTex = texLd5.getTexture();

    System.out.println("Načítám lávovou texture");
    TextureLoader texLd6 = new TextureLoader("textures/lava.jpg", null);
	Texture lavaTex = texLd6.getTexture();

    System.out.println("Načítám texturu oblohy");
    TextureLoader texLd7 = new TextureLoader("textures/sky.jpg", null);
	Texture skyTex = texLd7.getTexture();

    System.out.println("Načítám texturu dlažebních kostek");
    TextureLoader texLd8 = new TextureLoader("textures/cobbles.jpg", null);
	Texture cobblesTex = texLd8.getTexture();
  
    System.out.println("Načítám texturu kůry");
    TextureLoader texLd9 = new TextureLoader("textures/bark1.jpg", null);
	Texture barkTex = texLd9.getTexture();

    System.out.println("Načítám texturu víření");
    TextureLoader texLd10 = new TextureLoader("textures/swirled.jpg", null);
	Texture swirledTex = texLd10.getTexture();

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

    // křivky a textura
    double xsIn15[] = {0, 0.1, 0.7, 0};
    double ysIn15[] = {0, 0.1, 1.5, 2};
    LatheShape3D ls2 = new LatheShape3D( xsIn15, ysIn15, waterTex);
    displayLathe(ls2, -3.5f, -5.0f, "drip");


    // smíchej úsečky, křivky a textury
    double xsIn2[] = {-0.001, -0.7, -0.25, 0.25, 0.7, -0.6, -0.5};   // uses -ve coords
    double ysIn2[] = {0, 0, 0.5, 1, 2.5, 3, 3};
    LatheShape3D ls3 = new LatheShape3D( xsIn2, ysIn2, swirledTex);
    displayLathe(ls3, -1.0f, -5.0f, "cup");

    // končetina s texturou kůže
    double xsIn25[] = {0, 0.4, 0.6, 0};
    double ysIn25[] = {0, 0.4, 2.2, 3};
    LatheShape3D ls4 = new LatheShape3D( xsIn25, ysIn25, skinTex);
    displayLathe(ls4, 3.0f, -5.0f, "limb");


    // nejrůznější rotační tvary vytvořené pomocí podtříd
    double xsIn3[] = {-1, -1};
    double ysIn3[] = {0, 1};
    LatheShape3D ls5 = new LatheShape3D( xsIn3, ysIn3, rTex);   // kruhový
    displayLathe(ls5, 6.0f, -5.0f, "round R");

    EllipseShape3D ls6 = new EllipseShape3D( xsIn3, ysIn3, rTex);  // eliptický
    displayLathe(ls6, 6.0f, 0, "oval R");

    RhodoneaShape3D ls7 = new RhodoneaShape3D( xsIn3, ysIn3, null);  // růžicový
    displayLathe(ls7, 3.0f, 0, "flower");


    double xsIn4[] = {-0.001, -0.4, -0.2, 0.2, 0.3, -0.2, -0.3, -0.001}; 
    double ysIn4[] = {0, 0, 1, 1.2, 1.4, 1.6, 1.8, 1.8};
    LatheShape3D ls8 = new LatheShape3D( xsIn4, ysIn4, skyTex);
    displayLathe(ls8, -1.0f, 0, "chess");

    // všechny úsečky používají -0.001 pro zacházejí čáry od 0
    double xsIn5[] = {-0.001, -0.4, -0.15, -0.001};
    double ysIn5[] = {0, 0, 3, 3};
    LatheShape3D ls9 = new LatheShape3D( xsIn5, ysIn5, barkTex);
    displayLathe(ls9, -3.5f, 0, "branch");

    // rotovaný kruh: torus
    double xsIn6[] = {1, 1.5, 1, 0.5, 1};
    double ysIn6[] = {0, 0.5, 1, 0.5, 0};
    LatheShape3D ls10 = new LatheShape3D( xsIn6, ysIn6, lavaTex);
    displayLathe(ls10, -7.0f, 0, "torus");

    double xsIn7[] = {0, 0.4, -0.1, 0.1, 0.4, 0};
    double ysIn7[] = {0, 0.4, 0.8, 1.2, 1.6, 2};
    LatheShape3D ls11 = new LatheShape3D( xsIn7, ysIn7, cobblesTex);
    displayLathe(ls11, -3.5f, 5.0f, "dumbbell");

    double xsIn8[] = {-0.01, 1, 0};
    double ysIn8[] = {0, 0, 1};
    LatheShape3D ls12 = new LatheShape3D( xsIn8, ysIn8, brickTex);
    displayLathe(ls12, -1.0f, 5.0f, "dome");

    double xsIn9[] = {-0.01, 0.5, -1, -1.2, 1.4, -0.5, -0.5, 0};
    double ysIn9[] = {0, 0, 1.5, 1.5, 2, 2.5, 2.7, 2.7};
    EllipseShape3D ls13 = new EllipseShape3D( xsIn9, ysIn9, plateTex);  // elliptic
    displayLathe(ls13, 3.0f, 5.0f, "armour");

    // použij barvy
    Color3f brown = new Color3f( 0.3f, 0.2f, 0.0f);
    Color3f darkBrown = new Color3f(0.15f, 0.1f, 0.0f);
    double xsIn10[] = {0, 0.75, 0.9, 0.75, 0};
    double ysIn10[] = {0, 0.23, 0.38, 0.53, 0.75};
    LatheShape3D ls14 = new LatheShape3D( xsIn10, ysIn10, darkBrown, brown);
    displayLathe(ls14, 6.0f, 5.0f, "saucer");

  }  // konec metody: addLatheShapes()


  private void displayLathe(LatheShape3D ls, float x, float z, String label)
  {
    // umísti objekt typu LatheShape3D
    Transform3D t3d = new Transform3D();
    t3d.set( new Vector3f(x,1.5f,z)); 
    TransformGroup tg1 = new TransformGroup(t3d);

    tg1.addChild( ls ); 
    sceneBG.addChild(tg1);

    // umísti označení tvaru
    Text2D message = new Text2D(label, white, "SansSerif", 72, Font.BOLD );
       // Sans Serif, 72 bodů, tučně 
    t3d.set( new Vector3f(x-0.4f,0.75f,z) );
    TransformGroup tg2 = new TransformGroup(t3d);
    tg2.addChild(message);
    sceneBG.addChild(tg2);
  }  // konec metody: displayLathe()


} // konec třídy: WrapLathe3D