#include <raylib.h>

#include <cmath>
#include <iterator>
#include <vector>

#include "vmath.h"

int const Cw = 600;
int const Ch = 600;

using vec2 = vmath::vec2<float>;

void PutPixel(int x, int y, Color const &color) {
    DrawPixel(x + Cw / 2, -y + Ch / 2, color);
}

template <typename Iter>
    requires std::output_iterator<Iter, float>
void Interpolate(int i0, float d0, int i1, float d1, Iter out) {
    if (i0 == i1) {
        *out = d0;
        return;
    }

    auto a = (d1 - d0) / (i1 - i0);
    auto d = d0;

    for (int i = i0; i <= i1; ++i) {
        *out++ = d;
        d += a;
    }
}

void DrawLine(vec2 const &p0, vec2 const &p1, Color const &color) {
    auto x0 = p0.x;
    auto y0 = p0.y;
    auto x1 = p1.x;
    auto y1 = p1.y;

    if (std::abs(x1 - x0) > std::abs(y1 - y0)) {
        if (x0 > x1) {
            std::swap(x0, x1);
            std::swap(y0, y1);
        }
        auto i0 = static_cast<int>(std::floor(x0));
        auto i1 = static_cast<int>(std::floor(x1));
        auto ys = std::vector<float>(i1 - i0 + 1);

        Interpolate(i0, y0, i1, y1, ys.begin());

        for (int i = i0; i < i1; ++i) {
            PutPixel(i, ys[i - i0], color);
        }
    } else {
        if (y0 > y1) {
            std::swap(y0, y1);
            std::swap(x0, x1);
        }

        auto i0 = static_cast<int>(std::floor(y0));
        auto i1 = static_cast<int>(std::floor(y1));
        auto xs = std::vector<float>(i1 - i0 + 1);

        Interpolate(i0, x0, i1, x1, xs.begin());

        for (int i = i0; i <= i1; ++i) {
            PutPixel(xs[i - i0], i, color);
        }
    }
}

int main() {
    InitWindow(Cw, Ch, "Shaded Triangles");

    vec2 p0{0, 0};
    vec2 p1{50, 200};
    vec2 p2{0, 0};
    vec2 p3{200, 50};
    vec2 p4{0, 0};
    vec2 p5{0, 200};

    while (!WindowShouldClose()) {
        BeginDrawing();

        ClearBackground(RAYWHITE);

        DrawLine(p0, p1, GREEN);
        DrawLine(p2, p3, BLUE);
        DrawLine(p4, p5, RED);

        EndDrawing();
    }
}