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

Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.

This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).

Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

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

#include "../../../renderer/tr_local.h"


typedef struct primitive_s
{
	struct primitive_s* next;
	
	// only one of these will be non-NULL
	struct bspbrush_s* 	brush;
	struct mapTri_s* 	tris;
} primitive_t;


typedef struct
{
	struct optimizeGroup_s*	groups;
	// we might want to add other fields later
} uArea_t;

typedef struct
{
	idMapEntity* 		mapEntity;		// points into mapFile_t data
	
	idVec3				origin;
	primitive_t* 		primitives;
	struct tree_s* 		tree;
	
	int					numAreas;
	uArea_t* 			areas;
} uEntity_t;


// chains of mapTri_t are the general unit of processing
typedef struct mapTri_s
{
	struct mapTri_s* 	next;
	
	const idMaterial* 	material;
	void* 				mergeGroup;		// we want to avoid merging triangles
	// from different fixed groups, like guiSurfs and mirrors
	int					planeNum;			// not set universally, just in some areas
	
	idDrawVert			v[3];
	const struct hashVert_s* hashVert[3];
	struct optVertex_s* optVert[3];
} mapTri_t;


typedef struct
{
	int					width, height;
	idDrawVert* 		verts;
} mesh_t;


#define	MAX_PATCH_SIZE	32

#define	PLANENUM_LEAF		-1

typedef struct parseMesh_s
{
	struct parseMesh_s* next;
	mesh_t				mesh;
	const idMaterial* 	material;
} parseMesh_t;

typedef struct bspface_s
{
	struct bspface_s* 	next;
	int					planenum;
	bool				portal;			// all portals will be selected before
	// any non-portals
	bool				checked;		// used by SelectSplitPlaneNum()
	idWinding* 			w;
} bspface_t;

typedef struct
{
	idVec4		v[2];		// the offset value will always be in the 0.0 to 1.0 range
} textureVectors_t;

typedef struct side_s
{
	int					planenum;
	
	const idMaterial* 	material;
	textureVectors_t	texVec;
	
	idWinding* 			winding;		// only clipped to the other sides of the brush
	idWinding* 			visibleHull;	// also clipped to the solid parts of the world
} side_t;


typedef struct bspbrush_s
{
	struct bspbrush_s* 	next;
	struct bspbrush_s* 	original;	// chopped up brushes will reference the originals
	
	int					entitynum;			// editor numbering for messages
	int					brushnum;			// editor numbering for messages
	
	const idMaterial* 	contentShader;	// one face's shader will determine the volume attributes
	
	int					contents;
	bool				opaque;
	int					outputNumber;		// set when the brush is written to the file list
	
	idBounds			bounds;
	int					numsides;
	side_t				sides[6];			// variably sized
} uBrush_t;


typedef struct drawSurfRef_s
{
	struct drawSurfRef_s* 	nextRef;
	int						outputNumber;
} drawSurfRef_t;


typedef struct node_s
{
	// both leafs and nodes
	int					planenum;	// -1 = leaf node
	struct node_s* 		parent;
	idBounds			bounds;		// valid after portalization
	
	// nodes only
	side_t* 			side;		// the side that created the node
	struct node_s* 		children[2];
	int					nodeNumber;	// set after pruning
	
	// leafs only
	bool				opaque;		// view can never be inside
	
	uBrush_t* 			brushlist;	// fragments of all brushes in this leaf
	// needed for FindSideForPortal
	
	int					area;		// determined by flood filling up to areaportals
	int					occupied;	// 1 or greater can reach entity
	uEntity_t* 			occupant;	// for leak file testing
	
	struct uPortal_s* 	portals;	// also on nodes during construction
} node_t;


typedef struct uPortal_s
{
	idPlane		plane;
	node_t*		onnode;		// NULL = outside box
	node_t*		nodes[2];		// [0] = front side of plane
	struct uPortal_s*	next[2];
	idWinding*	winding;
} uPortal_t;

// a tree_t is created by FaceBSP()
typedef struct tree_s
{
	node_t*		headnode;
	node_t		outside_node;
	idBounds	bounds;
} tree_t;

#define	MAX_QPATH			256			// max length of a game pathname

typedef struct
{
	idRenderLightLocal	def;
	char				name[MAX_QPATH];		// for naming the shadow volume surface and interactions
	srfTriangles_t*		shadowTris;
	
	idPlane				frustumPlanes[6];		// RB: should be calculated after R_DeriveLightData()
} mapLight_t;

#define	MAX_GROUP_LIGHTS	16

