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

Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.

This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").

Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Doom 3 BFG Edition 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 BFG Edition 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.

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

#ifndef __LWO2_H__
#define __LWO2_H__

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

	LWO2 loader. (LightWave Object)

	Ernie Wright  17 Sep 00

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

/* chunk and subchunk IDs */

#define LWID_(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d))

#define ID_FORM  LWID_('F','O','R','M')
#define ID_LWO2  LWID_('L','W','O','2')
#define ID_LWOB  LWID_('L','W','O','B')

/* top-level chunks */
#define ID_LAYR  LWID_('L','A','Y','R')
#define ID_TAGS  LWID_('T','A','G','S')
#define ID_PNTS  LWID_('P','N','T','S')
#define ID_BBOX  LWID_('B','B','O','X')
#define ID_VMAP  LWID_('V','M','A','P')
#define ID_VMAD  LWID_('V','M','A','D')
#define ID_POLS  LWID_('P','O','L','S')
#define ID_PTAG  LWID_('P','T','A','G')
#define ID_ENVL  LWID_('E','N','V','L')
#define ID_CLIP  LWID_('C','L','I','P')
#define ID_SURF  LWID_('S','U','R','F')
#define ID_DESC  LWID_('D','E','S','C')
#define ID_TEXT  LWID_('T','E','X','T')
#define ID_ICON  LWID_('I','C','O','N')

/* polygon types */
#define ID_FACE  LWID_('F','A','C','E')
#define ID_CURV  LWID_('C','U','R','V')
#define ID_PTCH  LWID_('P','T','C','H')
#define ID_MBAL  LWID_('M','B','A','L')
#define ID_BONE  LWID_('B','O','N','E')

/* polygon tags */
#define ID_SURF  LWID_('S','U','R','F')
#define ID_PART  LWID_('P','A','R','T')
#define ID_SMGP  LWID_('S','M','G','P')

/* envelopes */
#define ID_PRE   LWID_('P','R','E',' ')
#define ID_POST  LWID_('P','O','S','T')
#define ID_KEY   LWID_('K','E','Y',' ')
#define ID_SPAN  LWID_('S','P','A','N')
#define ID_TCB   LWID_('T','C','B',' ')
#define ID_HERM  LWID_('H','E','R','M')
#define ID_BEZI  LWID_('B','E','Z','I')
#define ID_BEZ2  LWID_('B','E','Z','2')
#define ID_LINE  LWID_('L','I','N','E')
#define ID_STEP  LWID_('S','T','E','P')

/* clips */
#define ID_STIL  LWID_('S','T','I','L')
#define ID_ISEQ  LWID_('I','S','E','Q')
#define ID_ANIM  LWID_('A','N','I','M')
#define ID_XREF  LWID_('X','R','E','F')
#define ID_STCC  LWID_('S','T','C','C')
#define ID_TIME  LWID_('T','I','M','E')
#define ID_CONT  LWID_('C','O','N','T')
#define ID_BRIT  LWID_('B','R','I','T')
#define ID_SATR  LWID_('S','A','T','R')
#define ID_HUE   LWID_('H','U','E',' ')
#define ID_GAMM  LWID_('G','A','M','M')
#define ID_NEGA  LWID_('N','E','G','A')
#define ID_IFLT  LWID_('I','F','L','T')
#define ID_PFLT  LWID_('P','F','L','T')

/* surfaces */
#define ID_COLR  LWID_('C','O','L','R')
#define ID_LUMI  LWID_('L','U','M','I')
#define ID_DIFF  LWID_('D','I','F','F')
#define ID_SPEC  LWID_('S','P','E','C')
#define ID_GLOS  LWID_('G','L','O','S')
#define ID_REFL  LWID_('R','E','F','L')
#define ID_RFOP  LWID_('R','F','O','P')
#define ID_RIMG  LWID_('R','I','M','G')
#define ID_RSAN  LWID_('R','S','A','N')
#define ID_TRAN  LWID_('T','R','A','N')
#define ID_TROP  LWID_('T','R','O','P')
#define ID_TIMG  LWID_('T','I','M','G')
#define ID_RIND  LWID_('R','I','N','D')
#define ID_TRNL  LWID_('T','R','N','L')
#define ID_BUMP  LWID_('B','U','M','P')
#define ID_SMAN  LWID_('S','M','A','N')
#define ID_SIDE  LWID_('S','I','D','E')
#define ID_CLRH  LWID_('C','L','R','H')
#define ID_CLRF  LWID_('C','L','R','F')
#define ID_ADTR  LWID_('A','D','T','R')
#define ID_SHRP  LWID_('S','H','R','P')
#define ID_LINE  LWID_('L','I','N','E')
#define ID_LSIZ  LWID_('L','S','I','Z')
#define ID_ALPH  LWID_('A','L','P','H')
#define ID_AVAL  LWID_('A','V','A','L')
#define ID_GVAL  LWID_('G','V','A','L')
#define ID_BLOK  LWID_('B','L','O','K')

