/*
			===== IDBSP - id Software's BSP builder for DOOM ====
	DOS port (c) 1994 Ron Rossbach (ej070@cleveland.freenet.edu)

	File SAVEBSP.C
		Implements functions which write the completed level to the WAD file.

	Revisions:

		1)	Remove the "byte-swapping" casts (SHORT and LONG) (v1.0)

*/

#include "idbsp.h"

STORAGE 	*secstore_i;
STORAGE 	*mapvertexstore_i;
STORAGE 	*subsecstore_i;
STORAGE 	*maplinestore_i;
STORAGE 	*nodestore_i;
STORAGE 	*mapthingstore_i;
STORAGE 	*ldefstore_i;
STORAGE 	*sdefstore_i;

float   	bbox[4];

/*
===============================================================================

In id's original source, the output functions byte swap and write lumps to the
WAD file.  For our purposes, no byte-swapping is necessary, since we're
staying within a single architecture (Intel x86)

===============================================================================
*/

/*
===============================================================================
=
= WriteStorage
=
=		Writes a resource to the WAD file
===============================================================================
*/
void WriteStorage(char *name, STORAGE *store, int esize)
{
	int    count, len;

	count = store->count;
	len = esize*count;
	addName(name, store->data, len);
	printf ("%s (%i): %i\n",name,count,len);
}

/*
===============================================================================
=
= OutputSectors
=
===============================================================================
*/
void OutputSectors(void)
{
	int             i, count;
	mapsector_t     *p;

				count = secstore_i->count;
 /*				p = secstore_i->data + 1; */
				p = sectorsavelist->data + 1;

/*				WriteStorage ("sectors", secstore_i, sizeof(mapsector_t)); */
/*				WriteStorage("sectors", sectorsavelist, sizeof(mapsector_t)); */
	WriteStorage("sectors", sectorsavelist, sectorsavelist->size);

}

/*
===============================================================================
=
= OutputSegs
=
===============================================================================
*/
void OutputSegs(void)
{
/*	WriteStorage ("segs",maplinestore_i, sizeof(mapseg_t)); */
	WriteStorage("segs", maplinestore_i, maplinestore_i->size);
}

/*
===============================================================================
=
= OutputSubsectors
=
===============================================================================
*/
void OutputSubsectors(void)
{
	/* WriteStorage ("ssectors", subsecstore_i, sizeof(mapsubsector_t)); */
	WriteStorage("ssectors", subsecstore_i, subsecstore_i->size);
}

/*
===============================================================================
=
= OutputVertexes
=
===============================================================================
*/
void OutputVertexes (void)
{
	/* WriteStorage ("vertexes",mapvertexstore_i, sizeof(mapvertex_t)); */
	WriteStorage("vertexes", mapvertexstore_i, mapvertexstore_i->size);
}

/*
===============================================================================
=
= OutputThings
=
===============================================================================
*/
void OutputThings(void)
{
	/* WriteStorage ("things", mapthingstore_i, sizeof(mapthing_t)); */
	WriteStorage("things", mapthingstore_i, mapthingstore_i->size);
}

/*
===============================================================================
=
=	OutputLineDefs
=
===============================================================================
*/
void OutputLineDefs(void)
{
	/* WriteStorage ("linedefs", ldefstore_i, sizeof(maplinedef_t)); */
	WriteStorage("linedefs", ldefstore_i, ldefstore_i->size);
}

/*
===============================================================================
=
=	OutputSideDefs
=
===============================================================================
*/
void OutputSideDefs(void)
{
	/* WriteStorage ("sidedefs", sdefstore_i, sizeof(mapsidedef_t)); */
	WriteStorage("sidedefs", sdefstore_i, sdefstore_i->size);
}

/*
===============================================================================
=
=	OutputNodes
=
===============================================================================
*/
void OutputNodes(void)
{
	/* WriteStorage ("nodes", nodestore_i, sizeof(mapnode_t)); */
	WriteStorage("nodes", nodestore_i, nodestore_i->size);
}

