/*
    This file is part of Mitsuba, a physically based rendering system.

    Copyright (c) 2007-2014 by Wenzel Jakob and others.

    Mitsuba is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License Version 3
    as published by the Free Software Foundation.

    Mitsuba is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once
#if !defined(__MITSUBA_RENDER_EMITTER_H_)
#define __MITSUBA_RENDER_EMITTER_H_

#include <mitsuba/render/common.h>
#include <mitsuba/core/track.h>
#include <mitsuba/core/properties.h>
#include <mitsuba/core/cobject.h>
#include <mitsuba/render/shader.h>
#include <mitsuba/bidir/coherence.h>

MTS_NAMESPACE_BEGIN

/**
 * \brief Abstract radiance/importance emitter interface
 *
 * This class implements an abstract interface to all emitters in Mitsuba. The
 * term emitter is interpreted in a loose bidirectional sense here, where
 * luminaires and sensors are both considered to be emitters of radiance and
 * importance, respectively.
 *
 * Subclasses must implement functions for evaluating and sampling the
 * emission profile and furthermore support querying the probability density
 * of the provided sampling technique.
 *
 * Subclasses must also provide a specialized \a direct sampling method
 * (a generalization of direct illumination sampling to both emitters \a and
 * sensors). A direct sampling is given an arbitrary input position in the
 * scene and in turn returns a sampled emitter position and direction, which
 * has a nonzero contribution towards the provided position. The main idea is
 * that direct sampling reduces the underlying space from 4D to 2D, hence it
 * is often possible to use smarter sampling techniques than in the fully
 * general case.
 *
 * Since the emission profile is defined as function over both positions
 * and directions, there are functions to sample and query \a each of the
 * two components separately. Furthermore, there is a convenience function
 * to sample both at the same time, which is mainly used by unidirectional
 * rendering algorithms that do not need this level of flexibility.
 *
 * One underlying assumption of this interface is that position and
 * direction sampling will happen <em>in sequence</em>. This means that
 * the direction sampling step is allowed to statistically condition on
 * properties of the preceding position sampling step.
 *
 * When rendering scenes involving participating media, it is important
 * to know what medium surrounds the sensors and light sources. For
 * this reason, every emitter instance keeps a reference to a medium
 * (or \c NULL when it is surrounded by vacuum).
 *
 * \ingroup librender
 */
class MTS_EXPORT_RENDER AbstractEmitter : public ConfigurableObject {
public:
    /**
     * \brief Flags used to classify the emission profile of
     * different types of emitters
     */
    enum EEmitterType {
        /// Emission profile contains a Dirac delta term with respect to direction
        EDeltaDirection = 0x01,

        /// Emission profile contains a Dirac delta term with respect to position
        EDeltaPosition  = 0x02,

        /// Is the emitter associated with a surface in the scene?
        EOnSurface      = 0x04
    };

    // =============================================================
    //! @{ \name Sampling interface
    // =============================================================

    /**
     * \brief Importance sample the spatial component of the
     * emission profile.
     *
     * This function takes an uniformly distributed 2D vector
     * and maps it to a position on the surface of the emitter.
     *
     * Some implementations may choose to implement extra functionality
     * based on the value of \c extra: for instance, Sensors
     * (which are a subclass of \ref AbstractEmitter) perform uniform
     * sampling over the entire image plane if <tt>extra == NULL</tt>,
     * but other values, they will restrict sampling to a pixel-sized
     * rectangle with that offset.
     *
     * The default implementation throws an exception.
     *
     * \param pRec
     *    A position record to be populated with the sampled
     *    position and related information
     *
     * \param sample
     *    A uniformly distributed 2D vector (or any value,
     *    when \ref needsPositionSample() == \c false)
     *
     * \param extra
     *    An additional 2D vector provided to the sampling
     *    routine -- its use is implementation-dependent.
     *
     * \return
     *    An importance weight associated with the sampled position.
     *    This accounts for the difference between the spatial part of the
     *    emission profile and the density function.
     */
    virtual Spectrum samplePosition(PositionSamplingRecord &pRec,
        const Point2 &sample, const Point2 *extra = NULL) const;

