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

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.

*/

#pragma once

#include "quakeglm_qvec3.hpp"
#include "q_stdinc.hpp"
#include "quakedef_macros.hpp"

// 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

/* 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))

#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;
} mmodel_t;

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

// QSS
typedef struct
{
    float mins[3], maxs[3];
    float origin[3];
    int headnode[8];
    int visleafs; // not including the solid leaf 0
    int firstface, numfaces;
} dmodelh2_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;


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

// QSS
#define CONTENTS_LADDER -16


// !!! 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 16

// QSS
#define INVALID_LIGHTSTYLE 0xffffu
#define INVALID_LIGHTSTYLE_OLD 0xffu

typedef struct
{
    short planenum;
    short side;

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

    // lighting info
    byte styles[4];
    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[4];
    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 mmodel_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 dsnode_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();

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

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

struct entitybsp_t
{
    qvec3 origin;
    int firstbrush;
    int numbrushes;
    epair_t* epairs;
};

extern int num_entities;
extern entitybsp_t entities[MAX_MAP_ENTITIES];

#endif /* QUAKE_GAME */
