/* Bake a texture from pigmentmap+colortheme -> flat texture */

#include <stdio.h>
#include <unistd.h>

#include <algorithm>
#include <iostream>
#include <map>
#include <stdexcept>
#include <string>
#include <vector>

#define cimg_display 0
#define cimg_use_png
#define cimg_use_zlib
#include <CImg.h>
using namespace cimg_library;

template <typename T>
T lerp(T a, T b, float value) {
    return a + (b - a) * value;
}

int main(int argc, char *argv[]) {
    if (argc < 4 || argc > 6) {
        std::cerr << "Usage: " << argv[0] << " pigmentmap colormap outfile [subAmount] [subRow]" << std::endl;
        return 1;
    }

    float subAmount = 1.0;
    if (argc > 4) {
        subAmount = std::stof(argv[4]);
    }

    const CImg<unsigned char> pigments(argv[1]), colors(argv[2]);
    CImg<unsigned char> output(pigments.width(), pigments.height(), 1, 3);

    size_t subY = colors.height() - 1;
    if (argc > 5) {
        subY = std::atoi(argv[5]);
    }

    // colormap channels
    const uint8_t *cR = &colors.atX(0, 0, 0, 0);
    const uint8_t *cG = &colors.atX(0, 0, 0, 1);
    const uint8_t *cB = &colors.atX(0, 0, 0, 2);

    const size_t cW = colors.width(), cH = colors.height();
    const size_t subRow = subY * cW;

    // input iterators
    const unsigned char *inU = &pigments.atX(0, 0, 0, 0);  // U coord
    const unsigned char *inV = &pigments.atX(0, 0, 0, 1);  // V coord
    const unsigned char *inS = &pigments.atX(0, 0, 0, 2);  // Subsurface multiplier

    uint8_t *outR = &output.atX(0, 0, 0, 0);
    uint8_t *outG = &output.atX(0, 0, 0, 1);
    uint8_t *outB = &output.atX(0, 0, 0, 2);

    for (size_t j = 0; j < pigments.height(); j++) {
        fprintf(stderr, "row %ld\r", j);

        for (size_t i = 0; i < pigments.width(); i++) {
            const size_t u = *inU++ * (cW - 1) / 255, v = *inV++ * (cH - 1) / 255;
            const size_t sU = *inS++ * (cW - 1) / 255;

            const size_t pTexel = u + v * cW;
            const uint8_t r = cR[pTexel], g = cG[pTexel], b = cB[pTexel];

            const size_t sTexel = subRow + lerp(cW - 1, sU, 1.0 - subAmount);
            const uint8_t sR = cR[sTexel], sG = cG[sTexel], sB = cB[sTexel];

            *outR++ = r * sR / 255;
            *outG++ = g * sG / 255;
            *outB++ = b * sB / 255;
        }
    }
    fprintf(stderr, "\n");

    output.save(argv[3]);

    return 0;
}