/* texture layer */
#define ID_TYPE  LWID_('T','Y','P','E')
#define ID_CHAN  LWID_('C','H','A','N')
#define ID_NAME  LWID_('N','A','M','E')
#define ID_ENAB  LWID_('E','N','A','B')
#define ID_OPAC  LWID_('O','P','A','C')
#define ID_FLAG  LWID_('F','L','A','G')
#define ID_PROJ  LWID_('P','R','O','J')
#define ID_STCK  LWID_('S','T','C','K')
#define ID_TAMP  LWID_('T','A','M','P')

/* texture coordinates */
#define ID_TMAP  LWID_('T','M','A','P')
#define ID_AXIS  LWID_('A','X','I','S')
#define ID_CNTR  LWID_('C','N','T','R')
#define ID_SIZE  LWID_('S','I','Z','E')
#define ID_ROTA  LWID_('R','O','T','A')
#define ID_OREF  LWID_('O','R','E','F')
#define ID_FALL  LWID_('F','A','L','L')
#define ID_CSYS  LWID_('C','S','Y','S')

/* image map */
#define ID_IMAP  LWID_('I','M','A','P')
#define ID_IMAG  LWID_('I','M','A','G')
#define ID_WRAP  LWID_('W','R','A','P')
#define ID_WRPW  LWID_('W','R','P','W')
#define ID_WRPH  LWID_('W','R','P','H')
#define ID_VMAP  LWID_('V','M','A','P')
#define ID_AAST  LWID_('A','A','S','T')
#define ID_PIXB  LWID_('P','I','X','B')

/* procedural */
#define ID_PROC  LWID_('P','R','O','C')
#define ID_COLR  LWID_('C','O','L','R')
#define ID_VALU  LWID_('V','A','L','U')
#define ID_FUNC  LWID_('F','U','N','C')
#define ID_FTPS  LWID_('F','T','P','S')
#define ID_ITPS  LWID_('I','T','P','S')
#define ID_ETPS  LWID_('E','T','P','S')

/* gradient */
#define ID_GRAD  LWID_('G','R','A','D')
#define ID_GRST  LWID_('G','R','S','T')
#define ID_GREN  LWID_('G','R','E','N')
#define ID_PNAM  LWID_('P','N','A','M')
#define ID_INAM  LWID_('I','N','A','M')
#define ID_GRPT  LWID_('G','R','P','T')
#define ID_FKEY  LWID_('F','K','E','Y')
#define ID_IKEY  LWID_('I','K','E','Y')

/* shader */
#define ID_SHDR  LWID_('S','H','D','R')
#define ID_DATA  LWID_('D','A','T','A')


/* generic linked list */

typedef struct st_lwNode
{
	struct st_lwNode* next, *prev;
	void* data;
} lwNode;


/* plug-in reference */

typedef struct st_lwPlugin
{
	struct st_lwPlugin* next, *prev;
	char*          ord;
	char*          name;
	int            flags;
	void*          data;
} lwPlugin;


/* envelopes */

typedef struct st_lwKey
{
	struct st_lwKey* next, *prev;
	float          value;
	float          time;
	unsigned int   shape;               /* ID_TCB, ID_BEZ2, etc. */
	float          tension;
	float          continuity;
	float          bias;
	float          param[ 4 ];
} lwKey;

typedef struct st_lwEnvelope
{
	struct st_lwEnvelope* next, *prev;
	int            index;
	int            type;
	char*          name;
	lwKey*         key;                 /* linked list of keys */
	int            nkeys;
	int            behavior[ 2 ];       /* pre and post (extrapolation) */
	lwPlugin*      cfilter;             /* linked list of channel filters */
	int            ncfilters;
} lwEnvelope;