/*
===============================================================================
=
= UniqueVertex
=
= Returns the vertex number, adding a new vertex if needed
===============================================================================
*/
int UniqueVertex(int x, int y)
{
	int              i, count;
	mapvertex_t      mv, *mvp;

	mv.x = x;
	mv.y = y;

/* see if an identical vertex already exists */
	count = mapvertexstore_i->count;
	mvp = mapvertexstore_i->data;
	for (i=0 ; i<count ; i++, mvp++)
		if (mvp->x == mv.x && mvp->y == mv.y)
			return i;

	memcpy((mapvertex_t *)mapvertexstore_i->data + mapvertexstore_i->count, &mv,
					sizeof(mapvertex_t));
	mapvertexstore_i->count += 1;
	mapvertexstore_i->data = (mapvertex_t *)SafeRealloc(mapvertexstore_i->data,
						sizeof(mapvertex_t) * (mapvertexstore_i->count + 1));

	return count;
}

/*
===============================================================================
=
= AddPointtoBBox
=
===============================================================================
*/
void AddPointToBBox(NXPoint *pt)
{
	if (pt->x < bbox[BOXLEFT])
		bbox[BOXLEFT] = pt->x;
	if (pt->x > bbox[BOXRIGHT])
		bbox[BOXRIGHT] = pt->x;

	if (pt->y > bbox[BOXTOP])
		bbox[BOXTOP] = pt->y;
	if (pt->y < bbox[BOXBOTTOM])
		bbox[BOXBOTTOM] = pt->y;
}

/*
===============================================================================
=
= ProcessLines
=
= Adds the lines in a subsector to the mapline storage
===============================================================================
*/
void ProcessLines(STORAGE *store_i)
{
	int             i,count;
	line_t          *wline;
	mapseg_t        line;
	short           angle;
	float           fangle;

	bbox[BOXLEFT] = INT_MAX;
	bbox[BOXRIGHT] = INT_MIN;
	bbox[BOXTOP] = INT_MIN;
	bbox[BOXBOTTOM] = INT_MAX;

	count = store_i->count;
	for (i=0 ; i<count ; i++)
		{
		wline = (line_t *)store_i->data + i;
		if (wline->grouped)
			printf ("ERROR: line regrouped\n");
		wline->grouped = true;
		memset (&line, 0, sizeof(line));
		AddPointToBBox (&wline->p1);
		AddPointToBBox (&wline->p2);
		line.v1 = UniqueVertex (wline->p1.x, wline->p1.y);
		line.v2 = UniqueVertex (wline->p2.x, wline->p2.y);
		line.linedef = wline->linedef;
		line.side = wline->side;
		line.offset = wline->offset;
		fangle = atan2 (wline->p2.y - wline->p1.y, wline->p2.x - wline->p1.x);
		angle = (short)(fangle/(PI*2)*0x10000);
		line.angle = angle;
		memcpy((mapseg_t *)maplinestore_i->data + maplinestore_i->count, &line,
								sizeof(line));
		maplinestore_i->count += 1;
		maplinestore_i->data = (mapseg_t *)SafeRealloc(maplinestore_i->data,
										sizeof(mapseg_t) * (maplinestore_i->count + 1));
		}
}

/*
===============================================================================
=
= ProcessSubsector
=
= Adds the lines in a subsector to the mapline storage
===============================================================================
*/
int ProcessSubsector(STORAGE *wmaplinestore_i)
{
	int                  count;
	worldline_t          *linedef;
	line_t               *wline;
	mapsubsector_t  		 sub;

	memset (&sub,0,sizeof(sub));

	count = wmaplinestore_i->count;
	if (count < 1)
		Error ("ProcessSubsector: count = %i",count);

	wline = wmaplinestore_i->data;

	linedef = (worldline_t *)linestore_i->data + wline->linedef;
	sub.numsegs = count;
	sub.firstseg = maplinestore_i->count;
	ProcessLines (wmaplinestore_i);

/*
	add the new subsector
*/
	memcpy((mapsubsector_t *)subsecstore_i->data + subsecstore_i->count, &sub,
					sizeof(mapsubsector_t));
	subsecstore_i->count += 1;
	subsecstore_i->data = (mapsubsector_t *)SafeRealloc(subsecstore_i->data,
												sizeof(mapsubsector_t) * (subsecstore_i->count + 1));

	return subsecstore_i->count - 1;
}

