#define	LIBQTOOLS_CORE
#define	LIBQBUILD_CORE
#include <libqtools.h>
#include <libqbuild.h>

struct memory bspStatic;
struct memory *bspMem = &bspStatic;

extern int c_bad;
extern struct tnode *tnodes, *tnode_p;
extern bool *nolightface;
extern float *minlights;
extern float rangescale;
extern float scalecos;
extern float scaledist;
extern int bspfileface;						/* next surface to dispatch */
extern vec3_t *faceoffset;
extern vec3_t bsp_origin;

extern void LightWorld(__memBase);
extern void MakeTnodes(__memBase, register struct dmodel_t *bm);

/*
 * ========
 * main
 * 
 * light modelfile
 * ========
 */
int main(int argc, char **argv)
{
  int i;
  char source[NAMELEN_PATH];
  HANDLE bspFile;
  int litOptions = 0;

  memset(bspMem, 0, sizeof(struct memory));

  if (!setjmp(eabort)) {
    printf("----- LightFaces --------\n");

    for (i = 1; i < argc; i++) {
      if (!strcmp(argv[i], "-extra")) {
	litOptions |= LIGHT_EXTRA;
	mprintf("extra sampling enabled\n");
      }
      else if (!strcmp(argv[i], "-rad")) {
	litOptions |= LIGHT_RADIOSITY;
	mprintf("radiosity calculation enabled\n");
      }
      else if (!strcmp(argv[i], "-waterlit")) {
	litOptions |= LIGHT_WATERLIT;
	mprintf("extra watershadowing enabled\n");
      }
      else if (!strcmp(argv[i], "-dist")) {
	scaledist = atof(argv[i + 1]);
	i++;
      }
      else if (!strcmp(argv[i], "-range")) {
	rangescale = atof(argv[i + 1]);
	i++;
      }
      else if (argv[i][0] == '-')
	Error("Unknown option \"%s\"", argv[i]);
      else
	break;
    }

    if (i != argc - 1)
      Error("usage: light [-extra] bspfile");

    strcpy(source, argv[i]);
    ReplaceExt(source, "bsp");
    if ((bspFile = __open(source, H_READWRITE_BINARY_OLD)) > 0) {
      if ((bspMem = LoadBSP(bspFile, ALL_QUAKE1_LUMPS & ~(LUMP_LIGHTING | LUMP_VISIBILITY), BSP_VERSION_Q1))) {
	bspMem->litOptions = litOptions;
	AllocClusters(bspMem, LUMP_LIGHTING);

	if (!(minlights = (float *)kmalloc(sizeof(float) * bspMem->shared.quake1.numfaces)))
	    Error("Light: failed to allocate minlights!\n");

	if (!(nolightface = (bool *) kmalloc(sizeof(bool) * bspMem->shared.quake1.numfaces)))
	  Error("Light: failed to allocate nolightface!\n");
	if (!(faceoffset = (vec3_t *) kmalloc(sizeof(vec3_t) * bspMem->shared.quake1.numfaces)))
	  Error("Light: failed to allocate faceoffset!\n");

	if (bspMem->litOptions & LIGHT_RADIOSITY) {
	  if (!(facepatches = (struct patch **)kmalloc(sizeof(struct patch *) * bspMem->shared.quake1.numfaces)))
	      Error("Light: failed to allocate facepatches!\n");
	  if (!(faceentity = (struct entity **)kmalloc(sizeof(struct entity *) * bspMem->shared.quake1.numfaces)))
	      Error("Light: failed to allocate faceentity!\n");
	  if (!(facelights = (struct facelight *)kmalloc(sizeof(struct entity *) * bspMem->shared.quake1.numfaces)))
	      Error("Light: failed to allocate facelights!\n");
	  if (!(patches = (struct patch *)kmalloc(sizeof(struct patch) * 4096)))
	      Error("Light: failed to allocate patches!\n");

	  if (!(radiosity = (vec3_t *) kmalloc(sizeof(vec3_t) * bspMem->shared.quake1.numfaces)))
	    Error("Light: failed to allocate radiosity!\n");
	  if (!(illumination = (vec3_t *) kmalloc(sizeof(vec3_t) * bspMem->shared.quake1.numfaces)))
	    Error("Light: failed to allocate illumination!\n");
	  if (!(backplanes = (struct dplane_t *)kmalloc(sizeof(struct dplane_t) * bspMem->shared.quake1.numplanes)))
	      Error("Light: failed to allocate backplanes!\n");
	  if (!(directlights = (struct directlight **)kmalloc(sizeof(struct directlight *) * bspMem->shared.quake1.numleafs)))
	      Error("Light: failed to allocate directlights!\n");
	  if (!(leafparents = (int *)kmalloc(sizeof(int) * bspMem->shared.quake1.numleafs)))
	      Error("Light: failed to allocate leafparents!\n");
	  if (!(nodeparents = (int *)kmalloc(sizeof(int) * bspMem->shared.quake1.numnodes)))
	      Error("Light: failed to allocate nodeparents!\n");

	  if (!(texreflectivity = (vec3_t *) kmalloc(sizeof(vec3_t) * bspMem->shared.quake1.numtexinfo)))
	    Error("Lights: failed to allocate texture reflectivity!\n");
	}

	bspMem->mapOptions |= MAP_LOADLIGHTS;
	LoadMapFile(bspMem, bspMem->shared.quake1.dentdata);
	MakeTnodes(bspMem, &bspMem->shared.quake1.dmodels[0]);

	if (bspMem->litOptions & LIGHT_RADIOSITY)
	  RadWorld(bspMem);
	else
	  LightWorld(bspMem);

	WriteEntitiesToString(bspMem);
	WriteBSP(bspFile, bspMem, BSP_VERSION_Q1);
	PrintClusters(bspMem, 0, TRUE);

	FreeClusters(bspMem, 0);
	kfree();
	__close(bspFile);
      }
      else
	eprintf("failed to load bsp file %s\n", source);
    }
    else
      eprintf("failed to open bsp file %s\n", source);
  }

  return 0;
}