typedef struct optimizeGroup_s
{
	struct optimizeGroup_s*	nextGroup;
	
	idBounds			bounds;			// set in CarveGroupsByLight
	
	// all of these must match to add a triangle to the triList
	bool				smoothed;				// curves will never merge with brushes
	int					planeNum;
	int					areaNum;
	const idMaterial* 	material;
	int					numGroupLights;
	mapLight_t* 		groupLights[MAX_GROUP_LIGHTS];	// lights effecting this list
	void* 				mergeGroup;		// if this differs (guiSurfs, mirrors, etc), the
	// groups will not be combined into model surfaces
	// after optimization
	textureVectors_t	texVec;
	
	bool				surfaceEmited;
	
	mapTri_t* 			triList;
	mapTri_t* 			regeneratedTris;	// after each island optimization
	idVec3				axis[2];			// orthogonal to the plane, so optimization can be 2D
} optimizeGroup_t;

// all primitives from the map are added to optimzeGroups, creating new ones as needed
// each optimizeGroup is then split into the map areas, creating groups in each area
// each optimizeGroup is then divided by each light, creating more groups
// the final list of groups is then tjunction fixed against all groups, then optimized internally
// multiple optimizeGroups will be merged together into .proc surfaces, but no further optimization
// is done on them


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

// dmap.cpp

typedef enum
{
	SO_NONE,			// 0
	SO_MERGE_SURFACES,	// 1
	SO_CULL_OCCLUDED,	// 2
	SO_CLIP_OCCLUDERS,	// 3
	SO_CLIP_SILS,		// 4
	SO_SIL_OPTIMIZE		// 5
} shadowOptLevel_t;

typedef struct
{
	// mapFileBase will contain the qpath without any extension: "maps/test_box"
	char		mapFileBase[1024];
	
	idMapFile*	dmapFile;
	
	idPlaneSet	mapPlanes;
	
	int			num_entities;
	uEntity_t*	uEntities;
	
	int			entityNum;
	
	idList<mapLight_t*>	mapLights;
	
	bool	verbose;
	
	bool	glview;
	bool	noOptimize;
	bool	verboseentities;
	bool	noCurves;
	bool	fullCarve;
	bool	noModelBrushes;
	bool	noTJunc;
	bool	nomerge;
	bool	noFlood;
	bool	noClipSides;		// don't cut sides by solid leafs, use the entire thing
	bool	noLightCarve;		// extra triangle subdivision by light frustums
	shadowOptLevel_t	shadowOptLevel;
	bool	noShadow;			// don't create optimized shadow volumes
	
	idBounds	drawBounds;
	bool	drawflag;
	
	int		totalShadowTriangles;
	int		totalShadowVerts;
} dmapGlobals_t;

extern dmapGlobals_t dmapGlobals;

int FindFloatPlane( const idPlane& plane, bool* fixedDegeneracies = NULL );


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

// brush.cpp

#ifndef CLIP_EPSILON
#define	CLIP_EPSILON	0.1f
#endif

#define	PSIDE_FRONT			1
#define	PSIDE_BACK			2
#define	PSIDE_BOTH			(PSIDE_FRONT|PSIDE_BACK)
#define	PSIDE_FACING		4

int	CountBrushList( uBrush_t* brushes );
uBrush_t* AllocBrush( int numsides );
void FreeBrush( uBrush_t* brushes );
void FreeBrushList( uBrush_t* brushes );
uBrush_t* CopyBrush( uBrush_t* brush );
void DrawBrushList( uBrush_t* brush );
void PrintBrush( uBrush_t* brush );
bool BoundBrush( uBrush_t* brush );
bool CreateBrushWindings( uBrush_t* brush );
uBrush_t*	BrushFromBounds( const idBounds& bounds );
float BrushVolume( uBrush_t* brush );
void WriteBspBrushMap( const char* name, uBrush_t* list );

void FilterBrushesIntoTree( uEntity_t* e );

void SplitBrush( uBrush_t* brush, int planenum, uBrush_t** front, uBrush_t** back );
node_t* AllocNode();


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

// map.cpp

bool 		LoadDMapFile( const char* filename );
void		FreeOptimizeGroupList( optimizeGroup_t* groups );
void		FreeDMapFile();

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

// draw.cpp -- draw debug views either directly, or through glserv.exe

void Draw_ClearWindow();
void DrawWinding( const idWinding* w );
void DrawAuxWinding( const idWinding* w );

void DrawLine( idVec3 v1, idVec3 v2, int color );

void GLS_BeginScene();
void GLS_Winding( const idWinding* w, int code );
void GLS_Triangle( const mapTri_t* tri, int code );
void GLS_EndScene();



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

// portals.cpp

#define	MAX_INTER_AREA_PORTALS	1024

typedef struct
{
	int		area0, area1;
	side_t*	side;
} interAreaPortal_t;

extern	interAreaPortal_t interAreaPortals[MAX_INTER_AREA_PORTALS];
extern	int					numInterAreaPortals;