/*
===============================================================================
=
= ProcessNode
=
===============================================================================
*/
int ProcessNode(bspnode_t *node, short *totalbox)
{
	short           subbox[2][4];
	int             i, r;
	mapnode_t       mnode;

	memset (&mnode,0,sizeof(mnode));

	if (node->lines_i)      /* NF_SUBSECTOR flags a subsector */
		{
		r = ProcessSubsector (node->lines_i);
		for (i=0 ; i<4 ; i++)
			totalbox[i] = bbox[i];
		return r | NF_SUBSECTOR;
		}

	mnode.x =node->divline.pt.x;
	mnode.y =node->divline.pt.y;
	mnode.dx =node->divline.dx;
	mnode.dy =node->divline.dy;

	r = ProcessNode(node->side[0], subbox[0]);
	mnode.children[0] =r;
	for (i=0 ; i<4 ; i++)
		mnode.bbox[0][i] =subbox[0][i];

	r = ProcessNode (node->side[1],subbox[1]);
	mnode.children[1] =r;
	for (i=0 ; i<4 ; i++)
		mnode.bbox[1][i] =subbox[1][i];

	totalbox[BOXLEFT] = MIN(subbox[0][BOXLEFT], subbox[1][BOXLEFT]);
	totalbox[BOXTOP] = MAX(subbox[0][BOXTOP], subbox[1][BOXTOP]);
	totalbox[BOXRIGHT] = MAX(subbox[0][BOXRIGHT], subbox[1][BOXRIGHT]);
	totalbox[BOXBOTTOM] = MIN(subbox[0][BOXBOTTOM], subbox[1][BOXBOTTOM]);

	memcpy((mapnode_t *)nodestore_i->data + nodestore_i->count, &mnode, sizeof(mapnode_t));
	nodestore_i->count += 1;
	nodestore_i->data = (mapnode_t *)SafeRealloc(nodestore_i->data,
																																												sizeof(mapnode_t) * (nodestore_i->count + 1));
	return nodestore_i->count - 1;
}

/*
===============================================================================
=
= ProcessNodes
=
= Recursively builds the nodes, subsectors, and line lists,
= then writes the lumps
===============================================================================
*/
void ProcessNodes(void)
{
	short   worldbounds[4];

	subsecstore_i = (STORAGE *)SafeMalloc(sizeof(STORAGE));
	subsecstore_i->data = (mapsubsector_t *)SafeMalloc(sizeof(mapsubsector_t));
	subsecstore_i->count = 0;
	subsecstore_i->size = sizeof(mapsubsector_t);

	maplinestore_i = (STORAGE *)SafeMalloc(sizeof(STORAGE));
	maplinestore_i->data = (mapseg_t *)SafeMalloc(sizeof(mapseg_t));
	maplinestore_i->count = 0;
	maplinestore_i->size = sizeof(mapseg_t);

	nodestore_i = (STORAGE *)SafeMalloc(sizeof(STORAGE));
	nodestore_i->data = (mapnode_t *)SafeMalloc(sizeof(mapnode_t));
	nodestore_i->count = 0;
	nodestore_i->size = sizeof(mapnode_t);

	ProcessNode (startnode, worldbounds);
}

/*
===============================================================================
=
= ProcessThings
=
===============================================================================
*/
void ProcessThings(void)
{
	worldthing_t    *wt;
	mapthing_t      mt;
	int             count;

	mapthingstore_i = (STORAGE *)SafeMalloc(sizeof(STORAGE));
	mapthingstore_i->data = (mapthing_t *)SafeMalloc(sizeof(mapthing_t));
	mapthingstore_i->count = 0;
	mapthingstore_i->size = sizeof(mapthing_t);

	count = thingstore_i->count;
	wt = thingstore_i->data;
	while (count--)
		{
		memset (&mt,0,sizeof(mt));
		mt.x = wt->origin.x;
		mt.y = wt->origin.y;
		mt.angle = wt->angle;
		mt.type = wt->type;
		mt.options = wt->options;
		memcpy((mapthing_t *)mapthingstore_i->data + mapthingstore_i->count, &mt,
											sizeof(mapthing_t));
		mapthingstore_i->count += 1;
		mapthingstore_i->data = (mapthing_t *)SafeRealloc(mapthingstore_i->data,
								sizeof(mapthing_t) * (mapthingstore_i->count + 1));
		wt++;
		}
}