#define BEH_RESET      0
#define BEH_CONSTANT   1
#define BEH_REPEAT     2
#define BEH_OSCILLATE  3
#define BEH_OFFSET     4
#define BEH_LINEAR     5


/* values that can be enveloped */

typedef struct st_lwEParam
{
	float          val;
	int            eindex;
} lwEParam;

typedef struct st_lwVParam
{
	float          val[ 3 ];
	int            eindex;
} lwVParam;


/* clips */

typedef struct st_lwClipStill
{
	char*          name;
} lwClipStill;

typedef struct st_lwClipSeq
{
	char*          prefix;              /* filename before sequence digits */
	char*          suffix;              /* after digits, e.g. extensions */
	int            digits;
	int            flags;
	int            offset;
	int            start;
	int            end;
} lwClipSeq;

typedef struct st_lwClipAnim
{
	char*          name;
	char*          server;              /* anim loader plug-in */
	void*          data;
} lwClipAnim;

typedef struct st_lwClipXRef
{
	char*          string;
	int            index;
	struct st_lwClip* clip;
} lwClipXRef;

typedef struct st_lwClipCycle
{
	char*          name;
	int            lo;
	int            hi;
} lwClipCycle;

typedef struct st_lwClip
{
	struct st_lwClip* next, *prev;
	int            index;
	unsigned int   type;                /* ID_STIL, ID_ISEQ, etc. */
	union
	{
		lwClipStill    still;
		lwClipSeq      seq;
		lwClipAnim     anim;
		lwClipXRef     xref;
		lwClipCycle    cycle;
	}              source;
	float          start_time;
	float          duration;
	float          frame_rate;
	lwEParam       contrast;
	lwEParam       brightness;
	lwEParam       saturation;
	lwEParam       hue;
	lwEParam       gamma;
	int            negative;
	lwPlugin*      ifilter;             /* linked list of image filters */
	int            nifilters;
	lwPlugin*      pfilter;             /* linked list of pixel filters */
	int            npfilters;
} lwClip;


/* textures */

typedef struct st_lwTMap
{
	lwVParam       size;
	lwVParam       center;
	lwVParam       rotate;
	lwVParam       falloff;
	int            fall_type;
	char*          ref_object;
	int            coord_sys;
} lwTMap;

typedef struct st_lwImageMap
{
	int            cindex;
	int            projection;
	char*          vmap_name;
	int            axis;
	int            wrapw_type;
	int            wraph_type;
	lwEParam       wrapw;
	lwEParam       wraph;
	float          aa_strength;
	int            aas_flags;
	int            pblend;
	lwEParam       stck;
	lwEParam       amplitude;
} lwImageMap;

#define PROJ_PLANAR       0
#define PROJ_CYLINDRICAL  1
#define PROJ_SPHERICAL    2
#define PROJ_CUBIC        3
#define PROJ_FRONT        4

#define WRAP_NONE    0
#define WRAP_EDGE    1
#define WRAP_REPEAT  2
#define WRAP_MIRROR  3

typedef struct st_lwProcedural
{
	int            axis;
	float          value[ 3 ];
	char*          name;
	void*          data;
} lwProcedural;

typedef struct st_lwGradKey
{
	struct st_lwGradKey* next, *prev;
	float          value;
	float          rgba[ 4 ];
} lwGradKey;

typedef struct st_lwGradient
{
	char*          paramname;
	char*          itemname;
	float          start;
	float          end;
	int            repeat;
	lwGradKey*     key;                 /* array of gradient keys */
	short*         ikey;                /* array of interpolation codes */
} lwGradient;

typedef struct st_lwTexture
{
	struct st_lwTexture* next, *prev;
	char*          ord;
	unsigned int   type;
	unsigned int   chan;
	lwEParam       opacity;
	short          opac_type;
	short          enabled;
	short          negative;
	short          axis;
	union
	{
		lwImageMap     imap;
		lwProcedural   proc;
		lwGradient     grad;
	}              param;
	lwTMap         tmap;
} lwTexture;


/* values that can be textured */

typedef struct st_lwTParam
{
	float          val;
	int            eindex;
	lwTexture*     tex;                 /* linked list of texture layers */
} lwTParam;

typedef struct st_lwCParam
{
	float          rgb[ 3 ];
	int            eindex;
	lwTexture*     tex;                 /* linked list of texture layers */
} lwCParam;


/* surfaces */

typedef struct st_lwGlow
{
	short          enabled;
	short          type;
	lwEParam       intensity;
	lwEParam       size;
} Glow;

