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

	File DOOMLOAD.C
		Implements the functions that load the map data from the input file
		in preparation for building the BSP tree.

	Revisions:
		1)	Change ReadThing to NOT align THINGS on a 16x16 grid, as id's
				original source did. (v1.1)

		2)	Change ReadLine to NOT read sector information, as id's original
				source did.  Extend DWD files to include a WIF-like "sectors:"
				section for each level; also, have the "lines:" entries reference
				a sector number from the "sectors:" section, rather than include
				all the sector information redundantly for each SIDEDEF. (v1.1)

		3)	Change LoadDoomMap to really remove overlaid and zero-length LINEDEFS,
				rather than just warning about it.	(v1.1)
*/

#include "idbsp.h"

int       	linenum = 0;
STORAGE 		*linestore_i, *thingstore_i;
sectordef_t *sectorlist;
int 				sectorlistcount;

/*
===============================================================================
=
= ReadLine
=
=	Reads a line from a DWD file.  Must be called after the sector list is
= built.
===============================================================================
*/
worldline_t *ReadLine(FILE *file, worldline_t *line)
{
	NXPoint         *p1, *p2;
	worldside_t     *s;
	int             i, secnum;

	memset(line, 0, sizeof(worldline_t));

	p1 = &line->p1;
	p2 = &line->p2;

	if (fscanf (file,"(%f,%f) to (%f,%f) : %d : %d : %d\n", &p1->x, &p1->y,
							&p2->x, &p2->y,&line->flags, &line->special, &line->tag) != 7)
		Error ("Failed ReadLine");

	for (i=0 ; i<=  ( (line->flags&ML_TWOSIDED) != 0) ; i++)
		{
		s = &line->side[i];
		if (fscanf (file,"    %d (%d : %s / %s / %s ) %d\n",
									&s->firstrow, &s->firstcollumn, s->toptexture,
									s->bottomtexture, s->midtexture, &secnum) != 6)
			Error ("Failed ReadLine (side)");
/*  memcpy(&s->sectordef, &sectors[secnum], sizeof(sectordef_t)); */
		s->sectordef = sectorlist + secnum;
		s->sector = secnum;
		}

	linenum++;

	return line;
}

/*
===============================================================================
=
=	ReadSector
=
=	Reads a sector from a DWD file.
===============================================================================
*/
void ReadSector(FILE *file, sectordef_t *s)
{
	memset(s, 0, sizeof(sectordef_t));

	if (fscanf(file, "%d : %s %d : %s %d %d %d\n",&s->floorheight,
							s->floorflat, &s->ceilingheight, s->ceilingflat, &s->lightlevel,
							&s->special, &s->tag) != 7)
		Error("\nfailed ReadSector");

	return;
}

/*
===============================================================================
=
=	ReadThing
=
=	Reads a THING from a DWD file.
===============================================================================
*/
worldthing_t *ReadThing(FILE *file, worldthing_t *thing)
{
	int     x,y;

	memset (thing, 0, sizeof(*thing));

/*
	To perform alignment, retain following code (with fx and fy defined as
	floats) and NXPoint defined as ints...

	if (fscanf(file,"(%i,%i, %d) :%d, %d\n",&x, &y, &thing->angle,
						&thing->type, &thing->options) != 5)
		Error ("Failed ReadThing");

	fx = x & -16;
	fy = y & -16;
	thing->origin.x = fx;
	thing->origin.y = fy;
*/

	if (fscanf(file,"(%i,%i, %d) :%d, %d\n", &thing->origin.x,	&thing->origin.y,
							&thing->angle, &thing->type, &thing->options) != 5)
		Error("Failed ReadThing");

	return thing;
}