/*
===============================================================================
=
= ProcessSidedef
=
===============================================================================
*/
int ProcessSidedef(worldside_t *ws)
{
	mapsidedef_t    ms;

	ms.textureoffset = ws->firstcollumn;
	ms.rowoffset = ws->firstrow;
	memcpy (ms.toptexture, ws->toptexture, 8);
	memcpy (ms.bottomtexture, ws->bottomtexture, 8);
	memcpy (ms.midtexture, ws->midtexture, 8);
	ms.sector = ws->sector;

	memcpy((mapsidedef_t *)sdefstore_i->data + sdefstore_i->count, &ms,
					sizeof(mapsidedef_t));
	sdefstore_i->count += 1;
	sdefstore_i->data = (mapsidedef_t *)SafeRealloc(sdefstore_i->data,
										sizeof(mapsidedef_t) * (sdefstore_i->count + 1));

	return sdefstore_i->count - 1;
}

/*
===============================================================================
=
= ProcessLineSideDefs
=
= Must be called after BuildSectors
===============================================================================
*/
void ProcessLineSideDefs(void)
{
	int             i, count;
	maplinedef_t    ld;
	worldline_t     *wl;

	mapvertexstore_i = (STORAGE *)SafeMalloc(sizeof(STORAGE));
	mapvertexstore_i->data = (mapvertex_t *)SafeMalloc(sizeof(mapvertex_t));
	mapvertexstore_i->count = 0;
	mapvertexstore_i->size = sizeof(mapvertex_t);

	ldefstore_i = (STORAGE *)SafeMalloc(sizeof(STORAGE));
	ldefstore_i->data = (maplinedef_t *)SafeMalloc(sizeof(maplinedef_t));
	ldefstore_i->count = 0;
	ldefstore_i->size = sizeof(maplinedef_t);

	sdefstore_i = (STORAGE *)SafeMalloc(sizeof(STORAGE));
	sdefstore_i->data = (mapsidedef_t *)SafeMalloc(sizeof(mapsidedef_t));
	sdefstore_i->count = 0;
	sdefstore_i->size = sizeof(mapsidedef_t);

	count = linestore_i->count;
	wl = linestore_i->data;
	for (i=0 ; i<count ; i++, wl++)
		{
		ld.v1 = UniqueVertex(wl->p1.x,wl->p1.y);
		ld.v2 = UniqueVertex(wl->p2.x,wl->p2.y);
		ld.flags = wl->flags;
		ld.special = wl->special;
		ld.tag = wl->tag;
		ld.sidenum[0] = ProcessSidedef(&wl->side[0]);
		if (wl->flags & ML_TWOSIDED)
			ld.sidenum[1] = ProcessSidedef(&wl->side[1]);
		else
			ld.sidenum[1] =-1;

		memcpy((maplinedef_t *)ldefstore_i->data + ldefstore_i->count, &ld,
						sizeof(maplinedef_t));
		ldefstore_i->count += 1;
		ldefstore_i->data = (maplinedef_t *)SafeRealloc(ldefstore_i->data,
								sizeof(maplinedef_t) * (ldefstore_i->count + 1));
		}
}

/*
===============================================================================
=
=	SaveDoomMap
=
===============================================================================
*/
void SaveDoomMap(void)
{
  if (trace)
	  printf("\nBuildSectordefs\n");
	BuildSectordefs();

  if (trace)
  	printf("ProcessThings\n");
	ProcessThings();

  if (trace)
  	printf("ProcessLineSideDefs\n");
	ProcessLineSideDefs();

  if (trace)
  	printf("ProcessNodes\n");
	ProcessNodes();

  if (trace)
  	printf("ProcessSectors\n");
	ProcessSectors();

  if (trace)
  	printf("\nProcessConnections\n");
	ProcessConnections();

/* all processing is complete, write everything out */
	OutputThings();
	OutputLineDefs();
	OutputSideDefs();
	OutputVertexes();
	OutputSegs();
	OutputSubsectors();
	OutputNodes();
	OutputSectors();
	OutputConnections();
}

