/***
*
*	Copyright (c) 1998, Valve LLC. All rights reserved.
*	
*	This product contains software technology licensed from Id 
*	Software, Inc. ("Id Technology").  Id Technology (c) 1996 Id Software, Inc. 
*	All Rights Reserved.
*
****/


#include "bsp5.h"

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

/*
==================
WriteClipNodes_r

==================
*/
int WriteClipNodes_r (node_t *node)
{
	int			i, c;
	dclipnode_t	*cn;
	int			num;
	
	if (node->planenum == -1)
	{
		num = node->contents;
		free (node->markfaces);
		free (node);
		return num;
	}
	
// emit a clipnode
	if (numclipnodes == MAX_MAP_CLIPNODES)
		Error ("MAX_MAP_CLIPNODES");
	c = numclipnodes;
	cn = &dclipnodes[numclipnodes];
	numclipnodes++;
	if (node->planenum & 1)
		Error ("WriteClipNodes_r: odd planenum");
	cn->planenum = node->planenum;
	for (i=0 ; i<2 ; i++)
		cn->children[i] = WriteClipNodes_r(node->children[i]);
	
	free (node);
	return c;
}

/*
==================
WriteClipNodes

Called after the clipping hull is completed.  Generates a disk format
representation and frees the original memory.
==================
*/
void WriteClipNodes (node_t *nodes)
{
	WriteClipNodes_r (nodes);
}

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

/*
==================
WriteDrawLeaf
==================
*/
void WriteDrawLeaf (node_t *node)
{
	face_t		**fp, *f;
	dleaf_t		*leaf_p;
		
// emit a leaf
	leaf_p = &dleafs[numleafs];
	numleafs++;

	leaf_p->contents = node->contents;

//
// write bounding box info
//	
	VectorCopy (node->mins, leaf_p->mins);
	VectorCopy (node->maxs, leaf_p->maxs);
	
	leaf_p->visofs = -1;	// no vis info yet
	
//
// write the marksurfaces
//
	leaf_p->firstmarksurface = nummarksurfaces;
	
	for (fp=node->markfaces ; *fp ; fp++)
	{
	// emit a marksurface
		f = *fp;
		do
		{
			dmarksurfaces[nummarksurfaces] =  f->outputnumber;
			if (nummarksurfaces >= MAX_MAP_MARKSURFACES)
				Error ("nummarksurfaces == MAX_MAP_MARKSURFACES");
			nummarksurfaces++;
			f=f->original;		// grab tjunction split faces
		} while (f);
	}
	free (node->markfaces);
	
	leaf_p->nummarksurfaces = nummarksurfaces - leaf_p->firstmarksurface;
}

/*
==================
WriteFace
==================
*/
void WriteFace (face_t *f)
{
	dface_t	*df;
	int		i;
	int		e;

	f->outputnumber = numfaces;

	df = &dfaces[numfaces];
	if (numfaces >= MAX_MAP_FACES)
		Error ("numfaces == MAX_MAP_FACES");
	numfaces++;

	df->planenum = f->planenum & (~1);
	df->side = f->planenum & 1;
	df->firstedge = numsurfedges;
	df->numedges = f->numpoints;
	df->texinfo = f->texturenum;
	for (i=0 ; i<f->numpoints ; i++)
	{
		e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f);
		if (numsurfedges >= MAX_MAP_SURFEDGES)
			Error ("numsurfedges == MAX_MAP_SURFEDGES");
		dsurfedges[numsurfedges] = e;
		numsurfedges++;
	}
}

/*
==================
WriteDrawNodes_r
==================
*/
void WriteDrawNodes_r (node_t *node)
{
	dnode_t	*n;
	int		i;
	face_t	*f, *next;

// emit a node	
	if (numnodes == MAX_MAP_NODES)
		Error ("numnodes == MAX_MAP_NODES");
	n = &dnodes[numnodes];
	numnodes++;

	VectorCopy (node->mins, n->mins);
	VectorCopy (node->maxs, n->maxs);

	if (node->planenum & 1)
		Error ("WriteDrawNodes_r: odd planenum");
	n->planenum = node->planenum;
	n->firstface = numfaces;

	for (f=node->faces ; f ; f=f->next)
		WriteFace (f);

	n->numfaces = numfaces - n->firstface;

	//
	// recursively output the other nodes
	//	
	for (i=0 ; i<2 ; i++)
	{
		if (node->children[i]->planenum == -1)
		{
			if (node->children[i]->contents == CONTENTS_SOLID)
				n->children[i] = -1;
			else
			{
				n->children[i] = -(numleafs + 1);
				WriteDrawLeaf (node->children[i]);
			}
		}
		else
		{
			n->children[i] = numnodes;	
			WriteDrawNodes_r (node->children[i]);
		}
	}
}

/*
===========
FreeDrawNodes_r
===========
*/
void FreeDrawNodes_r (node_t *node)
{
	int		i;
	face_t	*f, *next;

	for (i=0 ; i<2 ; i++)
		if (node->children[i]->planenum != -1)
			FreeDrawNodes_r (node->children[i]);

	//
	// free the faces on the node
	//
	for (f=node->faces ; f ; f=next)
	{
		next = f->next;
		FreeFace (f);
	}

	free (node);
}

/*
==================
WriteDrawNodes

Called after a drawing hull is completed
Frees all nodes and faces.
==================
*/
void WriteDrawNodes (node_t *headnode)
{
	if (headnode->contents < 0)	
		WriteDrawLeaf (headnode);
	else
	{
		WriteDrawNodes_r (headnode);
		FreeDrawNodes_r (headnode);
	}
}


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

/*
==================
BeginBSPFile
==================
*/
void BeginBSPFile (void)
{
	// these values may actually be initialized
	// if the file existed when loaded, so clear them explicitly
	nummodels = 0;
	numfaces = 0;
	numnodes = 0;
	numclipnodes = 0;
	numvertexes = 0;
	nummarksurfaces = 0;
	numsurfedges = 0;

	// edge 0 is not used, because 0 can't be negated
	numedges = 1;

// leaf 0 is common solid with no faces
	numleafs = 1;
	dleafs[0].contents = CONTENTS_SOLID;
}


/*
==================
FinishBSPFile
==================
*/
void FinishBSPFile (void)
{
	int		i;

	qprintf ("--- FinishBSPFile ---\n");

	if (verbose)
		PrintBSPFileSizes ();
	WriteBSPFile (bspfilename);
}

