/*
	model.h

	(description)

	Copyright (C) 1996-1997  Id Software, Inc.

	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:

		Free Software Foundation, Inc.
		59 Temple Place - Suite 330
		Boston, MA  02111-1307, USA

	$Id: model.h,v 1.33 2004/02/23 07:17:40 taniwha Exp $
*/

#ifndef _MODEL_H
#define _MODEL_H

#include "QF/qtypes.h"
#include "QF/bspfile.h"
#include "QF/spritegn.h"
#include "QF/modelgen.h"
#include "QF/zone.h"

/*
	d*_t structures are on-disk representations
	m*_t structures are in-memory
*/

// entity effects =============================================================

#define	EF_BRIGHTFIELD	1
#define	EF_MUZZLEFLASH 	2
#define	EF_BRIGHTLIGHT 	4
#define	EF_DIMLIGHT 	8
#define	EF_FLAG1	 	16
#define	EF_FLAG2	 	32
#define EF_BLUE			64
#define EF_RED			128

// BRUSH MODELS ===============================================================

typedef struct efrag_s
{
	struct mleaf_s		*leaf;
	struct efrag_s		*leafnext;
	struct entity_s		*entity;
	struct efrag_s		*entnext;
} efrag_t;


// in memory representation ===================================================

// !!! if this is changed, it must be changed in asm_draw.h too !!!
typedef struct
{
	vec3_t		position;
} mvertex_t;

typedef struct texture_s
{
	char		name[16];
	unsigned int	width, height;
	int			gl_texturenum;
	int			gl_fb_texturenum;
	struct msurface_s	*texturechain;	// for gl_texsort drawing
	struct msurface_s	**texturechain_tail;
	int			anim_total;				// total tenths in sequence ( 0 = no)
	int			anim_min, anim_max;		// time for this frame min <=time< max
	struct texture_s *anim_next;		// in the animation sequence
	struct texture_s *alternate_anims;	// bmodels in frmae 1 use these
	unsigned int	offsets[MIPLEVELS];		// four mip maps stored
} texture_t;


#define	SURF_PLANEBACK		2
#define	SURF_DRAWSKY		4
#define SURF_DRAWSPRITE		8
#define SURF_DRAWTURB		0x10
#define SURF_DRAWTILED		0x20
#define SURF_DRAWBACKGROUND	0x40
#define SURF_UNDERWATER		0x80
#define SURF_DONTWARP		0x100
#define SURF_DRAWNOALPHA	0x200
#define SURF_DRAWFULLBRIGHT	0x400
#define SURF_LIGHTBOTHSIDES 0x800

// !!! if this is changed, it must be changed in asm_draw.h too !!!
typedef struct
{
	unsigned short	v[2];
	unsigned int	cachededgeoffset;
} medge_t;

typedef struct
{
	float		vecs[2][4];
	float		mipadjust;
	texture_t	*texture;
	int			flags;
} mtexinfo_t;

#define	VERTEXSIZE	7

typedef struct glpoly_s
{
	struct	glpoly_s	*next;
	struct	glpoly_s	*chain;
	struct	glpoly_s	*fb_chain;
	int		numverts;
	int		flags;					// for SURF_UNDERWATER
	float	verts[4][VERTEXSIZE];	// variable sized (xyz s1t1 s2t2)
} glpoly_t;

typedef struct msurface_s
{
	int			visframe;		// should be drawn when node is crossed

	mplane_t	*plane;
	int			flags;

	int			firstedge;	// look up in model->surfedges[], negative numbers
	int			numedges;	// are backwards edges

	struct surfcache_s	*cachespots[MIPLEVELS];

	short		texturemins[2];
	unsigned short extents[2];

	int			light_s, light_t;	// gl lightmap coordinates

	glpoly_t	*polys;				// multiple if warped
	struct	msurface_s	*texturechain;
//	struct msurface_s	*lightmapchain;		// Quake 2 ???

	mtexinfo_t	*texinfo;

// lighting info
	int			dlightframe;
	int			dlightbits;

	int			lightmaptexturenum;
	byte		styles[MAXLIGHTMAPS];
	int			cached_light[MAXLIGHTMAPS];	// values currently used in lightmap
	qboolean	cached_dlight;				// true if dynamic light in cache
	byte		*samples;		// [numstyles*surfsize]
} msurface_t;

