/*
Copyright (C) 1996-2001 Id Software, Inc.
Copyright (C) 2002-2009 John Fitzgibbons and others
Copyright (C) 2010-2014 QuakeSpasm developers

This program 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 2
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#ifndef __BSPFILE_H
#define __BSPFILE_H

// upper design bounds

#define MAX_MAP_HULLS 4

#define MAX_MAP_MODELS	  256
#define MAX_MAP_BRUSHES	  4096
#define MAX_MAP_ENTITIES  1024
#define MAX_MAP_ENTSTRING 65536

#define MAX_MAP_PLANES		 32767
#define MAX_MAP_NODES		 32767 // because negative shorts are contents
#define MAX_MAP_CLIPNODES	 32767
// #define	MAX_MAP_LEAFS		80000 //johnfitz -- was 8192
#define MAX_MAP_VERTS		 65535
#define MAX_MAP_FACES		 65535
#define MAX_MAP_MARKSURFACES 65535
#define MAX_MAP_TEXINFO		 4096
#define MAX_MAP_EDGES		 256000
#define MAX_MAP_SURFEDGES	 512000
#define MAX_MAP_TEXTURES	 512
#define MAX_MAP_MIPTEX		 0x200000
#define MAX_MAP_LIGHTING	 0x100000
#define MAX_MAP_VISIBILITY	 0x100000

#define MAX_MAP_PORTALS 65536

// key / value pair sizes

#define MAX_KEY	  32
#define MAX_VALUE 1024

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

#define BSPVERSION 29

#ifdef BSP29_VALVE
#define BSPVERSION_VALVE 30
#endif

/* RMQ support (2PSB). 32bits instead of shorts for all but bbox sizes (which
 * still use shorts) */
#define BSP2VERSION_2PSB (('B' << 24) | ('S' << 16) | ('P' << 8) | '2')

/* BSP2 support. 32bits instead of shorts for everything (bboxes use floats) */
#define BSP2VERSION_BSP2 (('B' << 0) | ('S' << 8) | ('P' << 16) | ('2' << 24))

// Quake64
#define BSPVERSION_QUAKE64 (('Q' << 24) | ('6' << 16) | ('4' << 8) | ' ')

#define TOOLVERSION 2

typedef struct
{
	int fileofs, filelen;
} lump_t;

#define LUMP_ENTITIES	  0
#define LUMP_PLANES		  1
#define LUMP_TEXTURES	  2
#define LUMP_VERTEXES	  3
#define LUMP_VISIBILITY	  4
#define LUMP_NODES		  5
#define LUMP_TEXINFO	  6
#define LUMP_FACES		  7
#define LUMP_LIGHTING	  8
#define LUMP_CLIPNODES	  9
#define LUMP_LEAFS		  10
#define LUMP_MARKSURFACES 11
#define LUMP_EDGES		  12
#define LUMP_SURFEDGES	  13
#define LUMP_MODELS		  14

#define HEADER_LUMPS 15

typedef struct
{
	float mins[3], maxs[3];
	float origin[3];
	int	  headnode[MAX_MAP_HULLS];
	int	  visleafs; // not including the solid leaf 0
	int	  firstface, numfaces;
} dmodel_t;

typedef struct
{
	int	   version;
	lump_t lumps[HEADER_LUMPS];
} dheader_t;

typedef struct
{
	int nummiptex;
	int dataofs[4]; // [nummiptex]
} dmiptexlump_t;

#define MIPLEVELS 4
typedef struct miptex_s
{
	char	 name[16];
	unsigned width, height;
	unsigned offsets[MIPLEVELS]; // four mip maps stored
} miptex_t;

// Quake64
typedef struct miptex64_s
{
	char	 name[16];
	unsigned width, height;
	unsigned shift;
	unsigned offsets[MIPLEVELS]; // four mip maps stored
} miptex64_t;

typedef struct
{
	float point[3];
} dvertex_t;

// 0-2 are axial planes
#define PLANE_X 0
#define PLANE_Y 1
#define PLANE_Z 2

// 3-5 are non-axial planes snapped to the nearest
#define PLANE_ANYX 3
#define PLANE_ANYY 4
#define PLANE_ANYZ 5

typedef struct
{
	float normal[3];
	float dist;
	int	  type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
} dplane_t;

#define CONTENTS_EMPTY	-1
#define CONTENTS_SOLID	-2
#define CONTENTS_WATER	-3
#define CONTENTS_SLIME	-4
#define CONTENTS_LAVA	-5
#define CONTENTS_SKY	-6
#define CONTENTS_ORIGIN -7 // removed at csg time
#define CONTENTS_CLIP	-8 // changed to contents_solid

#define CONTENTS_CURRENT_0	  -9
#define CONTENTS_CURRENT_90	  -10
#define CONTENTS_CURRENT_180  -11
#define CONTENTS_CURRENT_270  -12
#define CONTENTS_CURRENT_UP	  -13
#define CONTENTS_CURRENT_DOWN -14

// !!! if this is changed, it must be changed in asm_i386.h too !!!
typedef struct
{
	int			   planenum;
	short		   children[2]; // negative numbers are -(leafs+1), not nodes
	short		   mins[3];		// for sphere culling
	short		   maxs[3];
	unsigned short firstface;
	unsigned short numfaces; // counting both sides
} dsnode_t;

typedef struct
{
	int			 planenum;
	int			 children[2]; // negative numbers are -(leafs+1), not nodes
	short		 mins[3];	  // for sphere culling
	short		 maxs[3];
	unsigned int firstface;
	unsigned int numfaces; // counting both sides
} dl1node_t;

