// ===================================================================
// $Id: texture.h,v 1.8 2003/06/17 08:44:15 havran Exp $
//
// texture.h
//     Header file for CTexture class hierarchy.
//
// Class: CTextureList, CTexture, CConstantTexture
//
// 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 + Petr Mladek + Jiri Liska, 1999
//
// Given for the use to BRDFLIB project for the Polina Kondratieva's
// HIWI JOB assignment in November 2003.


#ifndef __TEXTURE_H__
#define __TEXTURE_H__

// BRDFLIB headers
#include "configh.h"
#include "color.h"
#include "mappibas.h"

// standard headers
#include <vector>


__BEGIN_BRDFLIB_HEADER

// forward declarations
class CMapPointInfo;
class CTexture;

// ----------------------------------------------------------------
// CTextureList
//  List of textures; derives from CSimpleList and adds a function
//  to search for a given color and return nonzero if there.
// ----------------------------------------------------------------
class CTextureList:
  public vector<CTexture *>
{
public:
  // returns true, if the texture is already present in the list
  bool TextureThere(CTexture *probe);
};

// --------------------------------------------------------------------------
// This is general class for textures
// most important is metod GetValue which comes in for the mapInfo and 
// returns appropriate value
// --------------------------------------------------------------------------
class CTexture 
{
public:
  // this identifikator allows to identify real class of the object CImage *
  // 0x01xxxx classes which calculate mapInfo on the texture value
  // 0x02xxxx classes which operate with the value from the one texture
  // 0x04xxxx classes which operate with the values from the two textures
  // 0x08xxxx classes which operate with the values from many textures
  // 0x10xxxx classes which change mapInfo
  enum EClassId {
    // unknown, not recognized texture
    EE_UnknownTexture = 0,
    
    // classes which calculate mapInfo on the texture value
    EE_ConstantTexture = 0x010000,
    EE_GeneralImageTexture,
    EE_InterpolatedTexture,
    EE_MipMapTexture,
    EE_NearestNeighbourTexture,
    EE_RipMapTexture,
    EE_SummedAreaTexture,
  };

private:
  // these must not be used
  CTexture & operator=(const CTexture &texture);
  // copy constructor
  CTexture(const CTexture &);
protected:
  // if the type (dimensionality) of the texture is static then is true
  // by other words if the demand on the dimensionality of the mapping 
  // is static then this variable is true
  bool _isTypeStatic;  
public:
  // constructor
  CTexture(bool isTypeStatic = true) : _isTypeStatic(isTypeStatic) { }

  // explicitely virtual destructor
  virtual ~CTexture() { }

  // returns the type (dimensionality) of the texture (2D,3D, ...). 
  // It corresponds to the mapping that has to be performed to access the data 
  // from this texture. So the dimensionality of mapping performed has to be
  // larger or greater than the dimensionality of this texture.
  virtual CMappingBase::EDimType GetType() const = 0;

  // returns true if the type of the texture is static 
  // by other words it returns true if the demand on the dimensionality 
  // of the mapping is static 
  bool IsTypeStatic() const { return _isTypeStatic; }

  // returns identification of the class
  virtual EClassId GetClassId() const = 0;

  // returns one value for specifed mapInfo
  virtual void GetValue(CValues &value, const CMapPointInfo &mapInfo) = 0;

  // Returns one value for specifed array of mapInfos.
  // The class mapInfos defines area instead of only one point.
  // This function can better solve antialiasing.
  virtual void GetValue(CValues &value, const CMapPointInfo mapInfo[],
			int number) = 0;

  // Describes the texture to a given stream
  virtual void Describe(ostream &app, int ind, float multiplier = 1.0) const {
    indent(app, ind); multiplier = multiplier; app << "Not yet implemented";
  }
};

// --------------------------------------------------------------------------
// this is class for constant texture, this texture needn't mapping
// --------------------------------------------------------------------------
class CConstantTexture:
  public CTexture
{
public:
  // constructor
  CConstantTexture(CValues &value):
    CTexture(), _value(value) { }

  CConstantTexture(const CConstantTexture &masterTexture):
    CTexture(),
    _value(masterTexture._value) { }

  // returns the type (dimensionality) of the texture (2D,3D, ...).
  virtual CMappingBase::EDimType GetType() const { return CMappingBase::EE_None; }

  // returns identification of the class
  virtual EClassId GetClassId() const { return EE_ConstantTexture; }

  // set the new color to constant texture
  void SetColor(CValues &newColor) {
    _value = newColor;
  }

  // set the new color to constant texture
  void GetColor(CValues &color) {
    color = _value;
  }

  // returns value for specifed mapInfo
  virtual void GetValue(CValues &value, const CMapPointInfo &) {
    value = _value;
  }

  virtual void GetValue(CValues &value, const CMapPointInfo [], int) {
    value = _value;
  }

  CConstantTexture & operator=(const CConstantTexture &texture) {
    if (this != &texture)
      this->_value = texture._value;
    return *this;
  }

  // Describes the texture to a given stream
  virtual void Describe(ostream &app, int ind, float multiplier = 1.0) const {
    indent(app, ind); app << _value * multiplier;
  }
protected:
  // value of this texture for each texture coordinates
  CValues _value;
};

