// This code example is created for educational purpose
// by Thorsten Thormaehlen (contact: www.thormae.de).
// It is distributed without any warranty.

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.imageio.ImageIO;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.glu.GLU;
import javax.swing.JFrame;

import com.jogamp.opengl.util.FPSAnimator;

class Renderer {

  private GLU glu = new GLU();
  
  public float t = 0.0f;
  private int texID0 = 0;
  private int texID1 = 0;

  public void init(GLAutoDrawable d) {
    GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context
    gl.glEnable(GL2.GL_DEPTH_TEST);
    gl.glEnable(GL2.GL_BLEND);
    gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
    
    texID0 = loadTexture(d, "foreground.png");
    texID1 = loadTexture(d, "background.png");
  }
  
  public void resize(GLAutoDrawable d, int w, int h) {
    GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context
    gl.glViewport(0, 0, w, h);
    gl.glMatrixMode(GL2.GL_PROJECTION);
    gl.glLoadIdentity();
    glu.gluPerspective (30.0, (float)w/(float)h, 0.1, 50.0);
  }
  
  public void display(GLAutoDrawable d) {
    GL2 gl = d.getGL().getGL2();  // get the OpenGL 2 graphics context
    gl.glClearColor(0.8f, 0.8f, 0.8f, 1.0f);
    gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);

    gl.glMatrixMode(GL2.GL_MODELVIEW);
    gl.glLoadIdentity();
    // set camera
    glu.gluLookAt(0.0, 0.0, 8.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0);
    // draw scene
    gl.glPushMatrix();
    gl.glTranslatef(0.0f, -t*0.015f, 0.0f);
    drawTexturedPlaneBackground(d);
    gl.glPopMatrix();
    
