#pragma once
#ifndef SUBDIVISION_H
#define SUBDIVISION_H

#include <QtOpenGL>
#include <QOpenGLFunctions_4_3_Core>

#include "mesh.h"

class Subdivision
{
public:
    Subdivision(QOpenGLFunctions_4_3_Core *f);
    ~Subdivision();

    void init();
    void splitRegular(Mesh *mesh);
    void subdivide(Mesh *mesh, int level);
    void setDebugOutbut(bool debug);

private:
    bool debugOutput;

    struct Input
    {
        GLuint vb_handle;
        QVector<unsigned int> index_buffer;
        QVector<Vertex> vertex_buffer;
    };

    struct Tables
    {
        QVector<GLuint> edge_indices;
        QVector<GLuint> vertex_indices;
        QVector<GLuint> vertex_offsets;
        QVector<GLuint> index_buffer;
        QVector<GLuint> index_regular;
    };

    struct Result
    {
      GLuint vb_handle;
      QVector<Vertex> vertex_buffer;
    };

    struct Patch
    {
        QVector<unsigned int> index_buffer;
        bool is_regular;
    };

    QOpenGLFunctions_4_3_Core *f;
    QOpenGLShaderProgram *edgeShader;
    QOpenGLShaderProgram *vertexShader;

    QOpenGLShaderProgram *initComputeShaderProgram(QString &source);
    Tables precomputeTables(Input input);
    void findRegular(QVector<unsigned int> index_buffer, QVector<Vertex> vertex_buffer, QVector<unsigned int> &regular, QVector<unsigned int> &irregular);
    Result runShader(Input input, Tables &tables);
    void runVertexShader(GLuint size, GLuint vb_handle, GLuint vertex_indices_handle, GLuint vertex_offsets_handle, GLuint output_handle);
    void runEdgeShader(GLuint size, GLuint vb_handle, GLuint edge_indices_handle, GLuint output_handle, GLuint offset);

    //Geht davon aus, dass jeder 3D-Punkt nur einmal im Vertex-Buffer vorkommt!
    QVector<unsigned int> getPatchIndexBuffer(QVector<unsigned int> ib);

    /**
     * @brief matchAndCompleteTriangle if tx ty matches sxsy, sysz or szsy, fill tz with third source vertex index.
     * @param sx source triangle: first vertex
     * @param sy source triangle: second vertex
     * @param sz source triangle: third vertex
     * @param tx target triangle: first known vertex
     * @param ty target triangle: second known vertex
     * @param tz target triangle: unknown vertex.
     * @return true if triangles could be matched and tz was filled.
     */
    bool matchAndCompleteTriangle(unsigned int sx, unsigned int sy, unsigned int sz, unsigned int tx, unsigned int ty, unsigned int& tz);
};

#endif
