package opengl.tetrahedron;

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

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 ShortBuffer indexArray;
  // number of coordinates per vertex in this array
  static final int COORDS_PER_VERTEX = 3;
  // vertices coordinates of tetrahedron  
  static float tetraCoords[] = {
     1, 0, -0.707f,  -1, 0, -0.707f,
     0, 1,  0.707f,   0, -1, 0.707f    
  };
  // Order of indices of drawing the tetrahedron
  private short drawOrder[] = { 0, 1, 2, 0, 3, 1, 2, 3 };
  // Set color with red, green, blue and alpha (opacity) values
  float color[] = { 0.9f, 0.1f, 0.9f, 1.0f };
		
  // 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);

    ByteBuffer bb = ByteBuffer.allocateDirect(tetraCoords.length * 4);
    bb.order(ByteOrder.nativeOrder());
    vertexBuffer = bb.asFloatBuffer();
    vertexBuffer.put(tetraCoords);
    vertexBuffer.position(0);
    // initialize byte buffer for the draw list
    //   with # of coordinate values * 2 bytes per short
    ByteBuffer bbDrawOrder = ByteBuffer.allocateDirect( drawOrder.length * 2);  
    bbDrawOrder.order(ByteOrder.nativeOrder());
    indexArray = bbDrawOrder.asShortBuffer();
    indexArray.put(drawOrder);
    indexArray.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 i shader
    int mvpMatrixHandle = GLES20.glGetUniformLocation( program, "mvpMatrix");
    // Pass the model-view projection transformation matrix to the shader
	GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0);
	// get handle to vertex shader's vPosition member
	int positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
    // Enable a handle to the triangle vertices
    GLES20.glEnableVertexAttribArray( positionHandle);

    // Prepare the triangles coordinate data
	int vertexStride = 0;
	GLES20.glVertexAttribPointer( positionHandle, COORDS_PER_VERTEX,
	                     GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);

	// get handle to fragment shader's vColor member
	int colorHandle = GLES20.glGetUniformLocation(program, "vColor");
	// Set color for drawing the triangle
    GLES20.glUniform4fv(colorHandle, 1, color, 0);
	// Draw the tetrahedron using lines
    GLES20.glLineWidth(5);
    GLES20.glDrawElements( GLES20.GL_LINE_STRIP, drawOrder.length,
                              GLES20.GL_UNSIGNED_SHORT, indexArray );
     // Disable vertex array
     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;
  }	    
}
