package opengl.tetrahedron1;

import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;

import android.content.Context;
import java.io.IOException;
import android.util.Log;
import android.opengl.GLES20;

public class Tetrahedron 
{
  private static String LOG_APP_TAG = "io_tag";	
  private Context context;
	  
  private String vsCode = null;
  private String fsCode = null;		
  private int program;
  private int vertexShader;
  private int fragmentShader;
  private FloatBuffer vertexBuffer;
  private FloatBuffer colorBuffer[];
  private ShortBuffer indexArray[];
  // number of coordinates per vertex in this array
  static final int COORDS_PER_VERTEX = 3;
  // number of faces in object
  static final int N_FACES = 4;
  // coordinates of tetrahedron vertices
  static float tetraCoords[] = {
    1, 0, -0.707f,  // vertex v0
   -1, 0, -0.707f,  // v1
    0, 1,  0.707f,  // v2
    0, -1, 0.707f   // v3 
  };

  // draw order for each face
  private short drawOrders[][] = {
		 {0, 1, 2},  {0, 2, 3},  {0, 3, 1},  {3, 2, 1}
  };
	
  // color for each face
  static float colors[][] = {
	{1.0f, 0.0f, 0.0f, 1.0f},   // 0,1, 2 red
    {0.0f, 1.0f, 0.0f, 1.0f},   // 0, 2, 3 green
    {0.0f, 0.0f, 1.0f, 1.0f},   // 0, 3, 1 blue
    {1.0f, 1.0f, 0.0f, 1.0f}    // 3, 2, 1 yellow
  };
  
  // Constructor   
  Tetrahedron( Context context0){
    context = context0;
    // get shader codes from res/raw/vshader and res/raw/fshader
    vsCode = getShaderCode( GLES20.GL_VERTEX_SHADER );
    fsCode = getShaderCode( GLES20.GL_FRAGMENT_SHADER );
    program = GLES20.glCreateProgram(); // create empty OpenGL ES Program
    vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vsCode );
    fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fsCode );
    GLES20.glAttachShader ( program, vertexShader ); // add the vertex shader to program    
    GLES20.glAttachShader(program, fragmentShader); // add the fragment shader to program
    GLES20.glLinkProgram(program);                  // creates OpenGL ES program executables
    GLES20.glUseProgram( program);

    // alloocate memory to store tetrahedron vertices
    ByteBuffer bb = ByteBuffer.allocateDirect(tetraCoords.length * 4);
    bb.order(ByteOrder.nativeOrder());
    vertexBuffer = bb.asFloatBuffer();
    vertexBuffer.put(tetraCoords);
    vertexBuffer.position(0);
    // do the same for colors
    colorBuffer = new FloatBuffer[N_FACES];   // a color for each face
    indexArray = new ShortBuffer[N_FACES];    // N_FACES triangles
    for ( int i = 0; i < N_FACES; i++) {
      ByteBuffer bbc = ByteBuffer.allocateDirect( colors[i].length * 4 );
      bbc.order(ByteOrder.nativeOrder());
      colorBuffer[i] = bbc.asFloatBuffer();
      colorBuffer[i].put( colors[i] );
      colorBuffer[i].position(0);
	      
      // initialize byte buffer for each face, 2 bytes per short
      ByteBuffer bbDrawOrder = ByteBuffer.allocateDirect( drawOrders[i].length * 2);
      bbDrawOrder.order(ByteOrder.nativeOrder());
      indexArray[i] = bbDrawOrder.asShortBuffer();
      indexArray[i].put(drawOrders[i]);
      indexArray[i].position(0);
    }

  } // Tetrahedron Constructor
		
  public void draw( float[] mvpMatrix ) {
    // Add program to OpenGL ES environment
  //  GLES20.glUseProgram(program);
    // get handle to shape's transformation matrix
    int mvpMatrixHandle = GLES20.glGetUniformLocation( program, "mvpMatrix");

    // Pass the projection and view transformation to the shader
    GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0);
    // Draw one face at a time   
    for ( int i = 0; i < N_FACES; i++){
      // get handles to shaders' vPosition and  vColor member
      int positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
      int colorHandle = GLES20.glGetUniformLocation(program, "vColor");
      // Enable a handle to the triangle vertices
      GLES20.glEnableVertexAttribArray( positionHandle);
      //  GLES20.glEnableVertexAttribArray( colorHandle );

      // Prepare the triangle coordinate and color data
      int vertexStride = 0;	      
      GLES20.glUniform4fv(colorHandle, 1, colors[i], 0);
      GLES20.glVertexAttribPointer( positionHandle, COORDS_PER_VERTEX,
                        GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
      GLES20.glDrawElements( GLES20.GL_TRIANGLES, drawOrders[i].length,
      GLES20.GL_UNSIGNED_SHORT, indexArray[i] );
      GLES20.glDisableVertexAttribArray(positionHandle);
    }
 }
	    
	    // Get source code of a shader
  protected String getShaderCode( int type )
  {
	 InputStream inputStream = null;
	 String str = null;
	 try {
	   if ( type == GLES20.GL_VERTEX_SHADER )
       inputStream = context.getResources().openRawResource(R.raw.vshader);
	 else
	    inputStream = context.getResources().openRawResource(R.raw.fshader);
        byte[] reader = new byte[inputStream.available()];;
        while (inputStream.read(reader) != -1) {}
        str = new String ( reader );
	 }  catch(IOException e) {
        Log.e(LOG_APP_TAG, e.getMessage());
     }
			 
     return  str;
  }

  public static int loadShader (int type, String shaderCode ) {

    // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
    // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
    int shader = GLES20.glCreateShader(type);

    // add the source code to the shader and compile it
    GLES20.glShaderSource(shader, shaderCode);
    GLES20.glCompileShader(shader);

    return shader;
  }
}