package com.roxiga.aquamotion3d;

import android.opengl.GLES20;
import android.opengl.Matrix;
import android.util.Log;

public class Scene3D
{
	private static String TAG = "AquaMotion3D";	

	private final String _vertexShader =
        "uniform mat4 u_MVPMatrix;\n" +
        "attribute vec4 a_Position;\n" +
        "attribute float a_Bone;\n" +
        "uniform mat4 u_BoneMatrix[36];\n" +
        "uniform bool u_UseBone;\n" +
        "attribute vec2 a_TextureCoord;\n" +
        "varying vec2 v_TextureCoord;\n" +
        "void main() {\n" +
        "  if ( u_UseBone ){\n" +
        "    int bone = int(a_Bone);\n" +
        "    gl_Position = u_MVPMatrix * u_BoneMatrix[bone] * a_Position;\n" +
        "  } else {\n" +
        "    gl_Position = u_MVPMatrix * a_Position;\n" +
        "  }\n" +
        "  v_TextureCoord = a_TextureCoord;\n" +
        "}\n";

    private final String _fragmentShader =
        "precision mediump float;\n" +
        "varying vec2 v_TextureCoord;\n" +
        "uniform sampler2D s_Texture;\n" +
        "void main() {\n" +
        "  gl_FragColor = texture2D(s_Texture, v_TextureCoord);\n" +
        "}\n";

    public float[] _projMatrix = new float[16];
    public float[] _orthoMatrix = new float[16];
    public float[] _vMatrix = new float[16];

    public int _program;
    public int _uBoneMatrixHandle;
    public int _uMVPMatrixHandle;
    public int _aPositionHandle;
    public int _aBoneHandle;
    public int _aTextureHandle;
    public int _uUseBoneHandle;
    
    public Scene3D()
    {
    }
    
    public void onSurfaceCreated()
    {
    	GLES20.glEnable(GLES20.GL_DEPTH_TEST);
    	GLES20.glFrontFace(GLES20.GL_CCW);
//    	GLES20.glEnable(GLES20.GL_CULL_FACE);

    	_program = createProgram(_vertexShader, _fragmentShader);
    	if (_program == 0)
    	{
    		return;
    	}
    	_aPositionHandle = GLES20.glGetAttribLocation(_program, "a_Position");
    	if (_aPositionHandle == -1)
    	{
    		throw new RuntimeException("Could not get attrib location for a_Position");
    	}
    	_aTextureHandle = GLES20.glGetAttribLocation(_program, "a_TextureCoord");
    	if (_aTextureHandle == -1)
    	{
    		throw new RuntimeException("Could not get attrib location for a_TextureCoord");
    	}
    	_aBoneHandle = GLES20.glGetAttribLocation(_program, "a_Bone");
    	if (_aBoneHandle == -1)
    	{
    		throw new RuntimeException("Could not get attrib location for a_Bone");
    	}

    	_uMVPMatrixHandle = GLES20.glGetUniformLocation(_program, "u_MVPMatrix");
    	if (_uMVPMatrixHandle == -1)
    	{
    		throw new RuntimeException("Could not get uniform location for u_MVPMatrix");
    	}

    	_uBoneMatrixHandle = GLES20.glGetUniformLocation(_program, "u_BoneMatrix");
    	if (_uBoneMatrixHandle == -1)
    	{
    		throw new RuntimeException("Could not get uniform location for u_BoneMatrix");
    	}

    	_uUseBoneHandle = GLES20.glGetUniformLocation(_program, "u_UseBone");
    	if (_uUseBoneHandle == -1)
    	{
    		throw new RuntimeException("Could not get uniform location for u_UseBone");
    	}

    	GLES20.glEnable(GLES20.GL_ALPHA);
    	GLES20.glEnable(GLES20.GL_BLEND);
    	GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
    }

    private int loadShader(int shaderType, String source)
    {
        int shader = GLES20.glCreateShader(shaderType);
        if (shader != 0) {
            GLES20.glShaderSource(shader, source);
            GLES20.glCompileShader(shader);
            int[] compiled = new int[1];
            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
            if (compiled[0] == 0) {
                Log.e(TAG, "Could not compile shader " + shaderType + ":");
                Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
                GLES20.glDeleteShader(shader);
                shader = 0;
            }
        }
        return shader;
    }

    private int createProgram(String vertexSource, String fragmentSource)
    {
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0) {
            return 0;
        }

        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
        if (pixelShader == 0) {
            return 0;
        }

        int program = GLES20.glCreateProgram();
        if (program != 0) {
            GLES20.glAttachShader(program, vertexShader);
            GLES20.glAttachShader(program, pixelShader);
            GLES20.glLinkProgram(program);
            int[] linkStatus = new int[1];
            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
            if (linkStatus[0] != GLES20.GL_TRUE) {
                Log.e(TAG, "Could not link program: ");
                Log.e(TAG, GLES20.glGetProgramInfoLog(program));
                GLES20.glDeleteProgram(program);
                program = 0;
            }
        }
        return program;
    }

    public void perspective(float fov,float aspect,float near,float far)
    {
    	float top = near * (float)Math.tan(fov * Math.PI / 360.0);
		float right = top * aspect;
    	Matrix.frustumM(_projMatrix, 0, -right, right, -top, top, near, far);
	}
}
