// -------------------------------------------------
// FILE NAME   bigdlight.h
// PURPOSE     Interface with goniodiagram point light
// CREATED     '00.07.01 Rkd (Kirill Dmitriev)
//
// This file is a property of Rkd (Kirill Dmitriev),
// do not change or distribute it without permission
// of Rkd.
// -------------------------------------------------

#ifndef _RKD_BI_GD_LIGHT_H_
#define _RKD_BI_GD_LIGHT_H_

#include <base/str.hpp>
#include <base/file.hpp>


#include <bipointlight/bipointlight.h>


__BEGIN_BRDFLIB_HEADER



class biFMCRTRay;
class biBRTRay;
class biHit;

/// class implements light with goniometric diagram
class BIGLOBAL_API biGDLight : public biPointLight
  {
  /// object creation function
  static biPointer _stdcall Init(void);
  /// static type descriptor
  static biType *st_type;

  protected:
    /// constructor
    biGDLight();
    /// constructor for derived classes
    biGDLight(biType *type);
    /// destructor
    virtual ~biGDLight();

  public:
    /// return static type descriptor
    static biType *getStaticType();

    virtual void FMCRTShootRay(FixtureRef &fixture, QRNG &rng, biFMCRTRay &ray) const;
    virtual void ShadeSampling(biSampler &sampler, biFixture *fixture, biRay &ray, biHit &hit, RGBColor &lum) const;

    virtual void GLApply(biFixture *fixture, int index) const;

    virtual void SetFlux(const double flux);

    /// read GD file
    BOOL ReadGD(const PathStr &file_name);
    /// edit array of theta angle values
    TArray<double> &EditTheta();
    /// edit array of phi angle values
    TArray<double> &EditPhi();
    /// edit goniometric diagram values
    TArray<double> &EditDiagram();
    /// this method must be called after editing of goniometric diagram is finished
    void EditDone();

  private:
    enum { Type_A = 3, Type_B = 2, Type_C = 1 }; ///< type of goniometric diagram (A, B or C)
    ///@{ the data in the *.ies file
    UINT            gonio_type; ///< type of goniometrix diagram (A, B or C)
    int          ies_theta_num; ///< number of theta values
    int            ies_phi_num; ///< number of phi values
    TArray<double>   ies_theta; ///< array of theta angles
    TArray<double>     ies_phi; ///< array of phi angles
    TArray<double> ies_diagram; ///< array of diagram values
    double          multiplier; ///< multiplier
    /// return index in ies_diagram array, given phi and theta indices
    int IES_IND(int itheta, int iphi);
    ///@}

    ///@{ diagram in internal format (most general case of .ies)
    int          theta_num; ///< number of theta values
    int            phi_num; ///< number of phi values
    TArray<double>   theta; ///< array of theta angles
    TArray<double> cos_theta; ///< array of theta cosines (for acceleration)
    TArray<double>     phi; ///< array of phi angles
    TArray<double> diagram; ///< array of diagram values
    /// return index in diagram array, given phi and theta indices
    int IND(int itheta, int iphi);
    ///@}

    double   max_intensity; ///< maximal goniometric diagram intensity

    /// diagram cells with assigned probabilities
    struct CELL
      {
      /// comparison operator
      INLINE BOOL operator < (const double u) const
        { return probab < u; }
      double        probab; ///< cell probability
      double     area_func; ///< some function over the cell area to improve rays shooting speed
      double max_intensity; ///< maximal intensity of the cell (or -maximal intensity if intensity is the same in whole cell)
      };
    /// structure to store one theta line of the diagram
    struct ThetaLine
      {
      /// constructor
      INLINE ThetaLine()  { cells = NULL; }
      /// destructor
      INLINE ~ThetaLine() { delete []cells; }
      /// comparison operator
      INLINE BOOL operator < (const double u) const
        { return probab < u; }
      double        probab; ///< probability to choose this theta line
      CELL          *cells; ///< all cells of this theta line
      };
    TArray<ThetaLine> grid; ///< diagram grid for shooting of rays

    /// read array of double values from .ies file
    BOOL LoadArray(InFile &file, double *array, int num);
    /// convert read iesna representation into internal one, used for rays shooting
    BOOL IesnaToGonio();

  /// callback for numerical solving of area equation for theta angle
  static double area_func(double *data, double x);
  };

INLINE TArray<double> &biGDLight::EditTheta()
  { return theta; }
INLINE TArray<double> &biGDLight::EditPhi()
  { return phi; }
INLINE TArray<double> &biGDLight::EditDiagram()
  { return diagram; }


__END_BRDFLIB_HEADER

#endif