// ==========================================================================


// --------------------------------------------------------------------------
// This is class for Fresnel texture, and for a now it needn't mapping
// The value of the texture depends only on angle between the incoming
// light dirction and normal. Complex refraction coeffitient can be
// taken from http://www.luxpop.com. By default this refraction coefficient
// corresponds to that of ideal mirror (n = 0, k > 0)
// --------------------------------------------------------------------------
class CFresnelTexture:
  public CTexture
{
public:
  // constructor
  CConstantTexture(CValues &value, float index, float extinction):
    CTexture(),
    _value(value),
    _index(ior),
    _extinction(extinction),
    _approxSchlick(approx)
    {
      assert(index >= 0 && extinction >= 0);
    }

  CConstantTexture(CValues &value, float index):
    CTexture(),
    _value(value),
    _index(ior),
    _extinction(extinction),
    _approxSchlick(false)
    {
      assert(index >= 0 && extinction >= 0);
    }

  CConstantTexture(CValues &value, float index):
    CTexture(),
    _value(value),
    _index(ior),
    _extinction(0),
    _approxSchlick(false)
    {
      assert(index >= 0 && extinction >= 0);
    }

  CConstantTexture(CValues &value):
    CTexture(),
    _value(value),
    _index(0),
    _extinction(1),
    _approxSchlick(false)
    {
      assert(index >= 0 && extinction >= 0);
    }

  CConstantTexture(const CConstantTexture &masterTexture):
    CTexture(),
    _value(masterTexture._value) { }

  // returns the type (dimensionality) of the texture (2D,3D, ...).
  virtual CMappingBase::EDimType GetType() const { return CMappingBase::EE_None; }

  // returns identification of the class
  virtual EClassId GetClassId() const { return EE_ConstantTexture; }

  // set the new color to constant texture
  void SetColor(CValues &newColor) {
    _value = newColor;
  }

  // set the new index of refraction (real part) for constant texture
  void SetIndexR(float &newIor) {
    _index = newIndex;
    assert(newIor >= 0);
  }

  // set the new extinction coefficient for constant texture
  void SetExtinction(float &newExtinction) {
    _extinction = newExtinction;
    assert(newExtinction >= 0);
  }

  // get the color from constant texture
  void GetColor(CValues &color) {
    color = _value;
  }

  // get the index of refraction (real part)
  void GetIndexR(float &ior) {
    extinction = _index;
  }

  // get the new extinction coefficient
  void GetExtinction(float &extinction) {
    extinction = _extinction;
  }

  // Reflectance of real metals and dielectrics depends on angle between the
  // incoming light direction and normal and is defined by the Fresnel
  // equation. (Shirley'2003 Realistic Ray Tracing). The maximum of albedo
  // is achieved:
  //    for dielectics at normal incidence,
  //    for metal at grazing angles (McCool'2002 Reflectance lecctures).

  // Returns the value of albedo at normal incidence
  virtual void GetValue(CValues &value, const CMapPointInfo &) {
    // For metals
    if(_index > 1e-06 && _extinction > 1e-06)
    {
      float sqr_ex = _extinction*_extinction;
      float reflectance = ((_index-1.0)*(_index-1.0) + sqr_ex) /
                          ((_index+1.0)*(_index+1.0) + sqr_ex);

      value = reflectance * _value;
    }
    else
    {
      // For dielectrics
      if(_index > 1e-06)
      {
        float reflectance = ((_index-1.0)*(_index-1.0)) /
                            ((_index+1.0)*(_index+1.0));
        value = reflectance * _value;
      }
      else // For ideal mirror
      {
        value = _value;
      }
    }
  }

  // Returns the value of albedo for specified angle between the incoming
  // light direction and normal.
  // First CMapPointInfo specifies incoming angle, second - texture mapping
  // for some particular surface
  virtual void GetValue(CValues &value, const CMapPointInfo mapInfo[],
                        int size)
  {
    assert(size > 0);

    CVector3D coords = mapInfo[0].coord;

    // The x coordinate of this vector should be set (by user) to the
    // value of incoming angle (range: 0..Pi/2)
    assert(coords[0] >= 0);

    if(coords[0] < 1e-06)
    {
      GetValue(value, mapInfo[0]);
      return;
    }
    value = _value;
  }

  CConstantTexture & operator=(const CConstantTexture &texture) {
    if (this != &texture)
      this->_value = texture._value;
    return *this;
  }

  // Describes the texture to a given stream
  virtual void Describe(ostream &app, int ind, float multiplier = 1.0) const {
    indent(app, ind); app << _value * multiplier;
  }
protected:
  // value of this texture for each texture coordinates
  CValues _value;
  float   _index;      // Real part of complex index of refraction
  float   _extinction; // Imaginary part of complex index of refraction
  bool    _approxSchlick;
};

// ==========================================================================

__END_BRDFLIB_HEADER

#endif // __TEXTURE_H__
