// ===================================================================
// $Id: contrib.h,v 1.5 2003/02/20 18:27:42 havran Exp $
//
// contrib.h
//     Header file for CContribution
//
// Class: CContributionItem, CContributionArray
//
// Licence and usage conditions in November 2003:
// This file can be used and modified only with written permission of
// Vlastimil Havran, Pohodli 27, 57001 Litomysl, the Czech Republic.
// This library is granted to be used by Polina Kondratieva within
// her MPI HIWI job working on BRDFLIB library. The usage condition
// may change in the next version of the library. At the moment,
// the library development is supported by Max-Planck-Institut for
// Informatik, Stuhlsatzenhausweg 85, 66123 Saarbruecken Germany
// See WWW: http://www.mpi-sb.mpg.de
// REPLACEMENT_STRING
//
// Initial coding by Vlastimil Havran, 1999
//
// Given for the use to BRDFLIB project for the Polina Kondratieva's
// HIWI JOB assignment in November 2003.

#ifndef __CONTRIB_H__
#define __CONTRIB_H__

// BRDFLIB library
#include "configh.h"
#include "color.h"
#include "hminfo.h"
#include "ray.h"
#include "vector3.h"

__BEGIN_BRDFLIB_HEADER

// ----------------------------------------------------------------------
// This is the class describing the contribution for a specific
// ray, that is the ray with the energy. The ray type can be specified,
// if needed by rendering algorithm. The energy is given by
// either the W/m^2 or W/m^2/sr or W/sr according to its use.
// The name ? IllumSample,LightSample is also possible ?
// The class might be used for shooting and gathering as well!!!
// ---------------------------------------------------------------------
class CContributionItem
{
public:
  // default constructor
  CContributionItem():
    ray(CVector3D(0), CVector3D(1,0,0), DUMMY_RAY),
    weigth(CValues(CValues::EE_Weigth3)), 
    maxt(-1.0),
    invalid(true),
    prob(0.0),
    flags(EE_Unused),
    interaction(0),
    diffuseness(0.0)
  { }

  // This is the ray corresponding to this Item
  CRay     ray;

  // This is the value for the weigth that can be used anyhow,
  // for example for BRDF and BSDF
  CValues  weigth;

  // This is the maximum distance that the ray should pass from the
  // point on the surface to the light to calculate illumination. This
  // is used by shadow rays starting on the object's surface.
  float    maxt;

  // This flag is set to true when the sample should be disregarded
  // in the final computation (secondary ray does not hit anything,
  // a shadow ray hits an opaque object or angle between the normal of
  // the surface and the shadow ray is greater than PI/2
  bool     invalid;
  
  // This is the probability in the range <0.0, 1.0> that ray should
  // be really shot, it can be used by rendering algorithm
  float    prob;
  
  // The additional flags to be assigned to the item if needed
  // denoting the meaning of the ray
  enum EFlags {
    // This ray has no meaning at all
    EE_Unused  = 0x0,
    // An ideal reflection (from a mirror etc.)
    EE_ReflectedRay = 0x1,
    // An ideal refraction (on glass surface etc.)
    EE_RefractedRay = 0x2,
    // A specular reflection (in Phong model)
    EE_SpecularRay  = 0x4,
    // A diffuse reflection from ideal diffuse surface
    EE_DiffuseRay   = 0x8,
    // A ray shot from a point of illumination to a light
    EE_ShadowRay    = 0x10,
    // An illumination ray shot from a light (emission surface) to a scene
    EE_LightRay     = 0x20
  };

  // any flags allowable for this item usable by rendering algorithm
  int      flags;

  /*
    The type of interaction that took place in order to generate
    this contribution (diffuse/glossy/mirror ref(le|ra)ction).
    It is filled by surface if SpawnRay method family.
  */
  int    interaction;
  // diffuseness of the bounce
  float  diffuseness;
  
  // set the flags for this illumination sample
  void SetFlags(EFlags newFlags) {
    flags = newFlags;
    invalid = (newFlags == EE_Unused);
  }

  // setting of the maximum distance for rays to be further shot to the scene
  void SetMaxT(const float maxT) {
    maxt = maxT;
  }

  // default setting of the flags  
  void Init() {
    invalid = true;
    flags = EE_Unused;
  }
};

// ---------------------------------------------------------------------------
// This is the array of contributions (one contribution = ray with energy)
// ---------------------------------------------------------------------------
class CContributionArray
{
public:
  typedef vector<CContributionItem> TContributionArray;
  
protected:
  // how many items inside the array are used
  int      usedItems;
public:
  // implicit constructor
  CContributionArray():usedItems(0) {}
  // deep copy constructor
  CContributionArray(const CContributionArray &ca):
    usedItems(ca.usedItems), array(ca.array),
    value(ca.value), value2(ca.value2), valuef(ca.valuef),
    hitInfo(ca.hitInfo) { }

  ~CContributionArray() {
    Delete();
  }

  // assignement operator
  CContributionArray& operator=(const CContributionArray &ca) {
    usedItems = ca.usedItems;
    array = ca.array;
    value = ca.value;
    value2 = ca.value2;
    valuef = ca.valuef;
    hitInfo = ca.hitInfo;
    return *this;
  }
  
  // the array of items to be used
  TContributionArray  array;

  // free all the data associated with this array
  void Delete() {
    array.erase(array.begin(), array.end());
  }

  // the number of entries in the array
  int GetUsedItems() const { return usedItems; }

  // Reserve the array to be used easily without allocation
  // until its size reaches 'N'
  void Reserve(int N)
  { array.reserve(N); }
  
  CContributionItem* GetItem(int i) {
    assert((i>=0) && (i<usedItems));
    return &(array[i]);
  }

  CContributionItem* GetLastItem() {
    assert (usedItems > 0);
    return &(array[usedItems-1]);
  }

  // returns the pointer to the next possible contribution item
  CContributionItem* AllocateNext() {
    if (usedItems >= (int)array.size()) {
      CContributionItem ci;
      array.push_back(ci);
    }
    else
      // initialize
      array[usedItems].Init();

    usedItems++;
    return &(array[usedItems - 1]);
  }

  // current contribution item is disregarded - it was found out, that
  // its contribution is zero or small
  void DeleteLastItem() {
    usedItems--;
  }
  
  // the function that resets the contribution array
  void     Reset() {usedItems = 0;}

  // any value that can be used in the rendering application for summing,
  // the weigth of current sample to the final pixel, cumulative sum, etc.
  CValues  value;

  // any value that can be used in the rendering application for
  // various purposes, such as self-radiance, etc.
  CValues  value2;

  // any singular value to be used in the rendering application for
  // summing, cumulative probability value, etc.
  float    valuef;
  
  // the info to be valid for the ray of current contribution item in array.
  CHitPointInfo hitInfo;
};


__END_BRDFLIB_HEADER

#endif // __CONTRIB_H__