    /**
     * \brief Conditioned on the spatial component, importance
     * sample the directional part of the emission profile.
     *
     * Some implementations may choose to implement extra functionality
     * based on the value of \c extra: for instance, Sensors
     * (which are a subclass of \ref AbstractEmitter) perform uniform
     * sampling over the entire image plane if <tt>extra == NULL</tt>,
     * but other values, they will restrict sampling to a pixel-sized
     * rectangle with that offset.
     *
     * The default implementation throws an exception.
     *
     * \param dRec
     *    A direction record to be populated with the sampled
     *    direction and related information
     *
     * \param pRec
     *    A position record generated by a preceding call
     *    to \ref samplePosition()
     *
     * \param sample
     *    A uniformly distributed 2D vector (or any value
     *    when \ref needsDirectionSample() == \c false)
     *
     * \return
     *    An importance weight associated with the sampled direction.
     *    This accounts for the difference between the directional part of the
     *    emission profile and the density function.
     */
    virtual Spectrum sampleDirection(
        DirectionSamplingRecord &dRec,
        PositionSamplingRecord &pRec,
        const Point2 &sample,
        const Point2 *extra = NULL) const;

    /**
     * \brief \a Direct sampling: given a reference point in the
     * scene, sample an emitter position that contributes towards it.
     *
     * Given an arbitrary reference point in the scene, this method
     * samples a position on the emitter that has a nonzero contribution
     * towards that point.
     * This can be seen as a generalization of direct illumination sampling
     * so that it works on both luminaires and sensors.
     *
     * Ideally, the implementation should importance sample the product of
     * the emission profile and the geometry term between the reference point
     * and the position on the emitter.
     *
     * The default implementation throws an exception.
     *
     * \param dRec
     *    A direct sampling record that specifies the reference point and
     *    a time value. After the function terminates, it will be
     *    populated with the position sample and related information
     *
     * \param sample
     *    A uniformly distributed 2D vector (or any value
     *    when \ref needsDirectSample() == \c false)
     *
     * \return
     *    An importance weight associated with the sample. Includes
     *    any geometric terms between the emitter and the reference point.
     */
    virtual Spectrum sampleDirect(DirectSamplingRecord &dRec,
            const Point2 &sample) const;

    //! @}
    // =============================================================

    // =============================================================
    //! @{ \name Query functions for the emission profile and
    //!          sampling density functions
    // =============================================================

    /**
     * \brief Evaluate the spatial component of the emission profile
     *
     * \param pRec
     *    A position sampling record, which specifies the query location
     *
     * \return The component of the emission profile that depends on
     * the position (i.e. emitted power per unit area for luminaires and
     * sensor response, or inverse power per unit area for sensors)
     */
    virtual Spectrum evalPosition(const PositionSamplingRecord &pRec) const;

    /**
     * \brief Evaluate the directional component of the emission profile
     *
     * When querying a smooth (i.e. non-degenerate) component, it already
     * multiplies the result by the cosine foreshortening factor with
     * respect to the outgoing direction.
     *
     * \param dRec
     *    A direction sampling record, which specifies the query direction
     *
     * \param pRec
     *    A position sampling record, which specifies the query position
     *
     * \return The component of the emission profile that depends on
     * the direction (having units of 1/steradian)
     */

    virtual Spectrum evalDirection(const DirectionSamplingRecord &dRec,
            const PositionSamplingRecord &pRec) const;

    /**
     * \brief Evaluate the spatial component of the sampling density
     * implemented by the \ref samplePosition() method
     *
     * \param pRec
     *    A position sampling record, which specifies the query location
     *
     * \return
     *    The area density at the supplied position
     */
    virtual Float pdfPosition(const PositionSamplingRecord &pRec) const;

