/* btdf.c: Bidirectional Transmittance Distribution Functions */

#include "btdf.h"
#include "brdf.h"
#include "pools.h"
#include "Boolean.h"
#include "error.h"

#ifdef NOPOOLS
#define NEWBTDF()	(BTDF *)Alloc(sizeof(BTDF))
#define DISPOSEBTDF(ptr) Free((char *)ptr, sizeof(BTDF))
#else
static POOL *btdfPool = (POOL *)NULL;
#define NEWBTDF()	(BTDF *)NewPoolCell(sizeof(BTDF), 0, "btdfs", &btdfPool)
#define DISPOSEBTDF(ptr) Dispose((char *)ptr, &btdfPool)
#endif

/* Creates a BTDF instance with given data and methods. A pointer
 * to the created BTDF struct is returned. */
BTDF *BtdfCreate(void *data, BTDF_METHODS *methods)
{
  BTDF *btdf;

  btdf = NEWBTDF();
  btdf->data = data;
  btdf->methods = methods;

  return btdf;
}

/* Creates and returns a duplicate of the given BTDF */
BTDF *BtdfDuplicate(BTDF *obtdf)
{
  BTDF *btdf;

  if (!obtdf)
    return obtdf;

  btdf = NEWBTDF();
  btdf->data = obtdf->methods->Duplicate(obtdf->data);
  btdf->methods = obtdf->methods;

  return btdf;
}

/* Creates an editor widget for the BTDF, returns the Widget casted
 * to a void * in order not to have to include all X window system files. */
void *BtdfCreateEditor(void *parent, BTDF *btdf)
{
  if (!btdf)
    Fatal(-1, "BtdfCreateEditor", "NULL btdf pointer passed.");
  return btdf->methods->CreateEditor(parent, btdf->data);
}

/* disposes of the memory occupied by the BTDF instance */
void BtdfDestroy(BTDF *btdf)
{
  if (!btdf) return;
  btdf->methods->Destroy(btdf->data);
  DISPOSEBTDF(btdf);
}

/* Returns the transmittance of the BTDF */
COLOR BtdfTransmittance(BTDF *btdf, XXDFFLAGS flags)
{
  if (btdf && btdf->methods->Transmittance)
    return btdf->methods->Transmittance(btdf->data, flags);
  else {
    static COLOR refl;
    COLORCLEAR(refl);
    return refl;
  }
}


void BtdfIndexOfRefraction(BTDF *btdf, REFRACTIONINDEX *index)
{
  if (btdf && btdf->methods->IndexOfRefraction)
  {
    btdf->methods->IndexOfRefraction(btdf->data, index);
  }
  else
  {
    index->nr = 1.0;
    index->ni = 0.0; /* Vacuum */
  }
}


/* Btdf evaluations */

COLOR BtdfEval(BTDF *btdf, REFRACTIONINDEX inIndex, REFRACTIONINDEX outIndex, VECTOR *in, VECTOR *out, VECTOR *normal, XXDFFLAGS flags)
{
  if (btdf && btdf->methods->Eval)
    return btdf->methods->Eval(btdf->data, inIndex, outIndex, in, out, normal, flags);
  else {
    static COLOR refl;
    COLORCLEAR(refl);
    return refl;
  }
}

VECTOR BtdfSample(BTDF *btdf, REFRACTIONINDEX inIndex, 
		  REFRACTIONINDEX outIndex, VECTOR *in, 
		  VECTOR *normal, int doRussianRoulette,
		  XXDFFLAGS flags, double x_1, double x_2, 
		  double *pdf)
{
  if (btdf && btdf->methods->Sample)
    return btdf->methods->Sample(btdf->data, inIndex, outIndex, in, normal, 
				 doRussianRoulette, flags, x_1, x_2, pdf);
  else {
    VECTOR dummy = {0., 0., 0.};
    *pdf = 0;
    return dummy;
  }
}

void BtdfEvalPdf(BTDF *btdf, REFRACTIONINDEX inIndex, 
		 REFRACTIONINDEX outIndex, VECTOR *in, 
		 VECTOR *out, VECTOR *normal,
		 XXDFFLAGS flags, double *pdf, double *pdfRR)
{
  if (btdf && btdf->methods->EvalPdf)
    btdf->methods->EvalPdf(btdf->data, inIndex, outIndex, in, out, 
			   normal, flags, pdf, pdfRR);
  else {
    *pdf = 0;
  }
}

/* Print the btdf data the to specified file pointer */
void BtdfPrint(FILE *out, BTDF *btdf)
{
  if (!btdf)
    fprintf(out, "(NULL BTDF)\n");
  else
    btdf->methods->Print(out, btdf->data);
}