    gl.glPushMatrix();
    gl.glRotatef(-t, 0.0f, 0.0f, 1.0f);
    drawTexturedPlaneForeground(d);
    gl.glPopMatrix();
  }

  // returns a valid textureID on success, otherwise 0
  private int loadTexture(GLAutoDrawable d, String filename) {
    GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context
    
    int width;
    int height;
    int level = 0;
    int border = 0;

    try{
      // open file
      FileInputStream  fileInputStream = new FileInputStream(new File(filename));

      // read image
      BufferedImage bufferedImage = ImageIO.read(fileInputStream);
      fileInputStream.close();
      
      width = bufferedImage.getWidth();
      height = bufferedImage.getHeight();

      // convert image to ByteBuffer
      int[] pixelIntData = new int[width * height];
      bufferedImage.getRGB(0, 0, width, height, pixelIntData, 0, width);
      ByteBuffer buffer = ByteBuffer.allocateDirect(pixelIntData.length * 4);
      buffer.order(ByteOrder.nativeOrder());
	  // Unpack the data, each integer into 4 bytes of the ByteBuffer.
	  // Also we need to vertically flip the image because the image origin
	  // in OpenGL is the lower-left corner.
	  for(int y=0; y < height; y++) {
		int k = (height-1-y) * width;
		for(int x=0; x < width; x++) {
			buffer.put((byte)(pixelIntData[k]>>> 16));
			buffer.put((byte)(pixelIntData[k]>>> 8));
			buffer.put((byte)(pixelIntData[k]));
			buffer.put((byte)(pixelIntData[k]>>> 24));
			k++;
		}
      }
      buffer.rewind();

      // data is aligned in byte order
      gl.glPixelStorei(GL2.GL_UNPACK_ALIGNMENT, 1);

      //request textureID
      final int[] textureID = new int[1];
      gl.glGenTextures( 1, textureID, 0);

      // bind texture
      gl.glBindTexture(GL2.GL_TEXTURE_2D, textureID[0]);

      //define how to filter the texture (important but ignore for now)
      gl.glTexParameteri (GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
      gl.glTexParameteri (GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR);

      //texture colors should replace the original color values
      gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_REPLACE); //GL_MODULATE

      // specify the 2D texture map
      gl.glTexImage2D(GL2.GL_TEXTURE_2D, level, GL2.GL_RGBA, width, height, border, GL2.GL_RGBA, GL2.GL_UNSIGNED_BYTE, buffer);

      return textureID[0];
    } catch( FileNotFoundException e) {
      System.out.println("Can not find texture data file " + filename);
    }
    catch(IOException e) {
      e.printStackTrace( );
    }
    return 0;
  }
  
  private void drawTexturedPlaneForeground(GLAutoDrawable d) {
    GL2 gl = d.getGL().getGL2();  // get the OpenGL 2 graphics context
    gl.glEnable(GL2.GL_TEXTURE_2D);
    gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_REPLACE); //GL_MODULATE
    gl.glBindTexture(GL2.GL_TEXTURE_2D, texID0);
    gl.glColor4f(1.0f,0.0f,0.0f,1.0f);
    gl.glBegin(GL2.GL_POLYGON);
    gl.glTexCoord2f(0.05f,0.95f); gl.glVertex3f(-1.0f, 1.0f, 0.1f);
    gl.glTexCoord2f(0.95f,0.95f); gl.glVertex3f(-1.0f,-1.0f, 0.1f);
    gl.glTexCoord2f(0.95f,0.05f); gl.glVertex3f( 1.0f,-1.0f, 0.1f);
    gl.glTexCoord2f(0.05f,0.05f); gl.glVertex3f( 1.0f, 1.0f, 0.1f);
    gl.glEnd();
    gl.glDisable(GL2.GL_TEXTURE_2D);
  }
  
  private void drawTexturedPlaneBackground(GLAutoDrawable d) {
    GL2 gl = d.getGL().getGL2();  // get the OpenGL 2 graphics context
    gl.glEnable(GL2.GL_TEXTURE_2D);
    
    gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_REPLACE); //GL_MODULATE
    gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_REPEAT);
    gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_REPEAT);

    gl.glBindTexture(GL2.GL_TEXTURE_2D, texID1);

    gl.glColor4f(0.0f,1.0f,0.0f,1.0f);
    gl.glBegin(GL2.GL_POLYGON);
    gl.glTexCoord2f(0.00f,1.00f); gl.glVertex3f(-2.0f, 16.0f, 0.0f);
    gl.glTexCoord2f(8.00f,1.00f); gl.glVertex3f(-2.0f,-16.0f, 0.0f);
    gl.glTexCoord2f(8.00f,0.00f); gl.glVertex3f( 2.0f,-16.0f, 0.0f);
    gl.glTexCoord2f(0.00f,0.00f); gl.glVertex3f( 2.0f, 16.0f, 0.0f);
    gl.glEnd();
    gl.glDisable(GL2.GL_TEXTURE_2D);
  }

}

class MyGui extends JFrame implements GLEventListener {

  private Renderer renderer;
  
  public void createGUI() {
    setTitle("Texture Demo");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   
    GLProfile glp = GLProfile.getDefault();
    GLCapabilities caps = new GLCapabilities(glp);
    GLCanvas canvas = new GLCanvas(caps);
    setSize(320, 320);
    
    getContentPane().add(canvas);
    final FPSAnimator ani = new FPSAnimator(canvas, 60, true);
    canvas.addGLEventListener(this);
    setVisible(true);
    renderer = new Renderer();
    
    ani.start();
  }

  @Override
  public void init(GLAutoDrawable d) { 
    renderer.init(d); 
  }

  @Override
  public void reshape(GLAutoDrawable d, int x, int y, int width, int height) {
    renderer.resize(d, width, height);
  }

  @Override
  public void display(GLAutoDrawable d) {
    float offset = 1.0f;
    renderer.t += offset;
    renderer.display(d);
  }

  @Override
  public void dispose(GLAutoDrawable d) { 
  }

}

public class TextureBlend {
  public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        MyGui myGUI = new MyGui();
        myGUI.createGUI();
      }
    });
  }
}
