#pragma once
#include <core/ptr.h>
#include <core/fwd.h>
#include <core/object.h>
#include <core/pmf.h>
#include <core/utils.h>

struct ReconstructionFilter : Object
{
    virtual ~ReconstructionFilter() {}
    virtual ReconstructionFilter *clone() const = 0;

    /// Evaluate the filter function
    Float eval(const Vector2 &p, const Float *misc = nullptr) const;
    Float sample(const Vector2 &rnd, Vector2 &p, const Float *misc = nullptr) const;
};

struct TentFilter : public ReconstructionFilter
{
    PSDR_DECLARE_CLASS(TentFilter)

    TentFilter() {}
    TentFilter(Float padding) : m_padding(padding), m_invPadding(1. / padding) {}
    virtual ReconstructionFilter *clone() const override
    {
        return new TentFilter(*this);
    }

    Float eval(const Vector2 &p, const Float *) const;
    Float sample(const Vector2 &rnd, Vector2 &p, const Float *) const;

    Float m_padding;
    Float m_invPadding;

protected:
    Float eval1D(Float x) const;
    Float sample1D(Float rnd, Float &pdf) const;
};

struct BoxFilter : public ReconstructionFilter
{
    PSDR_DECLARE_CLASS(BoxFilter)

    BoxFilter() {}
    virtual ReconstructionFilter *clone() const override
    {
        return new BoxFilter(*this);
    }

    Float eval(const Vector2 &p, const Float *) const;
    Float sample(const Vector2 &rnd, Vector2 &p, const Float *) const;

protected:
    Float eval1D(Float x) const;
    Float sample1D(Float rnd, Float &pdf) const;
};

struct AnisotropicGaussianFilter : public ReconstructionFilter
{
    PSDR_DECLARE_CLASS(AnisotropicGaussianFilter)

    AnisotropicGaussianFilter() {}
    virtual ReconstructionFilter *clone() const override { return new AnisotropicGaussianFilter(*this); }

    Float eval(const Vector2 &p, const Float *) const;
    Float sample(const Vector2 &rnd, Vector2 &p, const Float *) const;
};