/*
===============================================================================
=
=	BBoxFromPoints
=
=	Constructs a bounding box from two map points.
===============================================================================
*/
void BBoxFromPoints(fbbox_t *box, NXPoint *p1, NXPoint *p2)
{
	if (p1->x < p2->x)
		{
		box->left = p1->x;
		box->right = p2->x;
		}
	else
		{
		box->left = p2->x;
		box->right = p1->x;
		}

	if (p1->y < p2->y)
		{
		box->bottom = p1->y;
		box->top = p2->y;
		}
	else
		{
		box->bottom = p2->y;
		box->top = p1->y;
		}
}

/*
===============================================================================
=
=	LineOverlaid
=
=	Returns true if the line overlays any existing lines
===============================================================================
*/
boolean LineOverlaid(worldline_t *line)
{
	int             j, count;
	worldline_t     *scan;
	divline_t       wl;
	fbbox_t          linebox, scanbox;

	wl.pt = line->p1;
	wl.dx = line->p2.x - line->p1.x;
	wl.dy = line->p2.y - line->p1.y;

	count = linestore_i->count;
	scan = linestore_i->data;

	for (j=0 ; j<count ; j++, scan++)
		{
		if (PointOnSide(&scan->p1, &wl) != -1)
			continue;
		if (PointOnSide(&scan->p2, &wl) != -1)
			continue;
/* line is colinear, see if it overlapps */
		BBoxFromPoints(&linebox, &line->p1, &line->p2);
		BBoxFromPoints(&scanbox, &scan->p1, &scan->p2);
		if (linebox.right  > scanbox.left && linebox.left < scanbox.right)
			return true;
		if (linebox.bottom < scanbox.top && linebox.top > scanbox.bottom)
			return true;
		}

	return false;
}

/*
===============================================================================
=
=	LoadDoomMap
=
=	Loads map info (sectors, lines, things) from a DWD file.  Note that vertex
= sidedef info is also read when reading a line.
===============================================================================
*/
void LoadDoomMap(FILE *file)
{
	int     				i;
	int     				linecount, thingcount, sectorcount;
	worldline_t 		*line;
	worldthing_t		*thing;
	sectordef_t 		*sec;

/*
				read sectors
*/
	if (fscanf(file, "\nsectors:%d\n", &sectorcount) != 1)
		Error("\nLoadDoomMap: cannot read sectorcount");

	printf("%i sectors\n", sectorcount);
	sectorlist = sec = (sectordef_t *)SafeCalloc(sectorcount,
																								sizeof(sectordef_t));
	printf("\n");
	for (i=0; i<sectorcount; i++, sec++)
		{
		printf("Reading sector #%d\r",i);
		ReadSector(file,sec);
		}

	sectorlistcount = sectorcount;

/*
 read lines
*/
	if (fscanf (file,"\nlines:%d\n",&linecount) != 1)
		Error ("LoadDoomMap: can\'t read linecount");

	printf ("\n%i lines\n\n", linecount);
	linestore_i = (STORAGE *)SafeMalloc(sizeof(STORAGE));
	linestore_i->data = (worldline_t *)SafeCalloc(linecount,sizeof(worldline_t));
	linestore_i->size = sizeof(worldline_t);
	linestore_i->count = 0;

	line = linestore_i->data;

	for (i=0 ; i<linecount ; i++)
		{
		printf("Reading line #%d\r",i);
		ReadLine(file, line);
		if ((!duplines) && (line->p1.x == line->p2.x && line->p1.y == line->p2.y))
			{
			printf ("WARNING: line %i is length 0 (removed)\n",i);
			continue;
			}
		if ((!duplines) && (LineOverlaid(line)))
			{
			printf ("WARNING: line %i is overlaid (removed)\n",i);
			continue;
			}
		linestore_i->count += 1;
		line += 1;
		}

	printf("\ntotal lines: %i\n",linestore_i->count);

/*
 read things
*/
	if (fscanf (file,"\nthings:%d\n",&thingcount) != 1)
		Error ("LoadDoomMap: can't read thingcount");

	printf ( "\n\n%i things\n", thingcount);
	thingstore_i = (STORAGE *)SafeMalloc(sizeof(STORAGE));
	thingstore_i->data = (worldthing_t *)SafeCalloc(thingcount,sizeof(worldthing_t));
	thingstore_i->size = sizeof(worldthing_t);
	thingstore_i->count = thingcount;

	thing = thingstore_i->data;

	for (i=0;i<thingcount;i++)
		{
		printf("Reading thing #%d\r",i);
		ReadThing(file,thing);
		thing++;
		}
}


