/*
    Copyright (C) 2020 - 2022 Akaneyu

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef SYMTEX_PROCESSOR_H_
#define SYMTEX_PROCESSOR_H_

#include <vector>

#if defined(_MSC_VER)
    #define EXPORT __declspec(dllexport)
#else
    #define EXPORT
#endif

extern "C" {

EXPORT int SYMTEX_init(int type);
EXPORT void SYMTEX_free();
EXPORT void SYMTEX_setRegionSize(int width, int height);
EXPORT void SYMTEX_setOrthogonal(int isOrtho);
EXPORT void SYMTEX_setPerspectiveMatrix(float *mat);
EXPORT void SYMTEX_setViewPosition(float *pos);
EXPORT void SYMTEX_setViewDirection(float *dir);
EXPORT void SYMTEX_setVertexCoords(float *coords, int numCoords);
EXPORT void SYMTEX_setVertexNormals(float *normals, int numNormals);
EXPORT void SYMTEX_setVertexIndices(int *indices, int numIndices);
EXPORT void SYMTEX_setUVCoords(float *coords, int numCoords);
EXPORT void SYMTEX_setTriangles(int *indices, int numTriangles);
EXPORT void SYMTEX_setImageSize(int width, int height);
EXPORT void SYMTEX_setImagePixels(float *pixels);
EXPORT void SYMTEX_setMirrorAxis(int axis);
EXPORT void SYMTEX_setBrushSize(float size);
EXPORT void SYMTEX_setBrushStrength(float strength);
EXPORT void SYMTEX_setBrushFalloffType(int type);
EXPORT void SYMTEX_prepare();
EXPORT void SYMTEX_processStroke(float *pos);

}

class Triangle
{
public:
    Triangle();
    Triangle(int *indices);
    virtual ~Triangle();
    int *getIndices() { return m_indices; }

private:
    int m_indices[3];
};

class PixelState
{
public:
    PixelState();
    virtual ~PixelState();
    float *getScreenCoord() { return m_screenCoord; }
    void setScreenCoord(float *coord);
    int *getImageCoord() { return m_imageCoord; }
    void setImageCoord(int *coord);

private:
    float m_screenCoord[4];
    int m_imageCoord[2];
};

// brush position & size
//  3D: screen coordinate, 2D: uv coordinate (0 - 1.0)

class Processor
{
public:
    Processor(int type);
    virtual ~Processor();
    void setRegionSize(int width, int height);
    void setOrthogonal(bool isOrtho) { m_orthogonal = isOrtho; }
    void setPerspectiveMatrix(float *mat);
    void setViewPosition(float *pos);
    void setViewDirection(float *dir);
    void addVertexCoord(float *coord);
    void addVertexNormal(float *norm);
    void addVertexIndex(int index);
    void addUVCoord(float *coord);
    void addTriangle(int *indices);
    void setImageSize(int width, int height);
    void setImagePixels(float *pixels) { m_imagePixels = pixels; }
    void setMirrorAxis(int axis) { m_mirrorAxis = axis; }
    void setBrushSize(float size) { m_brushSize = size; }
    void setBrushStrength(float strength) { m_brushStrength = strength; }
    void setBrushFalloffType(int type) { m_brushFalloffType = type; }
    void prepare();
    void processStroke(float *pos);

private:
    void preparePixel(int x, int y, float *uvCoord,
            float *v1ScrCoord, float *v2ScrCoord, float *v3ScrCoord, float **triUvCoords);
    void processStroke3d(float *pos);
    void processStroke2d(float *pos);
    void processStrokePixel(int x, int y, float falloff);
    float calcBrushFalloff(float dist, float len);
    int m_processType;
    int m_regionWidth;
    int m_regionHeight;
    bool m_orthogonal;
    float m_perspectiveMatrix[16];
    float m_viewPosition[3];
    float m_viewDirection[3];
    std::vector<float *> m_vertexCoords;
    std::vector<float *> m_vertexNormals;
    std::vector<float *> m_screenCoords;
    std::vector<int> m_vertexIndices;
    std::vector<float *> m_uvCoords;
    std::vector<Triangle *> m_triangles;
    std::vector<int> m_vertexStates;
    int m_imageWidth;
    int m_imageHeight;
    float *m_imagePixels;
    float *m_originalImagePixels;
    unsigned short *m_imageAlpha;
    std::vector<PixelState *> m_pixelStates;
    int m_mirrorAxis;
    float m_brushSize;
    float m_brushStrength;
    int m_brushFalloffType;
};

#endif // SYMTEX_PROCESSOR_H_