    /**
     * \brief Evaluate the directional component of the sampling density
     * implemented by the \ref sampleDirection() method
     *
     * \param dRec
     *    A direction sampling record, which specifies the query direction
     *
     * \param pRec
     *    A position sampling record, which specifies the query position
     *
     * \return
     *    The directional density at the supplied position
     */

    virtual Float pdfDirection(const DirectionSamplingRecord &dRec,
        const PositionSamplingRecord &pRec) const;

    /**
     * \brief Evaluate the probability density of the \a direct sampling
     * method implemented by the \ref sampleDirect() method.
     *
     * \param dRec
     *    A direct sampling record, which specifies the query
     *    location. Note that this record need not be completely
     *    filled out. The important fields are \c p, \c n, \c ref,
     *    \c dist, \c d, \c measure, and \c uv.
     *
     * \return
     *    The density expressed with respect to the requested measure
     *    (usually \ref ESolidAngle)
     */
    virtual Float pdfDirect(const DirectSamplingRecord &dRec) const;

    //! @}
    // =============================================================

    // =============================================================
    //! @{ \name Other query functions
    // =============================================================

    /**
     * \brief Return a listing of classification flags combined
     * using binary OR.
     *
     * \sa EEmitterType
     */
    inline uint32_t getType() const { return m_type; }

    /// Return the local space to world space transformation
    inline const AnimatedTransform *getWorldTransform() const
            { return m_worldTransform.get(); }

    /// Set the local space to world space transformation
    inline void setWorldTransform(AnimatedTransform *trafo)
            { m_worldTransform = trafo; }

    /**
     * \brief Does the method \ref samplePosition() require a uniformly
     * distributed sample for the spatial component?
     */
    inline bool needsPositionSample() const { return !(m_type & EDeltaPosition); }

    /**
     * \brief Does the method \ref sampleDirection() require a uniformly
     * distributed sample for the direction component?
     */
    inline bool needsDirectionSample() const { return !(m_type & EDeltaDirection); }

    /**
     * \brief Does the emitter lie on some kind of surface?
     */
    inline bool isOnSurface() const { return m_type & EOnSurface; }

    /**
     * \brief Does the sensor have a degenerate directional or spatial
     * distribution?
     */
    inline bool isDegenerate() const { return m_type & (EDeltaPosition | EDeltaDirection); }

    /**
     * \brief Does the method \ref sampleDirect() require a uniformly
     * distributed sample?
     *
     * Since sampleDirect() essentially causes a 2D reduction of the
     * sampling domain, this is the case exactly when the original
     * domain was four-dimensionsional.
     */
    inline bool needsDirectSample() const {
        return needsPositionSample() && needsDirectionSample();
    }

    /**
     * \brief Return the measure associated with the \ref sampleDirect()
     * operation
     */
    inline EMeasure getDirectMeasure() const {
        return needsDirectSample() ? ESolidAngle : EDiscrete;
    }

    //! @}
    // =============================================================

    // =============================================================
    //! @{ \name Miscellaneous
    // =============================================================

    /// Return a pointer to the medium that surrounds the emitter
    inline Medium *getMedium() { return m_medium; }

    /// Return a pointer to the medium that surrounds the emitter (const version)
    inline const Medium *getMedium() const { return m_medium.get(); }

    /// Return the shape, to which the emitter is currently attached
    inline Shape *getShape() { return m_shape; }

    /// Return the shape, to which the emitter is currently attached (const version)
    inline const Shape *getShape() const { return m_shape; }

    /**
     * \brief Create a special shape that represents the emitter
     *
     * Some types of emitters are inherently associated with a surface, yet
     * this surface is not explicitly needed for many kinds of rendering
     * algorithms.
     *
     * An example would be an environment map, where the associated shape
     * is a sphere surrounding the scene. Another example would be a
     * perspective camera with depth of field, where the associated shape
     * is a disk representing the aperture (remember that this class
     * represents emitters in a generalized bidirectional sense, which
     * includes sensors).
     *
     * When this shape is in fact needed by the underlying rendering algorithm,
     * this function can be called to create it. The default implementation
     * simply returns \c NULL.
     *
     * \param scene
     *     A pointer to the associated scene (the created shape is
     *     allowed to depend on it)
     */
    virtual ref<Shape> createShape(const Scene *scene);