bool FloodEntities( tree_t* tree );
void FillOutside( uEntity_t* e );
void FloodAreas( uEntity_t* e );
void MakeTreePortals( tree_t* tree );
void FreePortal( uPortal_t* p );

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

// glfile.cpp -- write a debug file to be viewd with glview.exe

void OutputWinding( idWinding* w, idFile* glview );
void WriteGLView( tree_t* tree, char* source );

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

// leakfile.cpp

void LeakFile( tree_t* tree );

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

// facebsp.cpp

tree_t* AllocTree();

void FreeTree( tree_t* tree );

void FreeTree_r( node_t* node );
void FreeTreePortals_r( node_t* node );


bspface_t*	MakeStructuralBspFaceList( primitive_t* list );
bspface_t*	MakeVisibleBspFaceList( primitive_t* list );
tree_t*		FaceBSP( bspface_t* list );

node_t*		NodeForPoint( node_t* node, const idVec3& origin );

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

// surface.cpp

mapTri_t* CullTrisInOpaqueLeafs( mapTri_t* triList, tree_t* tree );
void	ClipSidesByTree( uEntity_t* e );
void	SplitTrisToSurfaces( mapTri_t* triList, tree_t* tree );
void	PutPrimitivesInAreas( uEntity_t* e );
void	Prelight( uEntity_t* e );

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

// tritjunction.cpp

struct hashVert_s*	GetHashVert( idVec3& v );
void	HashTriangles( optimizeGroup_t* groupList );
void	FreeTJunctionHash();
int		CountGroupListTris( const optimizeGroup_t* groupList );
void	FixEntityTjunctions( uEntity_t* e );
void	FixAreaGroupsTjunctions( optimizeGroup_t* groupList );
void	FixGlobalTjunctions( uEntity_t* e );

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

// optimize.cpp -- triangle mesh reoptimization

// the shadow volume optimizer call internal optimizer routines, normal triangles
// will just be done by OptimizeEntity()


typedef struct optVertex_s
{
	idDrawVert	v;
	idVec3	pv;					// projected against planar axis, third value is 0
	struct optEdge_s* edges;
	struct optVertex_s*	islandLink;
	bool	addedToIsland;
	bool	emited;			// when regenerating triangles
} optVertex_t;

typedef struct optEdge_s
{
	optVertex_t*	v1, *v2;
	struct optEdge_s*	islandLink;
	bool	addedToIsland;
	bool	created;		// not one of the original edges
	bool	combined;		// combined from two or more colinear edges
	struct optTri_s*	frontTri, *backTri;
	struct optEdge_s* v1link, *v2link;
} optEdge_t;

typedef struct optTri_s
{
	struct optTri_s*	next;
	idVec3		midpoint;
	optVertex_t*	v[3];
	bool	filled;
} optTri_t;

typedef struct
{
	optimizeGroup_t*	group;
	optVertex_t*	verts;
	optEdge_t*	edges;
	optTri_t*	tris;
} optIsland_t;


void	OptimizeEntity( uEntity_t* e );
void	OptimizeGroupList( optimizeGroup_t* groupList );

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

// tritools.cpp

mapTri_t*	AllocTri();
void		FreeTri( mapTri_t* tri );
int			CountTriList( const mapTri_t* list );
mapTri_t*	MergeTriLists( mapTri_t* a, mapTri_t* b );
mapTri_t*	CopyTriList( const mapTri_t* a );
void		FreeTriList( mapTri_t* a );
mapTri_t*	CopyMapTri( const mapTri_t* tri );
float		MapTriArea( const mapTri_t* tri );
mapTri_t*	RemoveBadTris( const mapTri_t* tri );
void		BoundTriList( const mapTri_t* list, idBounds& b );
void		DrawTri( const mapTri_t* tri );
void		FlipTriList( mapTri_t* tris );
void		TriVertsFromOriginal( mapTri_t* tri, const mapTri_t* original );
void		PlaneForTri( const mapTri_t* tri, idPlane& plane );
idWinding*	WindingForTri( const mapTri_t* tri );
mapTri_t*	WindingToTriList( const idWinding* w, const mapTri_t* originalTri );
void		ClipTriList( const mapTri_t* list, const idPlane& plane, float epsilon, mapTri_t** front, mapTri_t** back );

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

// output.cpp

srfTriangles_t*	ShareMapTriVerts( const mapTri_t* tris );
void WriteOutputFile();

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

// shadowopt.cpp

srfTriangles_t* CreateLightShadow( optimizeGroup_t* shadowerGroups, const mapLight_t* light );
void		FreeBeamTree( struct beamTree_s* beamTree );

void		CarveTriByBeamTree( const struct beamTree_s* beamTree, const mapTri_t* tri, mapTri_t** lit, mapTri_t** unLit );
