#include <render/integrator.h>
#include <render/scene.h>

struct VolPrimaryEdgeIntegrator
{
    DiscreteDistribution edge_dist;
    std::vector<Vector2i> edge_indices; // [{face_id, edge_id}]
    VolPrimaryEdgeIntegrator(const Scene &scene);
    ArrayXd renderD(SceneAD &sceneAD,
                    RenderOptions &options, const ArrayXd &d_image) const;
    void configure(const Scene &scene);
};

struct VolDirectEdgeIntegrator
{
    DiscreteDistribution edge_dist;
    std::vector<Vector2i> edge_indices; // [{face_id, edge_id}]
    VolDirectEdgeIntegrator(const Scene &scene);
    ArrayXd renderD(SceneAD &sceneAD,
                    RenderOptions &options, const ArrayXd &d_image) const;
    void configure(const Scene &scene);
};

struct VolIndirectEdgeIntegrator
{
    DiscreteDistribution edge_dist;
    std::vector<Vector2i> edge_indices; // [{face_id, edge_id}]
    VolIndirectEdgeIntegrator(const Scene &scene);
    ArrayXd renderD(SceneAD &sceneAD,
                    RenderOptions &options, const ArrayXd &d_image) const;
    void configure(const Scene &scene);
};

struct VolBoundaryIntegrator
{
    VolPrimaryEdgeIntegrator p;
    VolDirectEdgeIntegrator d;
    VolIndirectEdgeIntegrator i;
    VolBoundaryIntegrator(const Scene &scene) : p(scene), d(scene), i(scene) {}
    void configure(const Scene &scene)
    {
        p.configure(scene);
        d.configure(scene);
        i.configure(scene);
    }
    void configure_primary(const Scene &scene)
    {
        p.configure(scene);
    }
    
    ArrayXd renderD(SceneAD &sceneAD,
                    RenderOptions &options, const ArrayXd &d_image) const
    {
        return p.renderD(sceneAD, options, d_image) +
               d.renderD(sceneAD, options, d_image) +
               i.renderD(sceneAD, options, d_image);
    }
};