#include "qbsp.h"

int outleafs = 0;				// 4

struct portal *prevleaknode;			// 4
FILE *leakfile;					// 4

int hit_occupied = 0;				// 4
int backdraw = 0;				// 4
/* PROGRESS-ONLY! */
int outsidenum;
int outsidecur;

/*
 * ===========
 * PointInLeaf
 * ===========
 */
struct node *PointInLeaf(__memBase, struct node * node, vec3_t point)
{
  vec_t d;

  if (node->contents)
    return node;

#ifdef EXHAUSIVE_CHECK
  if(node->planenum >= bspMem->numbrushplanes || node->planennum < 0)
    Error("looking for nonexisting plane %d\n", node->planenum);
#endif
  d = DotProduct(bspMem->brushplanes[node->planenum].normal, point) - bspMem->brushplanes[node->planenum].dist;

  if (d > 0)
    return PointInLeaf(bspMem, node->children[0], point);

  return PointInLeaf(bspMem, node->children[1], point);
}

/*
 * ===========
 * PlaceOccupant
 * ===========
 */
bool PlaceOccupant(__memBase, register int num, register vec3_t point, register struct node * headnode)
{
  struct node *n;

  n = PointInLeaf(bspMem, headnode, point);
  if (n->contents == CONTENTS_SOLID)
    return false;
  n->occupied = num;
  return true;
}

/*
 * ==============
 * MarkLeakTrail
 * ==============
 */
void MarkLeakTrail(register struct portal * n2)
{
  int i;
  short int j;
  vec3_t p1, p2, dir;
  float len;
  struct portal *n1;

  if (hullnum)
    return;

  n1 = prevleaknode;
  prevleaknode = n2;

  if (!n1)
    return;

  VectorCopy(n2->winding->points[0], p1);
  for (i = 1; i < n2->winding->numpoints; i++) {
    for (j = 0; j < 3; j++)
      p1[j] = (p1[j] + n2->winding->points[i][j]) / 2;
  }

  VectorCopy(n1->winding->points[0], p2);
  for (i = 1; i < n1->winding->numpoints; i++) {
    for (j = 0; j < 3; j++)
      p2[j] = (p2[j] + n1->winding->points[i][j]) / 2;
  }

  VectorSubtract(p2, p1, dir);
  len = VectorLength(dir);
  VectorNormalize(dir);

  while (len > 2) {
    fprintf(leakfile, "%g %g %g\n", p1[0], p1[1], p1[2]);
    for (i = 0; i < 3; i++)
      p1[i] += dir[i] * 2;
    len -= 2;
  }
}

/*
 * ==================
 * RecursiveFillOutside
 * 
 * If fill is false, just check, don't fill
 * Returns true if an occupied leaf is reached
 * ==================
 */
bool RecursiveFillOutside(register struct node * l, register bool fill)
{
  struct portal *p;
  int s;
  
  /* PROGRESS-ONLY! */
  if(fill == FALSE)
    outsidenum++;
  else
    mprogress(outsidenum, ++outsidecur);

  if (l->contents == CONTENTS_SOLID || l->contents == CONTENTS_SKY)
    return false;

  if (l->valid == valid)
    return false;

  if (l->occupied)
    return true;

  l->valid = valid;

// fill it and it's neighbors
  if (fill)
    l->contents = CONTENTS_SOLID;
  outleafs++;

  for (p = l->portals; p;) {
    s = (p->nodes[0] == l);

    if (RecursiveFillOutside(p->nodes[s], fill)) {			       // leaked, so stop filling

      if (backdraw-- > 0) {
	MarkLeakTrail(p);
	DrawLeaf(l, 2);
      }
      return true;
    }
    p = p->next[!s];
  }

  return false;
}

/*
 * ==================
 * ClearOutFaces
 * 
 * ==================
 */
void ClearOutFaces(register struct node * node)
{
  struct visfacet **fp;

  if (node->planenum != -1) {
    ClearOutFaces(node->children[0]);
    ClearOutFaces(node->children[1]);
    return;
  }
  if (node->contents != CONTENTS_SOLID)
    return;

  for (fp = node->markfaces; *fp; fp++) {
    // mark all the original faces that are removed
    (*fp)->numpoints = 0;
  }
  node->faces = NULL;
}

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

/*
 * ===========
 * FillOutside
 * 
 * ===========
 */
bool FillOutside(__memBase, struct node * node, char *pointfilename)
{
  int s;
  vec_t *v;
  int i;
  bool inside;

  mprintf("----- FillOutside -------\n");
  /* PROGRESS-ONLY! */
  outsidenum = 0;
  outsidecur = 0;

  if (bspMem->bspOptions & QBSP_NOFILL) {
    mprintf("    - skipped\n");
    return false;
  }

  inside = false;
  for (i = 1; i < bspMem->nummapentities; i++) {
    if (!VectorZero(bspMem->mapentities[i].origin)) {
      if (PlaceOccupant(bspMem, i, bspMem->mapentities[i].origin, node))
	inside = true;
    }
  }

  if (!inside) {
    mprintf("Hullnum %i: No bspMem->mapentities in empty space -- no filling performed\n", hullnum);
    return false;
  }

  s = !(outside_node.portals->nodes[1] == &outside_node);

// first check to see if an occupied leaf is hit
  outleafs = 0;
  valid++;

  prevleaknode = NULL;

  if (!hullnum) {
    leakfile = fopen(pointfilename, "w");
    if (!leakfile)
      Error("Couldn't open %s\n", pointfilename);
  }

  if (RecursiveFillOutside(outside_node.portals->nodes[s], false)) {
    v = bspMem->mapentities[hit_occupied].origin;
    eprintf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
    eprintf("reached occupant at: ( %g %g %g )\n"
	    ,v[0], v[1], v[2]);
    eprintf("no filling performed\n");
    if (!hullnum)
      fclose(leakfile);
    eprintf("leak file written to %s\n", pointfilename);
    eprintf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
    return false;
  }
  if (!hullnum)
    fclose(leakfile);

// now go back and fill things in
  valid++;
  RecursiveFillOutside(outside_node.portals->nodes[s], true);

// remove faces from filled in leafs    
  ClearOutFaces(node);

  mprintf("%5i outleafs\n", outleafs);
  return true;
}
