/* radiance.c: stuff common to all radiance methods */

#include <string.h>

#include "config.h"

#include "radiance.h"
#include "scene.h"
#include "geom.h"
#include "error.h"
#include "options.h"
#include "defaults.h"

#ifdef GALERKIN
#include "GALERKIN/galerkin.h"
#endif

#ifdef STOCHRAY
#include "MCRAD/stochray.h"
#endif
#ifdef WDRS
#include "MCRAD/wdrs.h"
#endif
#ifdef NEVER
#ifdef RWRAD
#include "MCRAD/rwrad.h"
#endif
#endif

#ifdef STOCHRELAX
#include "MCRAD/mcrad.h"
#endif
#ifdef RWRAD
#include "MCRAD/mcrad.h"
#endif

#ifdef HURA
#include "HURA/hura.h"
#endif
#ifdef DEST
#include "DEST/dest.h"
#endif
#ifdef PHOTONMAP
#include "PHOTONMAP/pmap.h"
#endif

#ifdef RDRAD
#include "RDRAD/rdrad.h"
#endif

#ifdef PARTICLE
#include "PARTICLE/particle.h"
#endif
#ifdef BIRAD
#include "BIRAD/birad.h"
#endif
#ifdef YUP
#include "YUP/yup.h"
#endif

/* table of available radiance methods */
RADIANCEMETHOD *RadianceMethods[] = {
#ifdef GALERKIN
  &GalerkinRadiosity,
#endif

#ifdef WDRS
  &WDRSRadiosity,
#endif
#ifdef STOCHRAY
  &StochasticRayRadiosity,
#endif

#ifdef STOCHRELAX
  &StochasticRelaxationRadiosity,
#endif
#ifdef RWRAD
  &RandomWalkRadiosity,
#endif

#ifdef DEST
  &DensityEstimation,
#endif
#ifdef PHOTONMAP
  &Pmap,
#endif
#ifdef RDRAD
  &RDRad,
#endif
#ifdef PARTICLE
  &ParticleTracing,
#endif
#ifdef HURA
  &Hura,
#endif
#ifdef BIRAD
  &Birad,
#endif
#ifdef YUP
  &Yup,
#endif
  (RADIANCEMETHOD *)NULL
};

/* current radiance method handle */
RADIANCEMETHOD *Radiance = (RADIANCEMETHOD *)NULL;

/* This routine sets the current radiance method to be used + initializes */
void SetRadianceMethod(RADIANCEMETHOD *newmethod)
{
  if (Radiance) {
    Radiance->HideControlPanel();
    Radiance->Terminate();
    /* until we have radiance data convertors, we dispose of the old data and 
     * allocate new data for the new method. */
    if (Radiance->DestroyPatchData)
      PatchListIterate(Patches, Radiance->DestroyPatchData);
  }
  Radiance = newmethod;
  if (Radiance) {
    if (Radiance->CreatePatchData)
      PatchListIterate(Patches, Radiance->CreatePatchData);
    Radiance->Initialize();
  }
}

/* composes explanation for -radiance command line option */
static char radiance_methods_string[1000];
static void make_radiance_methods_string(void)
{
  char *str = radiance_methods_string;
  int n;
  sprintf(str, "\
-radiance-method <method>: Set world-space radiance computation method\n%n",
	  &n); str += n;
  sprintf(str, "\tmethods: %-20.20s %s%s\n%n", 
	  "none", "no world-space radiance computation", 
	  !Radiance ? " (default)" : "", &n); str += n;
  ForAllRadianceMethods(method) {
    sprintf(str, "\t         %-20.20s %s%s\n%n",
	    method->shortName, method->fullName, 
	    Radiance==method ? " (default)" : "", &n); str += n;
  } EndForAll;
  *(str-1) = '\0';	/* discard last newline character */
}

void RadianceDefaults(void)
{
  ForAllRadianceMethods(method) {
    method->Defaults();
    if (strncasecmp(DEFAULT_RADIANCE_METHOD, method->shortName, method->nameAbbrev) == 0)
      SetRadianceMethod(method);
  } EndForAll;
  make_radiance_methods_string();
}

static void RadianceMethodOption(void *value)
{
  char *name = *(char **)value;

  ForAllRadianceMethods(method) {
    if (strncasecmp(name, method->shortName, method->nameAbbrev) == 0) {
      SetRadianceMethod(method);
      return;
    }
  } EndForAll;

  if (strncasecmp(name, "none", 4) == 0)
    SetRadianceMethod(NULL);
  else
    Error(NULL, "Invalid world-space radiance method name '%s'", name);
}

static CMDLINEOPTDESC radianceOptions[] = {
  {"-radiance-method", 4, Tstring, 	NULL,	RadianceMethodOption,
   radiance_methods_string },
  {NULL	, 	0,	TYPELESS, 	NULL, 	DEFAULT_ACTION,
   NULL }
};

void ParseRadianceOptions(int *argc, char **argv)
{
  ParseOptions(radianceOptions, argc, argv);

  ForAllRadianceMethods(method) {
    method->ParseOptions(argc, argv);
  } EndForAll;
}

void PrintRadianceOptions(FILE *fp)
{
  fprintf(fp, "\nObject-space radiance computation options:\n");
  PrintOptions(fp, radianceOptions);

  ForAllRadianceMethods(method) {
    method->PrintOptions(fp);
  } EndForAll;
}

