package demo;

import java.awt.event.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
import jocode.*;

/**
 * Render a scene with a skydome and a ground plane.  Use arrow keys to navigate the scene.
 * <P>
 * @see JOCamera.java
 * @see JOCam.java
 * <P>
 * napier at potatoland dot org
 */
public class DemoSkydome extends JOApp {
    // Handles for textures
    int sphereTextureHandle = 0;
    int sphereTextureHandleD = 0;
    int groundTextureHandle = 0;
    int houseTextureHandle = 0;
    // display list for skydome
    int skydomeDL = 0;
    // Light position: if last value is 0, then this describes light direction.  If 1, then light position.
    float lightPosition[]= { -2f, 2f, 2f, 0f };
    // a camera and a cam to move around scene
    JOCamera camera1 = new JOCamera();
    JOCam cam = new JOCam(camera1);
    // SPACE key toggles dusk/daylight
    boolean dusk = false;
    
    /**
     * Initialize application and run main loop.
     */
    public static void main(String args[]) {
    	DemoSkydome demo = new DemoSkydome();
        VSyncEnabled = true;
        fullScreen = false;
        demo.run();  // will call init(), render(), mouse functions
    }
    
    /**
     * Initialise the environment.
     * Called automatically on startup.
     */
    @Override
    public void init(GLAutoDrawable _glDrawable) {
        super.init(_glDrawable);
        
        // init input callbacks
        _glDrawable.addKeyListener(cam);
    }

    /**
     * Initialize the scene.  Called by JOApp.run()
     */
    @Override
    public void setup() {
        // setup and enable perspective
        setPerspective();

        // Create a light (diffuse light, ambient light, position)
        setLight(GL.GL_LIGHT1,
        		 new float[] { .51f, .51f, .51f, 1f },
        		 new float[] { .5f, .5f, .53f, 1f },
        		 new float[] { .1f, .1f, .1f, 1f },
        		 lightPosition);

        // bright light overall
        setAmbientLight(new float[] {1f, 1f, 1f, 1});
        
        // medium bright material
        setMaterial(new float[] {.8f, .8f, .8f, 1}, .5f);
        
        // enable lighting and texture rendering
        gl.glEnable(GL.GL_LIGHTING);
        gl.glEnable(GL.GL_TEXTURE_2D);

        // Enable alpha transparency (so text will have transparent background)
        gl.glEnable(GL.GL_BLEND);
        gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);

        // Create textures
        sphereTextureHandle = makeTexture("images/dayfair_skydome_1.jpg");
        sphereTextureHandleD = makeTexture("images/dayfair_skydome_1_dusk.jpg");
        groundTextureHandle = makeTexture("images/grass_1_512.jpg", true, true);
        houseTextureHandle = makeTexture("images/house_Stirling_House_t.png");

        // set camera 1 position
        camera1.setCamera(0, 25, 130,   // position of camera 
        		          -.1f, 0, -1,  // direction camera is pointing NOT TARGET POSITION (different from gluLookAt()!)
        		          0, 1, 0);     // UP direction of camera
        
        // a little haze
        setFog(new float[] {.5f,.5f,.5f,1f}, .001f);
        
        // make the skydome display list
        makeSkyDome();
    }
    
    public void makeSkyDome() {
        GLUquadric s = glu.gluNewQuadric();
        glu.gluQuadricOrientation(s, GLU.GLU_INSIDE);  // normals point inwards
        glu.gluQuadricTexture(s, true);
        skydomeDL = beginDisplayList();
    	{
    	    gl.glDisable(GL.GL_LIGHTING);
    	    gl.glDisable(GL.GL_DEPTH_TEST);
    	    gl.glColor4f(.62f, .62f, .626f, 1);
    	    gl.glPushMatrix();
    		{
    		    gl.glRotatef(90f, 1, 0, 0);   // rotate the sphere to align the axis vertically
    		    gl.glScalef(200, 200, 200);
    		    glu.gluSphere(s, 1, 48, 48);  // run GL commands to draw sphere
    		}
    		gl.glPopMatrix();
    		gl.glEnable(GL.GL_LIGHTING);
    		gl.glEnable(GL.GL_DEPTH_TEST);
    	}
    	endDisplayList();
    }
    
    /**
     * Move the skydome so it is always centered at the camera position. Switch
     * dome textures between day and dusk.
     */
    public void renderDome() {
	    gl.glPushMatrix();
		{
		    gl.glTranslatef(camera1.position.x, camera1.position.y, camera1.position.z);
	        gl.glBindTexture(GL.GL_TEXTURE_2D, dusk? sphereTextureHandleD : sphereTextureHandle);
	    	callDisplayList(skydomeDL);
		}
		gl.glPopMatrix();
    }

    public void renderHouse() {
        // draw the house on a plane
        gl.glPushMatrix();
        {
            gl.glTranslatef(0f, 70f, 0f);
            gl.glBindTexture(GL.GL_TEXTURE_2D, houseTextureHandle);
            renderPlane(150, 150, 10, 10);
        }
        gl.glPopMatrix();
    }

    public void renderGround() {
        // draw the ground plane
        gl.glPushMatrix();
        {
            gl.glRotatef(-90, 1, 0, 0);
            gl.glBindTexture(GL.GL_TEXTURE_2D, groundTextureHandle);
            renderPlane(1000, 1000, 100, 100, 40, 40);
        }
        gl.glPopMatrix();
    }

    /**
     * set the field of view and view depth.
     */
    public void setPerspective() {
    	setPerspective(50f, .1f, 5000f);
    }

    /**
     * Render one frame.  Called by JOApp.run().
     */
    @Override
    public void draw() {
        // user keystrokes adjust camera position    	
        cam.handleNavKeys(getSecondsPerFrame());

        // clear depth buffer and color
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        // select model view for subsequent transforms
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();

        // do gluLookAt() with camera position, direction, orientation
        cam.render();

        // draw the sky
        renderDome();
        
        // draw the ground plane
        gl.glPushMatrix();
        {
            gl.glTranslatef(0f, -3f, 0f); // down a bit
            renderGround();
        }
        gl.glPopMatrix();
        
        // draw house
        gl.glPushMatrix();
        {
            gl.glTranslatef(0f, 0f, -50f);
            renderHouse();
        }
        gl.glPopMatrix();

        // Place the light.  Light will stay in sync with the rest of the scene
        setLightPosition(GL.GL_LIGHT1, lightPosition);

		// render some text using texture-mapped font
        print(30, viewportH- 80, "Left-Right arrows rotate camera", 1);
        print(30, viewportH-100, "Up-Down arrows move camera forward and back", 1);
        print(30, viewportH-120, "SPACE toggles dusk/daylight", 1);
        print(30, viewportH-140, "A W S D keys tilt and pan the camera", 1);
    }

    @Override
    public void keyPressed(KeyEvent _event) {
        super.keyPressed(_event);
    	
        if (_event.getKeyCode() == KeyEvent.VK_SPACE) {
    		dusk = !dusk;
    		if (dusk) {
    			setAmbientLight(new float[] {.1f, .1f, .1f, 1});
    		}
    		else {
    	        setAmbientLight(new float[] {1f, 1f, 1f, 1});
    		}
    	}
    }
}