package com.linkesoft.ctlogocardboard;

import android.graphics.Color;
import android.opengl.*;
import android.util.Log;

import java.nio.*;


public class CTLogo {

    private final String VERTEX_SHADER =
                    "precision mediump float;"		// mittlere Genauigkeit reicht für Berechnungen aus
                    + "uniform mat4 uMVPMatrix;"	// Model-View-Projection-Matrix
                    + "uniform vec3 uLightPos;"	    // Lichtposition

                    + "attribute vec4 aPosition;"	// Vertices
                    + "attribute vec4 aNormal;"		// Normalen
                    + "uniform vec4 uColor;"	    // Grundfarbe

                    + "varying vec4 vColor;"	    // berechnete Farbe für den Fragment Shader

                    + "void main()"
                    + "{"
                    + "   float distance = length(uLightPos - vec3(aPosition));"    // Abstand Lichtquelle - Vertex
                    + "   vec3 lightVector = normalize(uLightPos - vec3(aPosition));"
                    + "   float diffuse = max(dot(vec3(aNormal), lightVector), 0.3);" // Vektorprodukt aus Normale und Lichtvektor bestimmt die Helligkeit, plus etwas Grundhelligkeit
                    + "   diffuse = diffuse * (1.0 / (1.0 + (0.25 * distance * distance)));" // zusätzlicher Einfluss der Entfernung von der Lichtquelle
                    + "   vColor = uColor * diffuse;" // Farbe für den Fragment-Shader: Grundfarbe * Helligkeit
                    + "   gl_Position = uMVPMatrix * aPosition;" // endgültige Position des Vertex
                    + "}";

    private final String FRAGMENT_SHADER =
                    "precision mediump float;"		// mittlere Genauigkeit reicht für Berechnungen aus
                    + "varying vec4 vColor;"		// Farbe vom Vertex-Shader, interpoliert über das Dreieck
                    + "void main()"
                    + "{"
                    + "   gl_FragColor = vColor;"	// Farbe wird unverändert durchgereicht
                    + "}";

    private final FloatBuffer vertexBuffer;
    private final FloatBuffer normalsBuffer;
    // Handles in OpenGL
    private final int aPosition;
    private final int aNormal;
    private final int uColor;
    private final int uLightPos;
    private final int uMVPMatrix;

    // Konstanten
    private static final int COORDS_PER_VERTEX = 3;
    private static final int BYTES_PER_FLOAT=4;
    private static final int vertexCount=CTLogoVertices.ct_logo2NumVerts;

    // Grundfarbe des Logos
    private final int color=Color.GREEN;

    /**
     * OpenGL-Initialisierung
     */
    public CTLogo() {

        Log.i(getClass().getSimpleName(),CTLogoVertices.ct_logo2Verts.length+" vertices, "+CTLogoNormals.ct_logo2Normals.length+" normals");
        vertexBuffer = ByteBuffer.allocateDirect(CTLogoVertices.ct_logo2Verts.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
        vertexBuffer.put(CTLogoVertices.ct_logo2Verts);
        vertexBuffer.position(0);

        normalsBuffer = ByteBuffer.allocateDirect(CTLogoNormals.ct_logo2Normals.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
        normalsBuffer.put(CTLogoNormals.ct_logo2Normals);
        normalsBuffer.position(0);

        // erzeuge Shader und OpenGL-Programm
        int glProgram = GLES20.glCreateProgram();
        // Vertex-Shader
        int vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
        GLES20.glShaderSource(vertexShader, VERTEX_SHADER);
        GLES20.glCompileShader(vertexShader);
        GLES20.glAttachShader(glProgram, vertexShader);
        // Fragment-Shader
        int fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
        GLES20.glShaderSource(fragmentShader, FRAGMENT_SHADER);
        GLES20.glCompileShader(fragmentShader);
        GLES20.glAttachShader(glProgram, fragmentShader);

        GLES20.glLinkProgram(glProgram);
        GLES20.glUseProgram(glProgram);

        // Handles zu OpenGL-Speicherbereichen
        uMVPMatrix = GLES20.glGetUniformLocation(glProgram, "uMVPMatrix");
        uLightPos = GLES20.glGetUniformLocation(glProgram, "uLightPos");

        uColor = GLES20.glGetUniformLocation(glProgram, "uColor");
        aPosition = GLES20.glGetAttribLocation(glProgram, "aPosition");
        aNormal = GLES20.glGetAttribLocation(glProgram, "aNormal");
        GLES20.glEnableVertexAttribArray(aPosition);
        GLES20.glEnableVertexAttribArray(aNormal);

    }

    /**
     * Zeichne einen Frame in OpenGL ES
     *
     * @param mvpMatrix - Model-View-Projection-Matrix
     */
    public void draw(float[] mvpMatrix) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT|GLES20.GL_DEPTH_BUFFER_BIT);
        GLES20.glClearColor(0.1f,0.1f,0.2f,1f); // Hintergrundfarbe
        GLES20.glEnable(GLES20.GL_DEPTH_TEST); // zeichne nur sichtbare Teile

        // Array mit Vertices
        GLES20.glVertexAttribPointer(aPosition, COORDS_PER_VERTEX,GLES20.GL_FLOAT, false,0, vertexBuffer);

        // Array mit Normals
        GLES20.glVertexAttribPointer(aNormal, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false,0, normalsBuffer);

        // Grundfarbe des Logos
        float rgba[]=new float[4];
        rgba[0]= Color.red(color)/255f;
        rgba[1]=Color.green(color)/255f;
        rgba[2]=Color.blue(color)/255f;
        rgba[3]=Color.alpha(color)/255f;
        GLES20.glUniform4fv(uColor, 1, rgba, 0);

        // Lichtposition
        float[] lightPosition = new float[] {0.0f, -1.0f, 0.0f, -5.0f};
        GLES20.glUniform3fv(uLightPos, 1, lightPosition, 0);

        // Model-View-Projection-Matrix
        GLES20.glUniformMatrix4fv(uMVPMatrix, 1, false, mvpMatrix, 0);

        // zeichne das Logo aus vielen einzelnen Dreiecken
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
    }

}