    /**
     * \brief Return an axis-aligned box bounding the spatial
     * extents of the emitter
     */
    virtual AABB getAABB() const = 0;

    /// Set the medium that surrounds the emitter
    inline void setMedium(Medium *medium) { m_medium = medium; }

    /// Serialize this emitter to a binary data stream
    virtual void serialize(Stream *stream, InstanceManager *manager) const;

    //! @}
    // =============================================================

    // =============================================================
    //! @{ \name ConfigurableObject interface
    // =============================================================

    /// Add a child ConfigurableObject
    virtual void addChild(const std::string &name, ConfigurableObject *child);

    /// Add an unnamed child
    inline void addChild(ConfigurableObject *child) { addChild("", child); }

    //! @}
    // =============================================================

    MTS_DECLARE_CLASS()
protected:
    /// Construct a new emitter instance
    AbstractEmitter(const Properties &props);

    /// Unserialize a emitter instance from a binary data stream
    AbstractEmitter(Stream *stream, InstanceManager *manager);

    /// Virtual destructor
    virtual ~AbstractEmitter();
protected:
    ref<const AnimatedTransform> m_worldTransform;
    ref<Medium> m_medium;
    Shape *m_shape;
    uint32_t m_type;
};

/**
 * \brief Abstract radiance emitter interface
 *
 * This class provides an abstract interface to all emitter plugins in Mitsuba.
 * It exposes functions for evaluating and sampling the emission profile, and
 * it allows querying the probability density of the sampling method.
 *
 * \ingroup librender
 */
class MTS_EXPORT_RENDER Emitter : public AbstractEmitter, public HWResource {
public:
    /**
     * \brief This list of flags is used to additionally characterize
     * and classify the response functions of different types of sensors
     *
     * \sa AbstractEmitter::EEmitterType
     */
    enum EEmitterFlags {
        /// Is this an environment emitter, such as a HDRI map?
        EEnvironmentEmitter = 0x010
    };

    // =================================================================
    //! @{ \name Additional emitter-related sampling and query functions
    // =================================================================

    /**
     * \brief Return the radiant emittance for the given surface intersection
     *
     * This is function is used when an area light source has been hit by a
     * ray in a path tracing-style integrator, and it subsequently needs to
     * be queried for the emitted radiance along the negative ray direction.
     *
     * It efficiently computes the product of \ref evalPosition()
     * and \ref evalDirection() \a divided by the absolute cosine of the
     * angle between \c d and \c its.shFrame.n.
     *
     * This function is provided here as a fast convenience function for
     * unidirectional rendering techniques. The default implementation
     * throws an exception, which states that the method is not implemented.
     *
     * \param its
     *    An intersect record that specfies the query position
     * \param d
     *    A unit vector, which specifies the query direction
     * \return
     *    The radiant emittance
     */
    virtual Spectrum eval(const Intersection &its, const Vector &d) const;

    /**
     * \brief Importance sample a ray according to the emission profile
     *
     * This function combines both steps of choosing a ray origin and
     * direction value. It does not return any auxiliary sampling
     * information and is mainly meant to be used by unidirectional
     * rendering techniques.
     *
     *
     * Note that this function potentially uses a different sampling
     * strategy compared to the sequence of running \ref sampleArea()
     * and \ref sampleDirection(). The reason for this is that it may
     * be possible to switch to a better technique when sampling both
     * position and direction at the same time.
     *
     * \param ray
     *    A ray data structure to be populated with a position
     *    and direction value
     *
     * \param spatialSample
     *    Denotes the sample that is used to choose the spatial component
     *
     * \param directionalSample
     *    Denotes the sample that is used to choose the directional component
     *
     * \param time
     *    Scene time value to be associated with the sample
     *
     * \return
     *    An importance weight associated with the sampled ray.
     *    This accounts for the difference between the emission profile
     *    and the sampling density function.
     */
    virtual Spectrum sampleRay(Ray &ray,
        const Point2 &spatialSample,
        const Point2 &directionalSample,
        Float time) const;

