
#ifndef POLYGON_H
#define POLYGON_H

#include "linmath.h"

typedef struct {
    vec3 points[3];
    vec3 colors[3];
    vec3 normals[3];

    vec3 barycentrics;
    float baryFactor;

    float dot00;
    float dot01;
    float dot11;
    float v0[2];
    vec2 v1;

    float bounding[4]; // min x, max x, min y, max y

} polygon;

void preCalc(polygon *p) {

    p->v0[0] = p->points[2][0] - p->points[0][0];
    p->v0[1] = p->points[2][1] - p->points[0][1];

    p->v1[0] = p->points[1][0] - p->points[0][0];
    p->v1[1] = p->points[1][1] - p->points[0][1];

    p->dot00 = vec3_dot(p->v0, p->v0);
    p->dot01 = vec3_dot(p->v1, p->v0);
    p->dot11 = vec3_dot(p->v1, p->v1);

    p->baryFactor = 1.0f / (p->dot00 * p->dot11 - p->dot01 * p->dot01);

    p->bounding[0] = p->points[0][0];
    p->bounding[1] = p->points[0][0];
    p->bounding[2] = p->points[0][1];
    p->bounding[3] = p->points[0][1];
    for (int i = 1; i < 3; i++) {
        if (p->bounding[0] > p->points[i][0])
            p->bounding[0] = p->points[i][0];
        if (p->bounding[1] < p->points[i][0])
            p->bounding[1] = p->points[i][0];
        if (p->bounding[2] > p->points[i][1])
            p->bounding[2] = p->points[i][1];
        if (p->bounding[3] < p->points[i][1])
            p->bounding[3] = p->points[i][1];
    }
}

void calcBarycentric(polygon *p, vec3 s) {

    vec2 v2 = {s[0] - p->points[0][0], s[1] - p->points[0][1]};
    float dot02 = vec3_dot(p->v0, v2);
    float dot12 = vec3_dot(p->v1, v2);

    p->barycentrics[0] = (p->dot11 * dot02 - p->dot01 * dot12) * p->baryFactor;
    p->barycentrics[1] = (p->dot00 * dot12 - p->dot01 * dot02) * p->baryFactor;

    p->barycentrics[2] = 1.f - p->barycentrics[1] - p->barycentrics[0];
}
void calcNormal(vec3 d, polygon *p) {
    vec3_scale(d, p->normals[0], p->barycentrics[0]);
    vec3_add_scale(d, p->normals[1], p->barycentrics[1]);
    vec3_add_scale(d, p->normals[2], p->barycentrics[2]);
}

void calcColor(vec3 d, polygon *p) {
    vec3_scale(d, p->colors[0], p->barycentrics[0]);
    vec3_add_scale(d, p->colors[1], p->barycentrics[1]);
    vec3_add_scale(d, p->colors[2], p->barycentrics[2]);
}

float calcDepth(polygon *p) {
    return p->points[0][0] * p->barycentrics[0] +
           p->points[1][0] * p->barycentrics[1] +
           p->points[2][0] * p->barycentrics[2];
}
#endif