typedef struct mnode_s
{
// common with leaf
	int			contents;		// 0, to differentiate from leafs
	int			visframe;		// node needs to be traversed if current

	float		minmaxs[6];		// for bounding box culling

	struct mnode_s	*parent;

// node specific
	mplane_t	*plane;
	struct mnode_s	*children[2];

	unsigned short		firstsurface;
	unsigned short		numsurfaces;
} mnode_t;

typedef struct mleaf_s
{
// common with node
	int			contents;		// wil be a negative contents number
	int			visframe;		// node needs to be traversed if current

	// for bounding box culling
	float		mins[3];
	float		maxs[3];

	struct mnode_s	*parent;

// leaf specific
	byte		*compressed_vis;
	efrag_t		*efrags;

	msurface_t	**firstmarksurface;
	int			nummarksurfaces;
	int			key;			// BSP sequence number for leaf's contents
	byte		ambient_sound_level[NUM_AMBIENTS];
} mleaf_t;

// !!! if this is changed, it must be changed in asm_i386.h too !!!
typedef struct hull_s
{
	dclipnode_t	*clipnodes;
	mplane_t	*planes;
	int			firstclipnode;
	int			lastclipnode;
	vec3_t		clip_mins;
	vec3_t		clip_maxs;
} hull_t;

// SPRITE MODELS ==============================================================

// FIXME: shorten these?
typedef struct mspriteframe_s
{
	int		width;
	int		height;
	float	up, down, left, right;
	byte	pixels[4];
	int		gl_texturenum;
} mspriteframe_t;

typedef struct
{
	int				numframes;
	float			*intervals;
	mspriteframe_t	*frames[1];
} mspritegroup_t;

typedef struct
{
	spriteframetype_t	type;
	mspriteframe_t		*frameptr;
} mspriteframedesc_t;

typedef struct
{
	int					type;
	int					maxwidth;
	int					maxheight;
	int					numframes;
	float				beamlength;		// remove?
	void				*cachespot;		// remove?
	mspriteframedesc_t	frames[1];
} msprite_t;


// ALIAS MODELS ===============================================================
// Alias models are position independent, so the cache manager can move them.

// NOTE: the first three lines must match maliasgroupframedesc_t
typedef struct
{
	trivertx_t			bboxmin;
	trivertx_t			bboxmax;
	int					frame;
	aliasframetype_t	type;
	int					firstpose;
	int					numposes;
	float				interval;
	char				name[16];
} maliasframedesc_t;

typedef struct
{
	aliasskintype_t		type;
	int					skin;
	int					texnum;
	int					fb_texnum;
} maliasskindesc_t;

typedef struct
{
	trivertx_t			bboxmin;
	trivertx_t			bboxmax;
	int					frame;
} maliasgroupframedesc_t;

typedef struct
{
	int						numframes;
	int						intervals;
	maliasgroupframedesc_t	frames[1];
} maliasgroup_t;

typedef struct
{
	int					numskins;
	int					intervals;
	maliasskindesc_t	skindescs[1];
} maliasskingroup_t;

// !!! if this is changed, it must be changed in asm_draw.h too !!!
typedef struct mtriangle_s {
	int					facesfront;
	int					vertindex[3];
} mtriangle_t;


#define	MAX_SKINS	32
typedef struct {
	int			model;
	int			stverts;
	int			skindesc;
	int			triangles;

	mdl_t		mdl;
	int			tex_coord;
	int			numposes;
	int			poseverts;
	int			posedata;	// numposes * poseverts trivert_t
	int			commands;	// gl command list with embedded s/t

	unsigned short crc;

	maliasframedesc_t	frames[1];
} aliashdr_t;

#define	MAXALIASFRAMES	256
extern	aliashdr_t	*pheader;
extern	stvert_t	*stverts;
extern	mtriangle_t	*triangles;
extern	trivertx_t	*poseverts[MAXALIASFRAMES];
extern  int			 aliasbboxmins[3];
extern  int			 aliasbboxmaxs[3];

// Whole model ================================================================

typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t;

#define	EF_ROCKET		1			// leave a trail
#define	EF_GRENADE		2			// leave a trail
#define	EF_GIB			4			// leave a trail
#define	EF_ROTATE		8			// rotate (bonus items)
#define	EF_TRACER		16			// green split trail
#define	EF_ZOMGIB		32			// small blood trail
#define	EF_TRACER2		64			// orange split trail + rotate
#define	EF_TRACER3		128			// purple trail
#define EF_GLOWTRAIL	4096		// glowcolor particle trail

