#include "imageutils.h"

Image3Ref gaussianBlur(const Image3Ref& source, const Vector2int16& direction) {
    debugAssert(source->wrapMode() == WRAP_CLAMP);
    int w = source->width();
    int h = source->height();

    Image3Ref dest = Image3::createEmpty(w, h, source->wrapMode());

    // Generate the filter coefficients
    Array<float> coeff;
    int N = 5;
    float stddev = 2.5f;
    gaussian1D(coeff, N, stddev);

    // Run the blur filter
    for (int y = 0; y < h; ++y) {
        for (int x = 0; x < w; ++x) {
            Color3 sum = Color3::black();
            Vector2int16 pos(x, y);
            for (int t = 0; t < N; ++t) {
                Vector2int16 offset = direction * (t - (N-1)/2);
                sum += source->get(pos + offset, WRAP_CLAMP) * coeff[t];
            }
            dest->set(x, y, sum);
        }
    }

    return dest;
}

/** 
 2D Gaussian blur
 */
Image3Ref gaussianBlur(const Image3Ref& source) {
    static const Vector2int16 HORIZONTAL(1, 0);
    static const Vector2int16 VERTICAL(0, 1);

    return gaussianBlur(gaussianBlur(source, HORIZONTAL), VERTICAL);
}


/**
 Sub-samples by a factor of 2 in each direction.
 */
Image3Ref subsample(const Image3Ref& source) {
    int w = source->width() / 2;
    int h = source->height() / 2;

    Image3Ref dest = Image3::createEmpty(w, h, source->wrapMode());

    for (int y = 0; y < h; ++y) {
        for (int x = 0; x < w; ++x) {
            dest->set(x, y, source->get(x*2, y*2));
        }
    }
    return dest;
}


/**
 Gaussian blurs and then subsamples by a factor of 2.
 */
Image3Ref shrink(const Image3Ref& source) {
    return subsample(gaussianBlur(source));
}