typedef struct st_lwRMap
{
	lwTParam       val;
	int            options;
	int            cindex;
	float          seam_angle;
} lwRMap;

typedef struct st_lwLine
{
	short          enabled;
	unsigned short flags;
	lwEParam       size;
} lwLine;

typedef struct st_lwSurface
{
	struct st_lwSurface* next, *prev;
	char*          name;
	char*          srcname;
	lwCParam       color;
	lwTParam       luminosity;
	lwTParam       diffuse;
	lwTParam       specularity;
	lwTParam       glossiness;
	lwRMap         reflection;
	lwRMap         transparency;
	lwTParam       eta;
	lwTParam       translucency;
	lwTParam       bump;
	float          smooth;
	int            sideflags;
	float          alpha;
	int            alpha_mode;
	lwEParam       color_hilite;
	lwEParam       color_filter;
	lwEParam       add_trans;
	lwEParam       dif_sharp;
	lwEParam       glow;
	lwLine         line;
	lwPlugin*      shader;              /* linked list of shaders */
	int            nshaders;
} lwSurface;


/* vertex maps */

typedef struct st_lwVMap
{
	struct st_lwVMap* next, *prev;
	char*          name;
	unsigned int   type;
	int            dim;
	int            nverts;
	int            perpoly;
	int*           vindex;              /* array of point indexes */
	int*           pindex;              /* array of polygon indexes */
	float**        val;

	// added by duffy
	int			offset;
} lwVMap;

typedef struct st_lwVMapPt
{
	lwVMap*        vmap;
	int            index;               /* vindex or pindex element */
} lwVMapPt;


/* points and polygons */

typedef struct st_lwPoint
{
	float          pos[ 3 ];
	int            npols;               /* number of polygons sharing the point */
	int*           pol;                 /* array of polygon indexes */
	int            nvmaps;
	lwVMapPt*      vm;                  /* array of vmap references */
} lwPoint;

typedef struct st_lwPolVert
{
	int            index;               /* index into the point array */
	float          norm[ 3 ];
	int            nvmaps;
	lwVMapPt*      vm;                  /* array of vmap references */
} lwPolVert;

typedef struct st_lwPolygon
{
	union
	{
		intptr_t   index;
		lwSurface* ptr;
	}              surf;
	int            part;                /* part index */
	int            smoothgrp;           /* smoothing group */
	int            flags;
	unsigned int   type;
	float          norm[ 3 ];
	int            nverts;
	lwPolVert*     v;                   /* array of vertex records */
} lwPolygon;

typedef struct st_lwPointList
{
	int            count;
	int            offset;              /* only used during reading */
	lwPoint*       pt;                  /* array of points */
} lwPointList;

typedef struct st_lwPolygonList
{
	int            count;
	int            offset;              /* only used during reading */
	int            vcount;              /* total number of vertices */
	int            voffset;             /* only used during reading */
	lwPolygon*     pol;                 /* array of polygons */
} lwPolygonList;


/* geometry layers */

typedef struct st_lwLayer
{
	struct st_lwLayer* next, *prev;
	char*          name;
	int            index;
	int            parent;
	int            flags;
	float          pivot[ 3 ];
	float          bbox[ 6 ];
	lwPointList    point;
	lwPolygonList  polygon;
	int            nvmaps;
	lwVMap*        vmap;                /* linked list of vmaps */
} lwLayer;


/* tag strings */

typedef struct st_lwTagList
{
	int            count;
	int            offset;              /* only used during reading */
	char**         tag;                 /* array of strings */
} lwTagList;


/* an object */

typedef struct st_lwObject
{
	ID_TIME_T			timeStamp;
	lwLayer* 		layer;               /* linked list of layers */
	lwEnvelope* 	env;                 /* linked list of envelopes */
	lwClip* 		clip;                /* linked list of clips */
	lwSurface* 		surf;                /* linked list of surfaces */
	lwTagList		taglist;
	int				nlayers;
	int				nenvs;
	int				nclips;
	int				nsurfs;
} lwObject;


/* lwo2.c */

lwObject* lwGetObject( const char* filename, unsigned int* failID, int* failpos );
void lwFreeObject( lwObject* object );
void lwFreeLayer( lwLayer* layer );

/* pntspols.c */