typedef struct model_s
{
	char		 name[MAX_QPATH];
	qboolean	 needload;		// bmodels and sprites don't cache normally
	qboolean	 hasfullbrights;

	modtype_t	 type;
	int			 numframes;
	synctype_t	 synctype;

	int			 flags;

// lighting info
	float		 min_light;
	byte		 shadow_alpha;	// 255 = 1.0
	byte		 fullbright;

// coarse cull, for fine culling, axis-aligned bbox isn't good enough
	float		 radius;
// FIXME: bbox cruft has to stay until sw rendering gets updated
	vec3_t		 mins, maxs;

// solid volume for clipping
	qboolean	 clipbox;
	vec3_t		 clipmins, clipmaxs;

// brush model
	int			 firstmodelsurface, nummodelsurfaces;

	int			 numsubmodels;
	dmodel_t	*submodels;

	int			 numplanes;
	mplane_t	*planes;

	int			 numleafs;		// number of visible leafs, not counting 0
	mleaf_t		*leafs;

	int			 numvertexes;
	mvertex_t	*vertexes;

	int			 numedges;
	medge_t		*edges;

	int			 numnodes;
	mnode_t		*nodes;

	int			 numtexinfo;
	mtexinfo_t	*texinfo;

	int			 numsurfaces;
	msurface_t	*surfaces;

	int			 numsurfedges;
	int			*surfedges;

	int			 numclipnodes;
	dclipnode_t	*clipnodes;

	int			 nummarksurfaces;
	msurface_t	**marksurfaces;

	hull_t		 hulls[MAX_MAP_HULLS];

	int			 numtextures;
	texture_t	**textures;

	byte		*visdata;
	byte		*lightdata;
	char		*entities;

	unsigned int checksum;
	unsigned int checksum2;

// additional model data
	cache_user_t cache;		// only access through Mod_Extradata
} model_t;

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

extern float RadiusFromBounds (const vec3_t mins, const vec3_t maxs);
void	Mod_Init (void);
void	Mod_Init_Cvars (void);
void	Mod_ClearAll (void);
model_t *Mod_ForName (const char *name, qboolean crash);
void	*Mod_Extradata (model_t *mod);	// handles caching
void	Mod_TouchModel (const char *name);

mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model);
byte	*Mod_LeafPVS (mleaf_t *leaf, model_t *model);
model_t	*Mod_FindName (const char *name);
void	Mod_ProcessTexture(miptex_t *mt, texture_t *tx);
void	Mod_LoadExternalSkins (model_t * mod);
void	Mod_LoadExternalTextures (model_t * mod);
void	Mod_LoadLighting (lump_t *l);
int     Mod_CalcFullbright (byte *in, byte *out, int pixels);
int     Mod_Fullbright (byte * skin, int width, int height, char *name);

void    *Mod_LoadAliasFrame (void *pin, int *posenum, maliasframedesc_t *frame,
							 int extra);
void    *Mod_LoadAliasGroup (void *pin, int *posenum, maliasframedesc_t *frame,
							 int extra);
void	*Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum,
					   qboolean group, maliasskindesc_t *skindesc);
void     Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m,
										 int _s, int extra);
void	 Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr);
void	 Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum);

void	 Mod_LoadBrushModel (model_t *mod, void *buffer);
void	 Mod_LoadAliasModel (model_t *mod, void *buffer,
							 cache_allocator_t allocator);
void	 Mod_LoadAlias2Model (model_t *mod, void *buffer,
							 cache_allocator_t allocator);
void	 Mod_LoadSpriteModel (model_t *mod, void *buffer);
void	 Mod_LoadSprite2Model (model_t *mod, void *buffer);
void	 Mod_SubdivideSurface (msurface_t *fa);

void	 Mod_Print (void);

extern struct cvar_s *gl_mesh_cache;
extern struct cvar_s *gl_subdivide_size;
extern struct cvar_s *gl_alias_render_tri;
extern struct cvar_s *gl_textures_external;
extern model_t *loadmodel;
extern char *loadname;
extern byte *mod_base;
extern byte mod_novis[MAX_MAP_LEAFS / 8];
extern int mod_lightmap_bytes;

#endif	// _MODEL_H