typedef struct
{
	int			 planenum;
	int			 children[2]; // negative numbers are -(leafs+1), not nodes
	float		 mins[3];	  // for sphere culling
	float		 maxs[3];
	unsigned int firstface;
	unsigned int numfaces; // counting both sides
} dl2node_t;

typedef struct
{
	int	  planenum;
	short children[2]; // negative numbers are contents
} dsclipnode_t;

typedef struct
{
	int planenum;
	int children[2]; // negative numbers are contents
} dlclipnode_t;

typedef struct texinfo_s
{
	float vecs[2][4]; // [s/t][xyz offset]
	int	  miptex;
	int	  flags;
} texinfo_t;
#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
#define TEX_MISSING 2 // johnfitz -- this texinfo does not have a texture

// note that edge 0 is never used, because negative edge nums are used for
// counterclockwise use of the edge in a face
typedef struct
{
	unsigned short v[2]; // vertex numbers
} dsedge_t;

typedef struct
{
	unsigned int v[2]; // vertex numbers
} dledge_t;

#define MAXLIGHTMAPS 4
typedef struct
{
	short planenum;
	short side;

	int	  firstedge; // we must support > 64k edges
	short numedges;
	short texinfo;

	// lighting info
	byte styles[MAXLIGHTMAPS];
	int	 lightofs; // start of [numstyles*surfsize] samples
} dsface_t;

typedef struct
{
	int planenum;
	int side;

	int firstedge; // we must support > 64k edges
	int numedges;
	int texinfo;

	// lighting info
	byte styles[MAXLIGHTMAPS];
	int	 lightofs; // start of [numstyles*surfsize] samples
} dlface_t;

#define AMBIENT_WATER 0
#define AMBIENT_SKY	  1
#define AMBIENT_SLIME 2
#define AMBIENT_LAVA  3

#define NUM_AMBIENTS 4 // automatic ambient sounds

// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas
// all other leafs need visibility info
typedef struct
{
	int contents;
	int visofs; // -1 = no visibility info

	short mins[3]; // for frustum culling
	short maxs[3];

	unsigned short firstmarksurface;
	unsigned short nummarksurfaces;

	byte ambient_level[NUM_AMBIENTS];
} dsleaf_t;

typedef struct
{
	int contents;
	int visofs; // -1 = no visibility info

	short mins[3]; // for frustum culling
	short maxs[3];

	unsigned int firstmarksurface;
	unsigned int nummarksurfaces;

	byte ambient_level[NUM_AMBIENTS];
} dl1leaf_t;

typedef struct
{
	int contents;
	int visofs; // -1 = no visibility info

	float mins[3]; // for frustum culling
	float maxs[3];

	unsigned int firstmarksurface;
	unsigned int nummarksurfaces;

	byte ambient_level[NUM_AMBIENTS];
} dl2leaf_t;

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

#ifndef QUAKE_GAME

#define ANGLE_UP   -1
#define ANGLE_DOWN -2

// the utilities get to be lazy and just use large static arrays

extern int		nummodels;
extern dmodel_t dmodels[MAX_MAP_MODELS];

extern int	visdatasize;
extern byte dvisdata[MAX_MAP_VISIBILITY];

extern int	lightdatasize;
extern byte dlightdata[MAX_MAP_LIGHTING];

extern int	texdatasize;
extern byte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t)

extern int	entdatasize;
extern char dentdata[MAX_MAP_ENTSTRING];

// extern	int			numleafs;
// extern	dleaf_t		dleafs[MAX_MAP_LEAFS];

extern int		numplanes;
extern dplane_t dplanes[MAX_MAP_PLANES];

extern int		 numvertexes;
extern dvertex_t dvertexes[MAX_MAP_VERTS];

extern int	   numnodes;
extern dnode_t dnodes[MAX_MAP_NODES];

extern int		 numtexinfo;
extern texinfo_t texinfo[MAX_MAP_TEXINFO];

extern int	   numfaces;
extern dface_t dfaces[MAX_MAP_FACES];

extern int		   numclipnodes;
extern dclipnode_t dclipnodes[MAX_MAP_CLIPNODES];

extern int	   numedges;
extern dedge_t dedges[MAX_MAP_EDGES];

extern int			  nummarksurfaces;
extern unsigned short dmarksurfaces[MAX_MAP_MARKSURFACES];

extern int numsurfedges;
extern int dsurfedges[MAX_MAP_SURFEDGES];

void DecompressVis (byte *in, byte *decompressed);
int	 CompressVis (byte *vis, byte *dest);

void LoadBSPFile (char *filename);
void WriteBSPFile (char *filename);
void PrintBSPFileSizes (void);

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

typedef struct epair_s
{
	struct epair_s *next;
	char		   *key;
	char		   *value;
} epair_t;

typedef struct
{
	vec3_t	 origin;
	int		 firstbrush;
	int		 numbrushes;
	epair_t *epairs;
} entity_t;

extern int		num_entities;
extern entity_t entities[MAX_MAP_ENTITIES];

void ParseEntities (void);
void UnparseEntities (void);

void  SetKeyValue (entity_t *ent, char *key, char *value);
char *ValueForKey (entity_t *ent, char *key);
// will return "" if not present

vec_t FloatForKey (entity_t *ent, char *key);
void  GetVectorForKey (entity_t *ent, char *key, vec3_t vec);

epair_t *ParseEpair (void);

#endif /* QUAKE_GAME */

#endif /* __BSPFILE_H */
