/* Code from Jensen book typed by courtesy of :
 * 
 * Realistic Indoor Daylight Illumination
 * by Mike Houston and Jonathan Ragan-Kelley
 * CS348B Spring 2002
 * 
 * Changes by ANL:
 * - removed build_map, trace_photon, sample_photon
 * - removed defines of types of photon
 * - changed : float -> real , float x[3] -> R3 x
 */

#ifndef PHOTONMAP_H
#define PHOTONMAP_H

#include "Vec3.h"

#define PACKARDMODE yes

/* This is the photon
 * The power is not compressed so the
 * size is 28 bytes
*/
//**********************
typedef struct Photon
{
//**********************
   R3 pos;                      // photon position
   short plane;                 // splitting plane for kd-tree
   unsigned char theta, phi;    // incoming direction
   R3 power;                    // photon power (uncompressed)
#ifdef PACKARDMODE
   R3 normal;
#endif
}
Photon;

inline void photon_dir(R3 &d, Photon *p)
  {
  d.z = cos(p->theta*(M_PI/256));
  const real rad = sqrt(1-d.z*d.z);
  d.x = cos(p->phi*(2*M_PI/256)) / rad;
  d.y = sin(p->phi*(2*M_PI/256)) / rad;
  }


/* This structure is used only to locate the
 * nearest photons
*/
//******************************
typedef struct NearestPhotons
{
//******************************
   int max;
   int found;
   int got_heap;
   R3 pos;
#ifdef PACKARDMODE
   R3 normal;
#endif
   real *dist2;
   const Photon **index;
}
NearestPhotons;

/* This is the PhotonMap class
 */
//*****************
class PhotonMap
{
//*****************
 public:
   PhotonMap (int max_phot, int type);
    ~PhotonMap ();

   void reInit (int max_phot);  // Only to be used just after constructor
   void Clear();                // anl!!! hope it works 
   
   void store (const R3 power,  // photon power
               const R3 pos,    // photon position
               const R3 dir     // photon direction
#ifdef PACKARDMODE
               , const R3 normal        // surface normal
#endif
      );

   void scale_photon_power (const real scale);  // 1/(number of emitted photons)

   void balance (void);         // balance the kd-tree (before use!)

   void irradiance_estimate (R3 & irrad,        // returned irradiance
                             const R3 pos,      // surface position
                             const R3 normal,   // surface normal at pos
                             const real max_dist,       // max distance to look for photons
                             const int nphotons) const; // number of photons to use
   // Unused old version:
   void irradiance_estimate_all (R3 & irrad,        // returned irradiance
                             const R3 pos,      // surface position
                             const R3 normal,   // surface normal at pos
                             const real max_dist,       // max distance to look for photons
                             const int nphotons) const; // number of photons to use

   void irrad_gradient_estimate (R3 & irrad,    // returned irradiance
//			         R3 & irgrad,   // returned irradiance gradient
                             const R3 pos,      // surface position
                             const R3 normal,   // surface normal at pos
                             const real max_dist,       // max distance to look for photons
                             const int nphotons) const; // number of photons to use
   
   void locate_photons (NearestPhotons * const np,      // np is used to locate the photons
                        const int index) const; // call with index = 1

   void photon_dir (R3 & dir,   // direction of photon (returned)
                    const Photon * p) const;    // the photon

   inline int Count ()
   {
      return stored_photons;
   };                           //ANL

 private:

   void balance_segment (Photon ** pbal,
                         Photon ** porg,
                         const int index, const int start, const int end);

   void median_split (Photon ** p,
                      const int start,
                      const int end, const int median, const int axis);

   Photon *photons;

   int stored_photons;
   int half_stored_photons;
   int max_photons;
   int prev_scale;
   int map_type;

   real costheta[256];
   real sintheta[256];
   real cosphi[256];
   real sinphi[256];

   R3 bbox_min;                 // use bbox_min;
   R3 bbox_max;                 // use bbox_max;
};

#endif // PHOTONMAP_H