/*
===============================================================================
=
=	LoadWADMap
=
=	Loads map info (sectors, lines, things) from a WAD file.
===============================================================================
*/
void LoadWADMap(FILE *file, lumpinfo_t *lumps)
{
	int     				i;
	int 						linecount, thingcount, sectorcount, vertexcount, sidecount;
	worldline_t     *line;
	worldthing_t 		*thing;
	sectordef_t 		*sec;
	mapvertex_t 		*vertexes;
	mapsidedef_t 		*sidedefs;

/*
				"lumps" comes from WADMain pointing to the level label.....(ML_LABEL)
				read sectors
*/
	sectorcount = lumps[ML_SECTORS].size / sizeof(mapsector_t);
	printf("%i sectors\n\n", sectorcount);
	sectorlist = sec = (sectordef_t *)SafeCalloc(sectorcount,
																								sizeof(sectordef_t));
	fseek(file, lumps[ML_SECTORS].filepos, SEEK_SET);
	for (i=0; i<sectorcount; i++, sec++)
		{
		printf("Reading sector #%d\r",i);
		ReadWADSector(file,sec);
		}

	sectorlistcount = sectorcount;

/*
				read vertexes and sidedefs ... needed to construct a linedef
*/
	vertexcount = lumps[ML_VERTEXES].size / sizeof(mapvertex_t);
	printf("\n%i vertexes\n", vertexcount);
	vertexes = (mapvertex_t *)SafeCalloc(vertexcount, sizeof(mapvertex_t));
	fseek(file, lumps[ML_VERTEXES].filepos, SEEK_SET);
	if (fread(vertexes, sizeof(mapvertex_t), vertexcount, file) != vertexcount)
		Error("\nLoadWADMap failure - could not load vertexes\n");

	sidecount = lumps[ML_SIDEDEFS].size / sizeof(mapsidedef_t);
	printf("\n%i sides\n", sidecount);
	sidedefs = (mapsidedef_t *)SafeCalloc(sidecount, sizeof(mapsidedef_t));
	fseek(file, lumps[ML_SIDEDEFS].filepos, SEEK_SET);
	if (fread(sidedefs, sizeof(mapsidedef_t), sidecount, file) != sidecount)
		Error("\nLoadWADMap failure - could not load sidedefs\n");

/*
				read lines
*/
	linecount = lumps[ML_LINEDEFS].size / sizeof(maplinedef_t);
	printf ("\n%i lines\n\n", linecount);

	linestore_i = (STORAGE *)SafeMalloc(sizeof(STORAGE));
	linestore_i->data = (worldline_t *)SafeCalloc(linecount,sizeof(worldline_t));
	linestore_i->size = sizeof(worldline_t);
	linestore_i->count = 0;

	line = linestore_i->data;
	fseek(file, lumps[ML_LINEDEFS].filepos, SEEK_SET);
	for (i=0 ; i<linecount ; i++)
		{
		printf("Reading line #%d\r",i);
		ReadWADLine(file, line, vertexes, sidedefs);
		if ((!duplines) && (line->p1.x == line->p2.x && line->p1.y == line->p2.y))
			{
			printf ("WARNING: line %i is length 0 (removed)\n",i);
			continue;
			}
		if ((!duplines) && (LineOverlaid (line)))
			{
			printf ("WARNING: line %i is overlaid (removed)\n",i);
			continue;
			}
		linestore_i->count += 1;
		line += 1;
		}

	printf("\ntotal lines: %i\n",linestore_i->count);

	free(vertexes);
	free(sidedefs);

/*
				read things
*/
	thingcount = lumps[ML_THINGS].size / sizeof(mapthing_t);
	thingstore_i = (STORAGE *)SafeMalloc(sizeof(STORAGE));
	thingstore_i->data = (worldthing_t *)SafeCalloc(thingcount,sizeof(worldthing_t));
	thingstore_i->size = sizeof(worldthing_t);
	thingstore_i->count = thingcount;

	thing = thingstore_i->data;
	fseek(file, lumps[ML_THINGS].filepos, SEEK_SET);
	for (i=0;i<thingcount;i++)
		{
		printf("Reading thing #%d\r",i);
		ReadWADThing(file,thing);
		thing++;
		}

	return;
}