    //! @}
    // =============================================================

    // =============================================================
    //! @{ \name Miscellaneous
    // =============================================================

    /**
     * \brief Return the luminaire's sampling weight
     *
     * This is used by the luminaire importance sampling
     * routines in \ref Scene.
     */
    inline Float getSamplingWeight() const { return m_samplingWeight; }

    /**
     * \brief Return a bitmap representation of the emitter
     *
     * Some types of light sources (projection lights, environment maps)
     * are closely tied to an underlying bitmap data structure. This function
     * can be used to return this information for various purposes.
     *
     * When the class implementing this interface is a bitmap-backed texture,
     * this function directly returns the underlying bitmap. When it is procedural,
     * a bitmap version must first be generated. In this case, the parameter
     * \ref sizeHint is used to control the target size. The default
     * value <tt>-1, -1</tt> allows the implementation to choose a suitable
     * size by itself.
     *
     * \remark The default implementation throws an exception
     */
    virtual ref<Bitmap> getBitmap(const Vector2i &sizeHint = Vector2i(-1, -1)) const;

    /// Serialize this emitter to a binary data stream
    virtual void serialize(Stream *stream, InstanceManager *manager) const;

    //! @}
    // =============================================================

    // =============================================================
    //! @{ \name Functionality related to environment emitters
    // =============================================================

    /// Is this an environment emitter? (e.g. an HDRI environment map?)
    inline bool isEnvironmentEmitter() const { return m_type & EEnvironmentEmitter; }

    /**
     * \brief Return the radiant emittance from an environment emitter
     *
     * This is function is called by unidirectional rendering techniques
     * (e.g. a path tracer) when no scene object has been intersected, and
     * the scene has been determined to contain an environment emitter.
     *
     * The default implementation throws an exception.
     *
     * \param ray
     *    Specifies the ray direction that should be queried
     */
    virtual Spectrum evalEnvironment(const RayDifferential &ray) const;

    /**
     * \brief Fill out a data record that can be used to query the direct
     * illumination sampling density of an environment emitter.
     *
     * This is function is mainly called by unidirectional rendering
     * techniques (e.g. a path tracer) when no scene object has been
     * intersected, and the (hypothetical) sampling density of the
     * environment emitter needs to be known by a multiple importance
     * sampling technique.
     *
     * The default implementation throws an exception.
     *
     * \param dRec
     *    The direct illumination sampling record to be filled
     *
     * \param ray
     *    Specifies the ray direction that should be queried
     *
     * \return \c true upon success
     */
    virtual bool fillDirectSamplingRecord(
            DirectSamplingRecord &dRec, const Ray &ray) const;

    //! @}
    // =============================================================

    // =============================================================
    //! @{ \name Miscellaneous
    // =============================================================

    /// Is this a compound emitter consisting of several sub-objects?
    virtual bool isCompound() const;

    /**
     * \brief Return a sub-element of a compound emitter.
     *
     * When expanding emitters, the scene will repeatedly call this
     * function with increasing indices. Returning \a NULL indicates
     * that no more are available.
     */
    virtual Emitter *getElement(size_t index);
    
    //! @}
    // =============================================================
    // 

    virtual CoherenceProp sourceLight(const Vector3 &r) const = 0;

    MTS_DECLARE_CLASS()
protected:
    /// Construct a new emitter instance
    Emitter(const Properties &props);

    /// Unserialize a emitter instance from a binary data stream
    Emitter(Stream *stream, InstanceManager *manager);

    /// Virtual destructor
    virtual ~Emitter();
protected:
    Float m_samplingWeight, m_scale;
};

MTS_NAMESPACE_END

#endif /* __MITSUBA_RENDER_EMITTER_H_ */
