package engine.object3d;

import engine.geometry.Geometry;
import engine.material.Material;
import engine.opengl.vao.VertexArrayObject;
import engine.opengl.vbo.FloatVertexBufferObject;
import engine.opengl.vbo.ShortVertexBufferObject;
import engine.opengl.vbo.VertexAttributePointer;
import engine.opengl.vbo.VertexBufferObject;
import engine.shader.ShaderProgram;
import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;

import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import static org.lwjgl.opengl.GL20.glDisableVertexAttribArray;

public class Mesh extends Object3d {

    //TODO: check destroy.

    Geometry geometry;
    Material material;

    private VertexArrayObject vao;

    private FloatVertexBufferObject verticesVbo;
    private FloatVertexBufferObject colorsVbo;
    private ShortVertexBufferObject indicesVbo;

    public Mesh(Geometry g, Material m) {
        geometry = g;
        material = m;
        setupBuffers();
    }

    public void disableVertexAttributes() {
        material.getProgram().getAttributeLocations().forEach(location -> glDisableVertexAttribArray(location));
    }

    public Geometry getGeometry() {
        return geometry;
    }

    public Material getMaterial() {
        return material;
    }

    public Matrix4f getModel() {
        return getLocalToWorld();
    }

    private void setupBuffers() {
        float[] vertices = geometry.getVertices();
        float[] colors = geometry.getColors();

        ShaderProgram program = material.getProgram();

        FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(vertices.length);
        verticesBuffer.put(vertices);
        verticesBuffer.flip();
        verticesVbo = new FloatVertexBufferObject(verticesBuffer, VertexBufferObject.BUFFER_TARGET_ARRAY_BUFFER);
        int positionLocation = program.getAttributeLocation(program.positionAttributeName);
        verticesVbo.addVertexAttributePointer(new VertexAttributePointer(
                positionLocation,
                4,
                VertexAttributePointer.DATA_TYPE_FLOAT
        ));

        FloatBuffer colorsBuffer = BufferUtils.createFloatBuffer(colors.length);
        colorsBuffer.put(colors);
        colorsBuffer.flip();
        colorsVbo = new FloatVertexBufferObject(colorsBuffer, VertexBufferObject.BUFFER_TARGET_ARRAY_BUFFER);
        int colorLocation = program.getAttributeLocation(program.colorAttributeName);
        colorsVbo.addVertexAttributePointer(new VertexAttributePointer(
                colorLocation,
                4,
                VertexAttributePointer.DATA_TYPE_FLOAT
        ));


        vao = new VertexArrayObject(geometry.isIndexed());

        vao.setVerticesVbo(verticesVbo);
        vao.setColorsVbo(colorsVbo);

        if (geometry.isIndexed()) {
            short[] indices = geometry.getIndices();
            ShortBuffer indicesBuffer = BufferUtils.createShortBuffer(indices.length);
            indicesBuffer.put(indices);
            indicesBuffer.flip();
            indicesVbo = new ShortVertexBufferObject(indicesBuffer, VertexBufferObject.BUFFER_TARGET_ELEMENT_ARRAY_BUFFER);
            vao.setIndicesVbo(indicesVbo);
        }

        vao.sendVboDataAutoBind();
    }

    public void updateColors() {
        float[] vertices = geometry.getColors();
        FloatBuffer tempBuffer = BufferUtils.createFloatBuffer(vertices.length);
        tempBuffer.put(vertices);
        tempBuffer.flip();

        colorsVbo.setBufferData(tempBuffer);

        vao.bind();
        {
            colorsVbo.sendBufferDataAutoBind();
        }
        vao.unbind();
    }

    public void updateVertices() {
        float[] vertices = geometry.getVertices();
        FloatBuffer tempBuffer = BufferUtils.createFloatBuffer(vertices.length);
        tempBuffer.put(vertices);
        tempBuffer.flip();
        verticesVbo.setBufferData(tempBuffer);

        vao.bind();
        {
            verticesVbo.sendBufferDataAutoBind();
        }
        vao.unbind();
    }

    public VertexArrayObject getVao() {
        return vao;
    }

    public void destroy() {
        deleteVao();
        material.destroyShaderProgram();
    }

    private void deleteVao() {
        vao.bind();
        {
            disableVertexAttributes();
            deleteBuffers();
        }
        vao.unbind();
        vao.delete();
    }

    private void deleteBuffers() {
        verticesVbo.delete();
        colorsVbo.delete();
        if (geometry.isIndexed()) {
            indicesVbo.delete();
        }
    }

}

@@ -610,16 +610,24 @@
 y.%0A%0A    
+private 
 Geometry
@@ -641,16 +641,24 @@
 ry;%0A    
+private 
 Material
@@ -668,17 +668,16 @@
 terial;%0A
-%0A
     priv
@@ -708,153 +708,8 @@
 o;%0A%0A
-    private FloatVertexBufferObject verticesVbo;%0A    private FloatVertexBufferObject colorsVbo;%0A    private ShortVertexBufferObject indicesVbo;%0A%0A
     
@@ -1538,32 +1538,56 @@
 flip();%0A        
+FloatVertexBufferObject 
 verticesVbo = ne
@@ -2107,32 +2107,56 @@
 flip();%0A        
+FloatVertexBufferObject 
 colorsVbo = new 
@@ -2911,32 +2911,56 @@
 ();%0A            
+ShortVertexBufferObject 
 indicesVbo = new
@@ -3192,39 +3192,37 @@
         float%5B%5D 
-vertice
+color
 s = geometry.get
@@ -3286,39 +3286,37 @@
 eateFloatBuffer(
-vertice
+color
 s.length);%0A     
@@ -3325,39 +3325,37 @@
  tempBuffer.put(
-vertice
+color
 s);%0A        temp
@@ -3378,25 +3378,32 @@
         
-c
+vao.getC
 olorsVbo
 .setBuff
@@ -3390,24 +3390,26 @@
 getColorsVbo
+()
 .setBufferDa
@@ -3467,25 +3467,32 @@
         
-c
+vao.getC
 olorsVbo
 .sendBuf
@@ -3479,24 +3479,26 @@
 getColorsVbo
+()
 .sendBufferD
@@ -3771,32 +3771,33 @@
 pBuffer.flip();%0A
+%0A
         vertices
@@ -3781,32 +3781,39 @@
 ip();%0A%0A        v
+ao.getV
 erticesVbo.setBu
@@ -3806,16 +3806,18 @@
 ticesVbo
+()
 .setBuff
@@ -3872,32 +3872,39 @@
  %7B%0A            v
+ao.getV
 erticesVbo.sendB
@@ -3897,16 +3897,18 @@
 ticesVbo
+()
 .sendBuf
@@ -4355,32 +4355,39 @@
 rs() %7B%0A        v
+ao.getV
 erticesVbo.delet
@@ -4376,24 +4376,26 @@
 tVerticesVbo
+()
 .delete();%0A 
@@ -4401,25 +4401,32 @@
         
-c
+vao.getC
 olorsVbo
 .delete(
@@ -4413,24 +4413,26 @@
 getColorsVbo
+()
 .delete();%0A 
@@ -4474,25 +4474,32 @@
             
-i
+vao.getI
 ndicesVbo.de
@@ -4495,16 +4495,18 @@
 dicesVbo
+()
 .delete(

remove extra references to VBO's in mesh.