package com.example.opengles3;

import android.opengl.GLES30;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;

public class Stozac {
    private FloatBuffer vertexBuffer;
    float a = 0.5f;
    int n;
    private int lokacijaMatrice;
    private int lokacijaBoje;
    float vrhovi[];
    private float color[] = new float[] {0.3f, 0.3f, 0.3f, 1};
    private final String vertexShaderCode =
            "#version 300 es\n" +
                    "      in vec4 a_position;\n" +
                    "      in vec3 a_normal;\n" +
                    "      in vec4 v_boja;\n" +
                    "      out vec4 f_boja;\n" +
                    "      uniform mat4 matrica;\n" +
                    "      uniform vec3 izvor;\n" +
                    "      out float svjetlina;"+
                    "\n" +
                    "      void main() {\n" +
                    "        vec4 vrh = matrica * a_position;"+
                    "        vec3 normala = mat3(matrica) * a_normal;"+

                    "// Lambertov zakon\n" +
                    "        vec3 premaIzvoru = normalize(izvor - vec3(vrh));\n" +
                    "        svjetlina = dot(premaIzvoru, normala);\n" +
                    "\n" +
                    "        // zakon refleksije\n" +
                    "        float refleksija = 0.0;\n" +
                    "        if(svjetlina > 0.0) {\n" +
                    "          vec3 premaKameri = normalize(vec3(0, 5, -12) - vec3(vrh));\n" +
                    "          vec3 reflektiranaZraka = reflect(-premaIzvoru, normala);\n" +
                    "          refleksija = max(dot(reflektiranaZraka, premaKameri), 0.0);\n" +
                    "          refleksija = pow(refleksija, 2.0);\n" +
                    "        }\n" +
                    "\n" +
                    "        svjetlina = svjetlina * 0.68 + refleksija * 0.02+0.3;"+

                    "        f_boja = normalize(a_position+v_boja)*0.7;\n" +
                    "        gl_Position = vrh; // primijeni matricu transformacije\n" +
                    "      }";
    private final String fragmentShaderCode =
            "#version 300 es\n" +
                    "      precision mediump float;\n" +
                    "      in vec4 f_boja;\n" +
                    "      in float svjetlina;"+
                    "      out vec4 bojaPiksela;\n" +
                    "\n" +
                    "      void main() {\n" +
                    "        bojaPiksela = f_boja*svjetlina; \n" +
                    "      }";
    private int shaderProgram;
    public static int loadShader(int type, String shaderCode){
        int shader = GLES30.glCreateShader(type);
        GLES30.glShaderSource(shader, shaderCode);
        GLES30.glCompileShader(shader);
        return shader;
    }

    public Stozac(float radius, float visina, int _n){
        n=_n;
        ArrayList<Float> pos=new ArrayList<>();
        pos.add(0.0f);
        pos.add(visina);
        pos.add(0.0f);        //Increase the height of the center of the circle relative to the edge to form a cone
        pos.add(0.0f);
        pos.add(-0.01f);
        pos.add(0.0f);
        float angDegSpan=360f/n;
        for(float i=0;i<360+angDegSpan;i+=angDegSpan){
            pos.add((float) (radius*Math.sin(i*Math.PI/180f)));
            pos.add(0.0f);
            pos.add((float)(radius*Math.cos(i*Math.PI/180f)));
            pos.add((float) (Math.sin(i*Math.PI/180f)));
            pos.add(0.3f);// ovo bi trebalo nekako preciznije izracunati
            pos.add((float)(Math.cos(i*Math.PI/180f)));
        }
        vrhovi = new float[pos.size()];    //All vertices
        for (int i=0;i<vrhovi.length;i++){
            vrhovi[i]=pos.get(i);
        }

        ByteBuffer bb = ByteBuffer.allocateDirect(vrhovi.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(vrhovi);
        vertexBuffer.position(0);
        int vertexShader = loadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode);
        shaderProgram = GLES30.glCreateProgram();
        GLES30.glAttachShader(shaderProgram, vertexShader);
        GLES30.glAttachShader(shaderProgram, fragmentShader);

        // Bind vPosition to attribute 0
        GLES30.glBindAttribLocation(shaderProgram, 0, "a_position");
        GLES30.glLinkProgram(shaderProgram);

        int[] linkStatus = new int[1];
        GLES30.glGetProgramiv(shaderProgram, GLES30.GL_LINK_STATUS, linkStatus, 0);
        if (linkStatus[0] != GLES30.GL_TRUE) {
            GLES30.glDeleteProgram(shaderProgram);
            throw new RuntimeException("Could not link shader program: "
                    + GLES30.glGetProgramInfoLog(shaderProgram));
        }
    }

    public void draw(float[] matrica) {

        GLES30.glUseProgram(shaderProgram);
        lokacijaMatrice = GLES30.glGetUniformLocation(shaderProgram, "matrica");
        lokacijaBoje = GLES30.glGetAttribLocation(shaderProgram, "v_boja");
        int lokacijaIzvora = GLES30.glGetUniformLocation(shaderProgram, "izvor");

        GLES30.glUniformMatrix4fv(lokacijaMatrice, 1, false, matrica, 0);

        GLES30.glUniform3f(lokacijaIzvora,-10, 6, -10);

        int VERTEX_POS_INDX = 0;
        vertexBuffer.position(VERTEX_POS_INDX);
        int VERTEX_NORMAL_INDX = GLES30.glGetAttribLocation(shaderProgram, "a_normal");

        GLES30.glVertexAttribPointer(VERTEX_POS_INDX, 3, GLES30.GL_FLOAT,
                false, 24, vertexBuffer);
        GLES30.glVertexAttribPointer(VERTEX_NORMAL_INDX, 3, GLES30.GL_FLOAT,
                false, 24, vertexBuffer);
        GLES30.glEnableVertexAttribArray(VERTEX_POS_INDX);
        GLES30.glEnableVertexAttribArray(VERTEX_NORMAL_INDX);


        //CRTANJE Stozca
        GLES30.glVertexAttrib3fv(lokacijaBoje, color, 0);
        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, n+2);

    }
}