/*
===============================================================================
=
=	ReadWADLine
=
=	Reads a line from a WAD file, as ReadLine does from a DWD file.
===============================================================================
*/
void ReadWADLine(FILE *f, worldline_t *wl, mapvertex_t *verts,
									mapsidedef_t *sides)
{
	maplinedef_t 		ml;
	int 						i;
	worldside_t 		*s;
	mapsidedef_t 		*ms;

	if (fread(&ml, sizeof(maplinedef_t), 1, f) != 1)
		Error("\nReadWADLine failure\n");

	wl->p1.x = verts[ml.v1].x;
	wl->p1.y = verts[ml.v1].y;
	wl->p2.x = verts[ml.v2].x;
	wl->p2.y = verts[ml.v2].y;

	wl->special = ml.special;
	wl->tag = ml.tag;
	wl->flags = ml.flags;

/*
				 set remaining fields in worldline_t structure based on info already
				 read from WAD....sectors, sidedefs, etc.
*/

	for (i=0 ; i<=  ( (wl->flags&ML_TWOSIDED) != 0) ; i++)
		{
		s = &wl->side[i];
		ms = &sides[ml.sidenum[i]];
		s->firstrow = ms->rowoffset;
		s->firstcollumn = ms->textureoffset;
		strncpy(s->toptexture, ms->toptexture, 8);
		strncpy(s->bottomtexture, ms->bottomtexture, 8);
		strncpy(s->midtexture, ms->midtexture, 8);
		s->midtexture[8] = s->bottomtexture[8] = s->toptexture[8] = '\0';
		s->sectordef = sectorlist + ms->sector;
		s->sector = ms->sector;
		}

	linenum++;
}

/*
===============================================================================
=
=	ReadWADThing
=
=	Reads a THING from a WAD file, as ReadThing does from a DWD file.
===============================================================================
*/
void ReadWADThing(FILE *f, worldthing_t *t)
{
	mapthing_t mt;

	if (fread(&mt, sizeof(mapthing_t), 1, f) != 1)
		Error("\nReadWADThing failure\n");

	t->origin.x = mt.x;
	t->origin.y = mt.y;
	t->angle = mt.angle;
	t->type = mt.type;
	t->options = mt.options;

	return;
}

/*
===============================================================================
=
=	ReadWADSector
=
=	Reads a sector from a WAD file, as ReadSector does from a DWD file.
===============================================================================
*/
void ReadWADSector(FILE *f, sectordef_t *s)
{
	mapsector_t 	ms;

	if (fread(&ms, sizeof(mapsector_t), 1, f) != 1)
		Error("\nReadWADSector failure\n");

	s->floorheight = ms.floorheight;
	s->ceilingheight = ms.ceilingheight;
	strncpy(s->floorflat, ms.floorpic, 8);
	strncpy(s->ceilingflat, ms.ceilingpic, 8);
	s->floorflat[8] = '\0';
	s->ceilingflat[8] = '\0';
	s->lightlevel = ms.lightlevel;
	s->special = ms.special;
	s->tag = ms.tag;

	return;
}