void lwFreePoints( lwPointList* point );
void lwFreePolygons( lwPolygonList* plist );
int lwGetPoints( idFile* fp, int cksize, lwPointList* point );
void lwGetBoundingBox( lwPointList* point, float bbox[] );
int lwAllocPolygons( lwPolygonList* plist, int npols, int nverts );
int lwGetPolygons( idFile* fp, int cksize, lwPolygonList* plist, int ptoffset );
void lwGetPolyNormals( lwPointList* point, lwPolygonList* polygon );
int lwGetPointPolygons( lwPointList* point, lwPolygonList* polygon );
int lwResolvePolySurfaces( lwPolygonList* polygon, lwTagList* tlist,
						   lwSurface** surf, int* nsurfs );
void lwGetVertNormals( lwPointList* point, lwPolygonList* polygon );
void lwFreeTags( lwTagList* tlist );
int lwGetTags( idFile* fp, int cksize, lwTagList* tlist );
int lwGetPolygonTags( idFile* fp, int cksize, lwTagList* tlist,
					  lwPolygonList* plist );

/* vmap.c */

void lwFreeVMap( lwVMap* vmap );
lwVMap* lwGetVMap( idFile* fp, int cksize, int ptoffset, int poloffset,
				   int perpoly );
int lwGetPointVMaps( lwPointList* point, lwVMap* vmap );
int lwGetPolyVMaps( lwPolygonList* polygon, lwVMap* vmap );

/* clip.c */

void lwFreeClip( lwClip* clip );
lwClip* lwGetClip( idFile* fp, int cksize );
lwClip* lwFindClip( lwClip* list, int index );

/* envelope.c */

void lwFreeEnvelope( lwEnvelope* env );
lwEnvelope* lwGetEnvelope( idFile* fp, int cksize );
lwEnvelope* lwFindEnvelope( lwEnvelope* list, int index );
float lwEvalEnvelope( lwEnvelope* env, float time );

/* surface.c */

void lwFreePlugin( lwPlugin* p );
void lwFreeTexture( lwTexture* t );
void lwFreeSurface( lwSurface* surf );
int lwGetTHeader( idFile* fp, int hsz, lwTexture* tex );
int lwGetTMap( idFile* fp, int tmapsz, lwTMap* tmap );
int lwGetImageMap( idFile* fp, int rsz, lwTexture* tex );
int lwGetProcedural( idFile* fp, int rsz, lwTexture* tex );
int lwGetGradient( idFile* fp, int rsz, lwTexture* tex );
lwTexture* lwGetTexture( idFile* fp, int bloksz, unsigned int type );
lwPlugin* lwGetShader( idFile* fp, int bloksz );
lwSurface* lwGetSurface( idFile* fp, int cksize );
lwSurface* lwDefaultSurface();

/* lwob.c */

lwSurface* lwGetSurface5( idFile* fp, int cksize, lwObject* obj );
int lwGetPolygons5( idFile* fp, int cksize, lwPolygonList* plist, int ptoffset );
lwObject* lwGetObject5( const char* filename, unsigned int* failID, int* failpos );

/* list.c */

void lwListFree( void* list, void ( *freeNode )( void* ) );
void lwListAdd( void** list, void* node );
void lwListInsert( void** vlist, void* vitem,
				   int ( *compare )( void*, void* ) );

/* vecmath.c */

float dot( float a[], float b[] );
void cross( float a[], float b[], float c[] );
void normalize( float v[] );
#define vecangle( a, b ) ( float ) idMath::ACos( dot( a, b ) )

/* lwio.c */

void  set_flen( int i );
int   get_flen();
void* getbytes( idFile* fp, int size );
void  skipbytes( idFile* fp, int n );
int   getI1( idFile* fp );
short getI2( idFile* fp );
int   getI4( idFile* fp );
unsigned char  getU1( idFile* fp );
unsigned short getU2( idFile* fp );
unsigned int   getU4( idFile* fp );
int   getVX( idFile* fp );
float getF4( idFile* fp );
char* getS0( idFile* fp );
int   sgetI1( unsigned char** bp );
short sgetI2( unsigned char** bp );
int   sgetI4( unsigned char** bp );
unsigned char  sgetU1( unsigned char** bp );
unsigned short sgetU2( unsigned char** bp );
unsigned int   sgetU4( unsigned char** bp );
int   sgetVX( unsigned char** bp );
float sgetF4( unsigned char** bp );
char* sgetS0( unsigned char** bp );

#endif /* !__LWO2_H__ */
