//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//
//===========================================================================//

#ifndef STUDIOMDL_H
#define STUDIOMDL_H

#ifdef _WIN32
#pragma once
#endif


#include <stdio.h>
#include "basetypes.h"
#include "tier1/utlvector.h"
#include "tier1/utlsymbol.h"
#include "tier1/utlstring.h"
#include "mathlib/vector.h"
#include "studio.h"
#include "datamodel/dmelementhandle.h"
#include "checkuv.h"

struct LodScriptData_t;
struct s_flexkey_t;
struct s_flexcontroller_t;
struct s_flexcontrollerremap_t;
struct s_combinationrule_t;
struct s_combinationcontrol_t;
class CDmeVertexDeltaData;
class CDmeCombinationOperator;

#define IDSTUDIOHEADER			(('T'<<24)+('S'<<16)+('D'<<8)+'I')
														// little-endian "IDST"
#define IDSTUDIOANIMGROUPHEADER	(('G'<<24)+('A'<<16)+('D'<<8)+'I')
														// little-endian "IDAG"


#define STUDIO_QUADRATIC_MOTION 0x00002000

#define MAXSTUDIOANIMFRAMES		5000	// max frames per animation
#define MAXSTUDIOANIMS			2000	// total animations
#define MAXSTUDIOSEQUENCES		1524	// total sequences
#define MAXSTUDIOSRCBONES		512		// bones allowed at source movement
#define MAXSTUDIOMODELS			32		// sub-models per model
#define MAXSTUDIOBODYPARTS		32
#define MAXSTUDIOMESHES			256
#define MAXSTUDIOEVENTS			1024
#define MAXSTUDIOFLEXKEYS		512
#define MAXSTUDIOFLEXRULES		1024
#define MAXSTUDIOBONEWEIGHTS	3
#define MAXSTUDIOCMDS			64
#define MAXSTUDIOMOVEKEYS		64
#define MAXSTUDIOIKRULES		64
#define MAXSTUDIONAME			128

#ifndef EXTERN
#define EXTERN extern
#endif

EXTERN	char		outname[MAX_PATH];
//EXTERN	char		g_pPlatformName[1024];
EXTERN  qboolean	cdset;
EXTERN  int			numdirs;
EXTERN	char		cddir[32][MAX_PATH];
EXTERN	int			numcdtextures;
EXTERN	char *		cdtextures[16];
EXTERN  char		fullpath[1024];

EXTERN	char		rootname[MAXSTUDIONAME];		// name of the root bone
EXTERN	float		g_defaultscale;
EXTERN  float		g_currentscale;
EXTERN  RadianEuler	g_defaultrotation;


EXTERN	char		defaulttexture[16][MAX_PATH];
EXTERN	char		sourcetexture[16][MAX_PATH];

EXTERN	int			numrep;

EXTERN	int			tag_reversed;
EXTERN	int			tag_normals;
EXTERN	float		normal_blend;
EXTERN	int			dump_hboxes;
EXTERN	int			ignore_warnings;

EXTERN	Vector		eyeposition;
EXTERN	float		g_flMaxEyeDeflection;
EXTERN	int			g_illumpositionattachment;
EXTERN	Vector		illumposition;
EXTERN	int			illumpositionset;
EXTERN	int			gflags;
EXTERN	Vector		bbox[2];
EXTERN	Vector		cbox[2];
EXTERN	bool		g_wrotebbox;
EXTERN	bool		g_wrotecbox;

EXTERN	int			clip_texcoords;
EXTERN	bool		g_staticprop;
EXTERN	bool		g_centerstaticprop;

EXTERN	bool		g_realignbones;
EXTERN	bool		g_definebones;

EXTERN  byte		g_constdirectionalightdot;

// Methods associated with the key value text block
extern CUtlVector< char >	g_KeyValueText;
int		KeyValueTextSize( CUtlVector< char > *pKeyValue );
const char *KeyValueText( CUtlVector< char > *pKeyValue );

extern vec_t Q_rint (vec_t in);

extern void WriteModelFiles(void);
void *kalloc( int num, int size );

// --------------------------------------------------------------------

template< class T >
class CUtlVectorAuto : public CUtlVector< T >
{
	// typedef CUtlVectorAuto< T, CUtlVector<T > > BaseClass;
public:
	T& operator[]( int i );
};

template< typename T >
inline T& CUtlVectorAuto<T>::operator[]( int i )
{
	EnsureCount( i + 1 );
	Assert( IsValidIndex(i) );
	return Base()[i];
}

// --------------------------------------------------------------------

struct s_trianglevert_t
{
	int					vertindex;
	int					normindex;		// index into normal array
	int					s,t;
	float				u,v;
};

struct s_boneweight_t
{
	int		numbones;

	int		bone[MAXSTUDIOBONEWEIGHTS];
	float	weight[MAXSTUDIOBONEWEIGHTS];
};


struct s_tmpface_t
{
	int	material;
	unsigned long		a, b, c;
	unsigned long		ta, tb, tc;
	unsigned long		na, nb, nc;
};

struct s_face_t
{
	unsigned long		a, b, c;
};


struct s_vertexinfo_t
{
	int				material;
	int				mesh;
	Vector			position;	
	Vector			normal;
	Vector4D		tangentS;
	Vector2D		texcoord;
	s_boneweight_t	boneweight;
};


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

// dstudiobone_t bone[MAXSTUDIOBONES];
struct s_bonefixup_t
{
	matrix3x4_t m;	
};

EXTERN int g_numbones;
struct s_bonetable_t
{
	char			name[MAXSTUDIONAME];	// bone name for symbolic links
	int		 		parent;		// parent bone
	bool			split;
	int				bonecontroller;	// -1 == 0
	Vector			pos;		// default pos
	Vector			posscale;	// pos values scale
	RadianEuler		rot;		// default pos
	Vector			rotscale;	// rotation values scale
	int				group;		// hitgroup
	Vector			bmin, bmax;	// bounding box
	bool			bPreDefined;
	matrix3x4_t		rawLocalOriginal; // original transform of preDefined bone
	matrix3x4_t		rawLocal;
	matrix3x4_t		srcRealign;
	bool			bPreAligned;
	matrix3x4_t		boneToPose;
	int				flags;
	int				proceduralindex;
	int				physicsBoneIndex;
	int				surfacePropIndex;
	Quaternion		qAlignment;
	bool			bDontCollapse;
	Vector			posrange;
};
EXTERN	s_bonetable_t g_bonetable[MAXSTUDIOSRCBONES];
extern int findGlobalBone( const char *name );	// finds a named bone in the global bone table

EXTERN int g_numrenamedbones;
struct s_renamebone_t
{
	char			from[MAXSTUDIONAME];
	char			to[MAXSTUDIONAME];
};
EXTERN s_renamebone_t g_renamedbone[MAXSTUDIOSRCBONES];
const char *RenameBone( const char *pName ); // returns new name if available, else return pName.

EXTERN int g_numimportbones;
struct s_importbone_t
{
	char			name[MAXSTUDIONAME];
	char			parent[MAXSTUDIONAME];
	matrix3x4_t		rawLocal;
	bool			bPreAligned;
	matrix3x4_t		srcRealign;
};
EXTERN s_importbone_t g_importbone[MAXSTUDIOSRCBONES];


EXTERN int g_numincludemodels;
struct s_includemodel_t
{
	char			name[MAXSTUDIONAME];
};
EXTERN s_includemodel_t g_includemodel[128];

struct s_bbox_t
{
	char			name[MAXSTUDIONAME];		// bone name
	char			hitboxname[MAXSTUDIONAME];	// hitbox name
	int				bone;
	int				group;		// hitgroup
	int				model;
	Vector			bmin, bmax;	// bounding box
};

#define MAXSTUDIOHITBOXSETNAME 64

struct s_hitboxset
{
	char		hitboxsetname[ MAXSTUDIOHITBOXSETNAME ];
	
	int			numhitboxes;

	s_bbox_t	hitbox[MAXSTUDIOSRCBONES];
};

extern CUtlVector< s_hitboxset > g_hitboxsets;

EXTERN int g_numhitgroups;
struct s_hitgroup_t
{
	int				models;
	int				group;
	char			name[MAXSTUDIONAME];	// bone name
};
EXTERN s_hitgroup_t g_hitgroup[MAXSTUDIOSRCBONES];


struct s_bonecontroller_t
{
	char	name[MAXSTUDIONAME];
	int		bone;
	int		type;
	int		inputfield;
	float	start;
	float	end;
};

EXTERN s_bonecontroller_t g_bonecontroller[MAXSTUDIOSRCBONES];
EXTERN int g_numbonecontrollers;

struct s_screenalignedbone_t
{
	char	name[MAXSTUDIONAME];
	int		flags;
};

EXTERN s_screenalignedbone_t g_screenalignedbone[MAXSTUDIOSRCBONES];
EXTERN int g_numscreenalignedbones;

struct s_attachment_t
{
	char	name[MAXSTUDIONAME];
	char	bonename[MAXSTUDIONAME];
	int		bone;
	int		type;
	int		flags;
	matrix3x4_t	local;
	int		found;	// a owning bone has been flagged

	bool operator==( const s_attachment_t &rhs ) const;
};


#define IS_ABSOLUTE		0x0001
#define IS_RIGID		0x0002

EXTERN s_attachment_t g_attachment[MAXSTUDIOSRCBONES];
EXTERN int g_numattachments;

struct s_bonemerge_t
{
	char	bonename[MAXSTUDIONAME];
};

EXTERN CUtlVector< s_bonemerge_t > g_BoneMerge;

struct s_mouth_t
{
	char	bonename[MAXSTUDIONAME];
	int		bone;
	Vector	forward;
	int		flexdesc;
};

EXTERN s_mouth_t g_mouth[MAXSTUDIOSRCBONES]; // ?? skins?
EXTERN int g_nummouths;

struct s_node_t
{
	char			name[MAXSTUDIONAME];
	int				parent;
};

struct s_bone_t
{
	Vector			pos;
	RadianEuler		rot;
};

struct s_linearmove_t
{
	int				endframe;	// frame when pos, rot is valid.
	int				flags;		// type of motion.  Only linear, linear accel, and linear decel is allowed
	float			v0;
	float			v1;
	Vector			vector;		// movement vector
	Vector			pos;	// final position
	RadianEuler		rot;		// final rotation
};


#define CMD_WEIGHTS	1
#define CMD_SUBTRACT 2
#define CMD_AO		3
#define CMD_MATCH	4
#define CMD_FIXUP	5
#define CMD_ANGLE	6
#define CMD_IKFIXUP	7
#define CMD_IKRULE	8
#define CMD_MOTION	9
#define CMD_REFMOTION	10
#define CMD_DERIVATIVE 11
#define	CMD_NOANIMATION 12
#define CMD_LINEARDELTA 13
#define CMD_SPLINEDELTA 14
#define CMD_COMPRESS 15
#define CMD_NUMFRAMES 16
#define CMD_COUNTERROTATE 17
#define CMD_SETBONE 18
#define CMD_WORLDSPACEBLEND 19
#define CMD_MATCHBLEND 20
#define CMD_LOCALHIERARCHY 21

struct s_animation_t;
struct s_ikrule_t;


struct s_motion_t
{
	int				motiontype;
	int				iStartFrame;// starting frame to apply motion over
	int				iEndFrame;	// end frame to apply motion over
	int				iSrcFrame;	// frame that matches the "reference" animation
	s_animation_t	*pRefAnim;	// animation to match
	int				iRefFrame;	// reference animation's frame to match
};


struct s_animcmd_t
{
	int cmd;
	union 
	{
		struct
		{
			int				index;	
		} weightlist;

		struct
		{
			s_animation_t	*ref;
			int				frame;
			int				flags;
		} subtract;

		struct
		{
			s_animation_t	*ref;
			int				motiontype;
			int				srcframe;
			int				destframe;
			char			*pBonename;
		} ao;

		struct
		{
			s_animation_t	*ref;
			int				srcframe;
			int				destframe;
			int				destpre;
			int				destpost;
		} match;

		struct
		{
			s_animation_t	*ref;
			int				startframe;
			int				loops;
		} world;

		struct 
		{
			int				start;
			int				end;
		} fixuploop;

		struct 
		{
			float			angle;
		} angle;

		struct
		{
			s_ikrule_t		*pRule;
		} ikfixup;

		struct
		{
			s_ikrule_t		*pRule;
		} ikrule;

		struct
		{
			float			scale;
		} derivative;

		struct
		{
			int				flags;
		} linear;

		struct
		{
			int				frames;
		} compress;

		struct
		{
			int				frames;
		} numframes;

		struct
		{
			char			*pBonename;
			bool			bHasTarget;
			float 			targetAngle[3];
		} counterrotate;

		struct
		{
			char			*pBonename;
			char			*pParentname;
			int				start;
			int				peak;
			int				tail;
			int				end;
		} localhierarchy;

		struct s_motion_t	motion;
	} u;
};

struct s_streamdata_t
{
	Vector pos;
	Quaternion q;
};


struct s_animationstream_t
{
	// source animations
	int					numerror;
	s_streamdata_t		*pError;
	// compressed animations
	float				scale[6];
	int					numanim[6];
	mstudioanimvalue_t	*anim[6];
};

struct s_ikrule_t
{
	int		chain;

	int		index;
	int		type;
	int		slot;
	char	bonename[MAXSTUDIONAME];
	char	attachment[MAXSTUDIONAME];
	int		bone;
	Vector	pos;
	Quaternion q;
	float	height;
	float	floor;
	float	radius;

	int		start;
	int		peak;
	int		tail;
	int		end;

	int		contact;

	bool	usesequence;
	bool	usesource;

	int		flags;

	s_animationstream_t errorData;
};

struct s_localhierarchy_t
{
	int		bone;
	int		newparent;

	int		start;
	int		peak;
	int		tail;
	int		end;

	s_animationstream_t localData;
};


struct s_source_t;
EXTERN	int g_numani;
struct s_compressed_t
{
	int					num[6];
	mstudioanimvalue_t *data[6];
};

struct s_animation_t
{
	bool			isImplied;
	bool			isOverride;
	bool			doesOverride;
	int				index;
	char			name[MAXSTUDIONAME];
	char			filename[MAX_PATH];

	/*
	int				animsubindex;

	// For sharing outside of current .mdl file
	bool			shared_group_checkvalidity;
	bool			shared_group_valid;
	char			shared_animgroup_file[ MAX_PATH ]; // share file name
	char			shared_animgroup_name[ MAXSTUDIONAME ]; // group name in share file
	int				shared_group_subindex;
	studioanimhdr_t *shared_group_header;
	*/

	float			fps;
	int				startframe;
	int				endframe;
	int				flags;
	// animations processed (time shifted, linearized, and bone adjusted ) from source animations
	CUtlVectorAuto< s_bone_t * > sanim; // [MAXSTUDIOANIMFRAMES]; // [frame][bones];

	int				motiontype;

	int				fudgeloop;
	int				looprestart; // new starting frame for looping animations

	// piecewise linear motion
	int				numpiecewisekeys;
	s_linearmove_t	piecewisemove[MAXSTUDIOMOVEKEYS];

	// default adjustments
	Vector			adjust;
	float			scale; // ????
	RadianEuler		rotation; 

	s_source_t		*source;
	char			animationname[MAX_PATH];

	Vector 			bmin;
	Vector			bmax;

	int				numframes;

	// compressed animation data
	int				numsections;
	int				sectionframes;
	CUtlVectorAuto< CUtlVectorAuto< s_compressed_t > > anim;

	// int				weightlist;
	float			weight[MAXSTUDIOSRCBONES];
	float			posweight[MAXSTUDIOSRCBONES];

	int				numcmds;
	s_animcmd_t		cmds[MAXSTUDIOCMDS];

	int				numikrules;
	s_ikrule_t		ikrule[MAXSTUDIOIKRULES];
	bool			noAutoIK;

	int				numlocalhierarchy;
	s_localhierarchy_t localhierarchy[MAXSTUDIOIKRULES];

	float			motionrollback;

	bool			disableAnimblocks;		// no demand loading
	bool			isFirstSectionLocal;	// first block of a section isn't demand loaded
};
EXTERN	s_animation_t *g_panimation[MAXSTUDIOANIMS];


EXTERN  int	g_numcmdlists;
struct s_cmdlist_t
{
	char			name[MAXSTUDIONAME];
	int				numcmds;
	s_animcmd_t		cmds[MAXSTUDIOCMDS];
};
EXTERN	s_cmdlist_t g_cmdlist[MAXSTUDIOANIMS];


struct s_iklock_t
{
	char			name[MAXSTUDIONAME];
	int				chain;
	float			flPosWeight;
	float			flLocalQWeight;
};

EXTERN	int g_numikautoplaylocks;
EXTERN	s_iklock_t g_ikautoplaylock[16];


struct s_event_t
{
	int				event;
	int				frame;
	char			options[64];
	char			eventname[MAXSTUDIONAME];
};

struct s_autolayer_t
{
	char			name[MAXSTUDIONAME];
	int				sequence;
	int				flags;
	int				pose;
	float			start;
	float			peak;
	float			tail;
	float			end;
};


class s_sequence_t
{
public:
	char			name[MAXSTUDIONAME];
	char			activityname[MAXSTUDIONAME];	// index into the string table, the name of this activity.

	int				flags;
	// float			fps;
	// int				numframes;

	int				activity;
	int				actweight;

	int				numevents;
	s_event_t		event[MAXSTUDIOEVENTS];

	int				numblends;
	int				groupsize[2];
	CUtlVectorAuto< CUtlVectorAuto< s_animation_t * > > panim; // [MAXSTUDIOBLENDS][MAXSTUDIOBLENDS];

	int				paramindex[2];
	float			paramstart[2];
	float			paramend[2];
	int				paramattachment[2];
	int				paramcontrol[2];
	CUtlVectorAuto< float >param0; // [MAXSTUDIOBLENDS];
	CUtlVectorAuto< float >param1; // [MAXSTUDIOBLENDS];
	s_animation_t	*paramanim;
	s_animation_t	*paramcompanim;
	s_animation_t	*paramcenter;

	// Vector			automovepos[MAXSTUDIOANIMATIONS];
	// Vector			automoveangle[MAXSTUDIOANIMATIONS];

	int				animindex;

	Vector 			bmin;
	Vector			bmax;

	float			fadeintime;
	float			fadeouttime;

	int				entrynode;
	int				exitnode;
	int				nodeflags;
	float			entryphase;
	float			exitphase;

	int				numikrules;

	int				numautolayers;
	s_autolayer_t	autolayer[64];

	float			weight[MAXSTUDIOSRCBONES];

	s_iklock_t		iklock[64];
	int				numiklocks;

	int				cycleposeindex;

	CUtlVector< char > KeyValue;
};
EXTERN	CUtlVector< s_sequence_t > g_sequence;
//EXTERN	int g_numseq;


EXTERN int g_numanimblocks;
struct s_animblock_t
{
	int		iStartAnim;
	int		iEndAnim;
	byte	*start;
	byte	*end;
};
EXTERN s_animblock_t g_animblock[MAXSTUDIOANIMBLOCKS];
EXTERN int g_animblocksize;
EXTERN char g_animblockname[260];


EXTERN int g_numposeparameters;
struct s_poseparameter_t
{
	char	name[MAXSTUDIONAME];
	float	min;
	float	max;
	int		flags;
	float	loop;
};
EXTERN s_poseparameter_t g_pose[32]; // FIXME: this shouldn't be hard coded


EXTERN int g_numxnodes;
EXTERN char *g_xnodename[100];
EXTERN int g_xnode[100][100];
EXTERN int g_numxnodeskips;
EXTERN int g_xnodeskip[10000][2];

struct rgb_t
{
	byte r, g, b;
};
struct rgb2_t
{
	float r, g, b, a;
};

// FIXME: what about texture overrides inline with loading models
enum TextureFlags_t
{
	RELATIVE_TEXTURE_PATH_SPECIFIED = 0x1
};

struct s_texture_t
{
	char	name[MAX_PATH];
	int		flags;
	int		parent;
	int		material;
	float	width;
	float	height;
	float	dPdu;
	float	dPdv;
};
EXTERN	s_texture_t g_texture[MAXSTUDIOSKINS];
EXTERN	int g_numtextures;
EXTERN	int	g_material[MAXSTUDIOSKINS]; // link into texture array
EXTERN  int g_nummaterials;

EXTERN  float g_gamma;
EXTERN	int g_numskinref;
EXTERN  int g_numskinfamilies;
EXTERN  int g_skinref[256][MAXSTUDIOSKINS]; // [skin][skinref], returns texture index
EXTERN	int g_numtexturegroups;
EXTERN	int g_numtexturelayers[32];
EXTERN	int g_numtexturereps[32];
EXTERN  int g_texturegroup[32][32][32];

struct s_mesh_t
{
	int numvertices;
	int	vertexoffset;

	int numfaces;
	int	faceoffset;
};


struct s_vertanim_t
{
	int		vertex;
	float	speed;
	float	side;
	Vector	pos;
	Vector	normal;
	float	wrinkle;
};

struct s_lodvertexinfo_t : public s_vertexinfo_t
{
	int lodFlag;
};

// processed aggregate lod pools
struct s_loddata_t
{
	int					numvertices;
	s_lodvertexinfo_t	*vertex;

	int					numfaces;
	s_face_t			*face;

	s_mesh_t			mesh[MAXSTUDIOSKINS];

	// remaps verts from an lod's source mesh to this all-lod processed aggregate pool
	int					*pMeshVertIndexMaps[MAX_NUM_LODS];
};

// Animations stored in raw off-disk source files.  Raw data should be not processed.
class s_sourceanim_t
{
public:
	char animationname[MAX_PATH];
	int numframes;
	int startframe;
	int endframe;
	CUtlVectorAuto< s_bone_t * >rawanim;

	// vertex animation
	bool			newStyleVertexAnimations;	// new style doesn't store a base pose in vertex anim[0]
	int				*vanim_mapcount;	// local verts map to N target verts
	int				**vanim_map;		// local vertices to target vertices mapping list
	int				*vanim_flag;		// local vert does animate

	int				numvanims[MAXSTUDIOANIMFRAMES];
	s_vertanim_t	*vanim[MAXSTUDIOANIMFRAMES];	// [frame][vertex]
};

// raw off-disk source files.  Raw data should be not processed.
struct s_source_t
{
	char	filename[MAX_PATH];
	int 	time;	// time stamp

	bool	isActiveModel;

	// local skeleton hierarchy
	int numbones;
	s_node_t localBone[MAXSTUDIOSRCBONES];
	matrix3x4_t boneToPose[MAXSTUDIOSRCBONES];	// converts bone local data into initial pose data

	// bone remapping
	int boneflags[MAXSTUDIOSRCBONES];	// attachment, vertex, etc flags for this bone
	int boneref[MAXSTUDIOSRCBONES];		// flags for this and child bones
	int	boneLocalToGlobal[MAXSTUDIOSRCBONES]; // bonemap : local bone to world bone mapping
	int	boneGlobalToLocal[MAXSTUDIOSRCBONES]; // boneimap : world bone to local bone mapping

	int	texmap[MAXSTUDIOSKINS*4];		// map local MAX materials to unique textures

	// per material mesh
	int				nummeshes;
	int				meshindex[MAXSTUDIOSKINS];	// mesh to skin index
	s_mesh_t		mesh[MAXSTUDIOSKINS];

	// vertices defined in "local" space (not remapped to global bones)
	int				numvertices;
	s_vertexinfo_t	*vertex;

	// vertices defined in "global" space (remapped to global bones)
	CUtlVector< s_vertexinfo_t > m_GlobalVertices;

	int numfaces;
	s_face_t *face;						// vertex indexs per face

	// raw skeletal animation
	CUtlVector< s_sourceanim_t > m_Animations;
	// default adjustments
	Vector			adjust;
	float			scale; // ????
	RadianEuler		rotation; 


	// Flex keys stored in the source data
	CUtlVector< s_flexkey_t > m_FlexKeys;

	// Combination controls stored in the source data
	CUtlVector< s_combinationcontrol_t > m_CombinationControls;

	// Combination rules stored in the source data
	CUtlVector< s_combinationrule_t > m_CombinationRules;

	// Flexcontroller remaps
	CUtlVector< s_flexcontrollerremap_t > m_FlexControllerRemaps;

	// Attachment points stored in the SMD/DMX/etc. file
	CUtlVector< s_attachment_t > m_Attachments;

	// Information about how flex controller remaps map into flex rules
	int m_nKeyStartIndex;	// The index at which the flex keys for this model start in the global list
	CUtlVector< int > m_rawIndexToRemapSourceIndex;
	CUtlVector< int > m_rawIndexToRemapLocalIndex;
	CUtlVector< int > m_leftRemapIndexToGlobalFlexControllIndex;
	CUtlVector< int > m_rightRemapIndexToGlobalFlexControllIndex;
};


EXTERN int g_numsources;
EXTERN s_source_t *g_source[MAXSTUDIOSEQUENCES];

struct s_eyeball_t
{
	char	name[MAXSTUDIONAME];
	int		index;
	int		bone;
	Vector	org;
	float	zoffset;
	float	radius;
	Vector	up;
	Vector	forward;

	int		mesh;
	float	iris_scale;

	int		upperlidflexdesc;
	int		upperflexdesc[3];
	float	uppertarget[3];

	int		lowerlidflexdesc;
	int		lowerflexdesc[3];
	float	lowertarget[3];

	int		m_flags;

	enum StudioMdlEyeBallFlags
	{
		STUDIOMDL_EYELID_DME = 1 << 0
	};
};

struct s_model_t
{
	char name[MAXSTUDIONAME];
	char filename[MAX_PATH];

	// needs local scaling and rotation paramaters
	s_source_t	 *source; // index into source table

	float scale;	// UNUSED

	float boundingradius;

	Vector boundingbox[MAXSTUDIOSRCBONES][2];

	int	numattachments;
	s_attachment_t	attachment[32];

	int numeyeballs;
	s_eyeball_t		eyeball[4];

	int	numflexes;
	int flexoffset;

	// References to sources which are the LODs for this model
	CUtlVector< s_source_t* > m_LodSources;

	// processed aggregate lod data
	s_loddata_t		*m_pLodData;
};

EXTERN	int g_nummodels;
EXTERN	int g_nummodelsbeforeLOD;
EXTERN	s_model_t *g_model[MAXSTUDIOMODELS];


struct s_flexdesc_t
{
	char FACS[MAXSTUDIONAME];	// FACS identifier
};
EXTERN int g_numflexdesc;
EXTERN s_flexdesc_t g_flexdesc[MAXSTUDIOFLEXDESC];
int Add_Flexdesc( const char *name );


struct s_flexcontroller_t
{
	char name[MAXSTUDIONAME];
	char type[MAXSTUDIONAME];
	float min;
	float max;
};
EXTERN int g_numflexcontrollers;
EXTERN s_flexcontroller_t g_flexcontroller[MAXSTUDIOFLEXCTRL];

struct s_flexcontrollerremap_t
{
	CUtlString m_Name;
	FlexControllerRemapType_t m_RemapType;
	bool m_bIsStereo;
	CUtlVector< CUtlString > m_RawControls;
	int m_Index;		///< The model relative index of the slider control for value for this if it's not split, -1 otherwise
	int m_LeftIndex;	///< The model relative index of the left slider control for this if it's split, -1 otherwise
	int m_RightIndex;	///< The model relative index of the right slider control for this if it's split, -1 otherwise
	int m_MultiIndex;	///< The model relative index of the value slider control for this if it's multi, -1 otherwise
	CUtlString m_EyesUpDownFlexName;	// The name of the eyes up/down flex controller
	int m_EyesUpDownFlexController;		// The global index of the Eyes Up/Down Flex Controller
	int m_BlinkController;				// The global index of the Blink Up/Down Flex Controller
};

extern CUtlVector<s_flexcontrollerremap_t> g_FlexControllerRemap;


struct s_flexkey_t
{
	int	 flexdesc;
	int	 flexpair;
	
	s_source_t	 *source; // index into source table
	char animationname[MAX_PATH];

	int	imodel;
	int	frame;

	float	target0;
	float	target1;
	float	target2;
	float	target3;

	int		original;
	float	split;

	float	decay;

	// extracted and remapped vertex animations
	int				numvanims;
	s_vertanim_t	*vanim;
	int				vanimtype;
	int	weighttable;
};
EXTERN int g_numflexkeys;
EXTERN s_flexkey_t g_flexkey[MAXSTUDIOFLEXKEYS];
EXTERN s_flexkey_t *g_defaultflexkey;

#define MAX_OPS 512

struct s_flexop_t
{
	int		op;
	union 
	{
		int		index;
		float	value;
	} d;
};

struct s_flexrule_t
{
	int		flex;
	int		numops;
	s_flexop_t op[MAX_OPS];
};

EXTERN int g_numflexrules;
EXTERN s_flexrule_t g_flexrule[MAXSTUDIOFLEXRULES];

struct s_combinationcontrol_t
{
	char name[MAX_PATH];
};

struct s_combinationrule_t
{
	// The 'ints' here are indices into the m_Controls array
	CUtlVector< int > m_Combination;
	CUtlVector< CUtlVector< int > > m_Dominators;

	// The index into the flexkeys to put the result in
	// (should affect both left + right if the key is sided)
	int m_nFlex;
};

EXTERN	Vector g_defaultadjust;

struct s_bodypart_t
{
	char				name[MAXSTUDIONAME];
	int					nummodels;
	int					base;
	s_model_t			*pmodel[MAXSTUDIOMODELS];
};

EXTERN	int g_numbodyparts;
EXTERN	s_bodypart_t g_bodypart[MAXSTUDIOBODYPARTS];


#define MAXWEIGHTLISTS	128
#define MAXWEIGHTSPERLIST	(MAXSTUDIOBONES)

struct s_weightlist_t
{
	// weights, indexed by numbones per weightlist
	char			name[MAXSTUDIONAME];
	int				numbones;
	char			*bonename[MAXWEIGHTSPERLIST];
	float			boneweight[MAXWEIGHTSPERLIST];
	float			boneposweight[MAXWEIGHTSPERLIST];

	// weights, indexed by global bone index
	float			weight[MAXSTUDIOBONES];
	float			posweight[MAXSTUDIOBONES];
};

EXTERN	int	g_numweightlist;
EXTERN	s_weightlist_t g_weightlist[MAXWEIGHTLISTS];

struct s_iklink_t
{
	int		bone;
	Vector	kneeDir;
};

struct s_ikchain_t
{
	char			name[MAXSTUDIONAME];
	char			bonename[MAXSTUDIONAME];
	int				axis;
	float			value;
	int				numlinks;
	s_iklink_t		link[10]; // hip, knee, ankle, toes...
	float			height;
	float			radius;
	float			floor;
	Vector			center;
};

EXTERN	int g_numikchains;
EXTERN	s_ikchain_t g_ikchain[16];


struct s_jigglebone_t
{
	int				flags;
	char			bonename[MAXSTUDIONAME];
	int				bone;

	mstudiojigglebone_t data;	// the actual jiggle properties
};

EXTERN int g_numjigglebones;
EXTERN s_jigglebone_t g_jigglebones[MAXSTUDIOBONES];
EXTERN int g_jigglebonemap[MAXSTUDIOBONES]; // map used jigglebone's to source jigglebonebone's


struct s_axisinterpbone_t
{
	int				flags;
	char			bonename[MAXSTUDIONAME];
	int				bone;
	char			controlname[MAXSTUDIONAME];
	int				control;
	int				axis;
	Vector			pos[6];
	Quaternion		quat[6];
};

EXTERN int g_numaxisinterpbones;
EXTERN s_axisinterpbone_t g_axisinterpbones[MAXSTUDIOBONES];
EXTERN int g_axisinterpbonemap[MAXSTUDIOBONES]; // map used axisinterpbone's to source axisinterpbone's

struct s_quatinterpbone_t
{
	int				flags;
	char			bonename[MAXSTUDIONAME];
	int				bone;
	char			parentname[MAXSTUDIONAME];
	// int				parent;
	char			controlparentname[MAXSTUDIONAME];
	// int				controlparent;
	char			controlname[MAXSTUDIONAME];
	int				control;
	int				numtriggers;
	Vector			size;
	Vector			basepos;
	float			percentage;
	float			tolerance[32];
	Quaternion		trigger[32];
	Vector			pos[32];
	Quaternion		quat[32];
};

EXTERN int g_numquatinterpbones;
EXTERN s_quatinterpbone_t g_quatinterpbones[MAXSTUDIOBONES];
EXTERN int g_quatinterpbonemap[MAXSTUDIOBONES]; // map used quatinterpbone's to source axisinterpbone's


struct s_aimatbone_t
{
	char			bonename[MAXSTUDIONAME];
	int				bone;
	char			parentname[MAXSTUDIONAME];
	int				parent;
	char			aimname[MAXSTUDIONAME];
	int				aimAttach;
	int				aimBone;
	Vector			aimvector;
	Vector			upvector;
	Vector			basepos;
};

EXTERN int g_numaimatbones;
EXTERN s_aimatbone_t g_aimatbones[MAXSTUDIOBONES];
EXTERN int g_aimatbonemap[MAXSTUDIOBONES]; // map used aimatpbone's to source aimatpbone's (may be optimized out)


struct s_forcedhierarchy_t
{
	char			parentname[MAXSTUDIONAME];
	char			childname[MAXSTUDIONAME];
	char			subparentname[MAXSTUDIONAME];
};

EXTERN int g_numforcedhierarchy;
EXTERN s_forcedhierarchy_t g_forcedhierarchy[MAXSTUDIOBONES];

struct s_forcedrealign_t
{
	char			name[MAXSTUDIONAME];
	RadianEuler		rot;
};
EXTERN int g_numforcedrealign;
EXTERN s_forcedrealign_t g_forcedrealign[MAXSTUDIOBONES];

struct s_limitrotation_t
{
	char			name[MAXSTUDIONAME];
	int				numseq;
	char			*sequencename[64];
};

EXTERN int g_numlimitrotation;
EXTERN s_limitrotation_t g_limitrotation[MAXSTUDIOBONES];

extern int BuildTris (s_trianglevert_t (*x)[3], s_mesh_t *y, byte **ppdata );


struct s_bonesaveframe_t
{
	char		name[ MAXSTUDIOHITBOXSETNAME ];
	bool		bSavePos;
	bool		bSaveRot;
};

EXTERN CUtlVector< s_bonesaveframe_t > g_bonesaveframe;

int OpenGlobalFile( char *src );
bool GetGlobalFilePath( const char *pSrc, char *pFullPath, int nMaxLen );
s_source_t *Load_Source( char const *filename, const char *ext, bool reverse = false, bool isActiveModel = false );
int Load_VRM( s_source_t *psource );
int Load_SMD( s_source_t *psource );
int Load_VTA( s_source_t *psource );
int Load_OBJ( s_source_t *psource );
int Load_DMX( s_source_t *psource );
int AppendVTAtoOBJ( s_source_t *psource, char *filename, int frame );
void Build_Reference( s_source_t *psource, const char *pAnimName );
int Grab_Nodes( s_node_t *pnodes );
void Grab_Animation( s_source_t *psource, const char *pAnimName );

// Processes source comment line and extracts information about the data file
void ProcessSourceComment( s_source_t *psource, const char *pCommentString );

// Processes original content file "szOriginalContentFile" that was used to generate
// data file "szDataFile"
void ProcessOriginalContentFile( const char *szDataFile, const char *szOriginalContentFile );

//-----------------------------------------------------------------------------
// Utility methods to get or add animation data from sources
//-----------------------------------------------------------------------------
s_sourceanim_t *FindSourceAnim( s_source_t *pSource, const char *pAnimName );
const s_sourceanim_t *FindSourceAnim( const s_source_t *pSource, const char *pAnimName );
s_sourceanim_t *FindOrAddSourceAnim( s_source_t *pSource, const char *pAnimName );

// Adds flexkey data to a particular source
void AddFlexKey( s_source_t *pSource, CDmeCombinationOperator *pComboOp, const char *pFlexKeyName );

// Adds combination data to the source
void AddCombination( s_source_t *pSource, CDmeCombinationOperator *pCombination );

int LookupTexture( const char *pTextureName, bool bRelativePath = false );
int UseTextureAsMaterial( int textureindex );
int MaterialToTexture( int material );

int LookupAttachment( char *name );

void ClearModel (void);
void SimplifyModel (void);
void CollapseBones (void);

void adjust_vertex( float *org );
void scale_vertex( Vector &org );
void clip_rotations( RadianEuler& rot );
void clip_rotations( Vector& rot );

void *kalloc( int num, int size );
void kmemset( void *ptr, int value, int size );
char *stristr( const char *string, const char *string2 );

void CalcBoneTransforms( s_animation_t *panimation, int frame, matrix3x4_t* pBoneToWorld );
void CalcBoneTransforms( s_animation_t *panimation, s_animation_t *pbaseanimation, int frame, matrix3x4_t* pBoneToWorld );
void CalcBoneTransformsCycle( s_animation_t *panimation, s_animation_t *pbaseanimation, float flCycle, matrix3x4_t* pBoneToWorld );

void BuildRawTransforms( const s_source_t *psource, const char *pAnimationName, int frame, float scale, Vector const &shift, RadianEuler const &rotate, int flags, matrix3x4_t* boneToWorld );
void BuildRawTransforms( const s_source_t *psource, const char *pAnimationName, int frame, matrix3x4_t* boneToWorld );

void TranslateAnimations( const s_source_t *pSource, const matrix3x4_t *pSrcBoneToWorld, matrix3x4_t *pDestBoneToWorld );

// Returns surface property for a given joint
char* GetSurfaceProp ( char const* pJointName );
int GetContents ( char const* pJointName );
char* GetDefaultSurfaceProp ( );
int GetDefaultContents( );

// Did we read 'end'
bool IsEnd( char const* pLine );

// Parses an LOD command
void Cmd_LOD( char const *cmdname );
void Cmd_ShadowLOD( void );

// Fixes up the LOD source files
void FixupLODSources();

// Get model LOD source
s_source_t* GetModelLODSource( const char *pModelName, 
						const LodScriptData_t& scriptLOD, bool* pFound );


void LoadLODSources( void );
void ConvertBoneTreeCollapsesToReplaceBones( void );
void FixupReplacedBones( void );
void UnifyLODs( void );
void SpewBoneUsageStats( void );
void MarkParentBoneLODs( void );
//void CheckAutoShareAnimationGroup( char const *animation_name );

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

extern bool GetLineInput(void);
extern char	g_szFilename[1024];
extern FILE	*g_fpInput;
extern char	g_szLine[4096];
extern int	g_iLinecount;

extern int g_min_faces, g_max_faces;
extern float g_min_resolution, g_max_resolution;

EXTERN	int g_numverts;
EXTERN	Vector g_vertex[MAXSTUDIOVERTS];
EXTERN	s_boneweight_t g_bone[MAXSTUDIOVERTS];

EXTERN	int g_numnormals;
EXTERN	Vector g_normal[MAXSTUDIOVERTS];

EXTERN	int g_numtexcoords;
EXTERN	Vector2D g_texcoord[MAXSTUDIOVERTS];

EXTERN	int g_numfaces;
EXTERN	s_tmpface_t g_face[MAXSTUDIOTRIANGLES];
EXTERN	s_face_t g_src_uface[MAXSTUDIOTRIANGLES];	// max res unified faces

struct v_unify_t
{
	int	refcount;
	int	lastref;
	int	firstref;
	int	v;
	int m;
	int n;
	int t;
	v_unify_t *next;
};

EXTERN	v_unify_t *v_list[MAXSTUDIOVERTS];
EXTERN	v_unify_t v_listdata[MAXSTUDIOVERTS];
EXTERN	int numvlist;

int SortAndBalanceBones( int iCount, int iMaxCount, int bones[], float weights[] );
void Grab_Vertexanimation( s_source_t *psource, const char *pAnimationName );
extern void BuildIndividualMeshes( s_source_t *psource );

//-----------------------------------------------------------------------------
// A little class used to deal with replacement commands
//-----------------------------------------------------------------------------

class CLodScriptReplacement_t
{
public:
	void SetSrcName( const char *pSrcName )
	{
		if( m_pSrcName )
		{
			delete [] m_pSrcName;
		}
		m_pSrcName = new char[strlen( pSrcName ) + 1];
		strcpy( m_pSrcName, pSrcName );
	}
	void SetDstName( const char *pDstName )
	{
		if( m_pDstName )
		{
			delete [] m_pDstName;
		}
		m_pDstName = new char[strlen( pDstName ) + 1];
		strcpy( m_pDstName, pDstName );
	}

	const char *GetSrcName( void ) const 
	{
		return m_pSrcName;
	}
	const char *GetDstName( void ) const
	{
		return m_pDstName;
	}
	CLodScriptReplacement_t()
	{
		m_pSrcName = NULL;
		m_pDstName = NULL;
		m_pSource = 0;
	}
	~CLodScriptReplacement_t()
	{
		delete [] m_pSrcName;
		delete [] m_pDstName;
	}

	s_source_t*	m_pSource;

private:
	char *m_pSrcName;
	char *m_pDstName;
	bool m_bReverse;
};


struct LodScriptData_t
{
public:
	float switchValue;
	CUtlVector<CLodScriptReplacement_t> modelReplacements;
	CUtlVector<CLodScriptReplacement_t> boneReplacements;
	CUtlVector<CLodScriptReplacement_t> boneTreeCollapses;
	CUtlVector<CLodScriptReplacement_t> materialReplacements;
	CUtlVector<CLodScriptReplacement_t> meshRemovals;


	void EnableFacialAnimation( bool val )
	{
		m_bFacialAnimation = val;
	}
	bool GetFacialAnimationEnabled() const 
	{
		return m_bFacialAnimation;
	}

	void StripFromModel( bool val )
	{
		m_bStrippedFromModel = val;
	}
	bool IsStrippedFromModel() const
	{
		return m_bStrippedFromModel;
	}
	
	LodScriptData_t()
	{
		m_bFacialAnimation = true;
		m_bStrippedFromModel = false;
	}

private:
	bool m_bFacialAnimation;
	bool m_bStrippedFromModel;
};

EXTERN CUtlVector<LodScriptData_t> g_ScriptLODs;

extern bool g_collapse_bones;
extern bool g_collapse_bones_aggressive;
extern bool g_quiet;
extern bool g_verbose;
extern bool g_bCheckLengths;
extern bool g_bPrintBones;
extern bool g_bPerf;
extern bool g_bFast;
extern bool g_bDumpGraph;
extern bool g_bMultistageGraph;
extern bool g_bCreateMakefile;
extern bool g_bZBrush;
extern bool g_bVerifyOnly;
extern bool g_bUseBoneInBBox;
extern bool g_bLockBoneLengths;
extern bool g_bOverridePreDefinedBones;
extern bool g_bX360;
extern int g_minLod;
extern int g_numAllowedRootLODs;
extern bool g_bBuildPreview;
extern bool g_bCenterBonesOnVerts;
extern float g_flDefaultMotionRollback;
extern int g_minSectionFrameLimit;
extern int g_sectionFrames;
extern bool g_bNoAnimblockStall;

extern Vector g_vecMinWorldspace;
extern Vector g_vecMaxWorldspace;

EXTERN CUtlVector< char * >g_collapse;

extern float GetCollisionModelMass();

// List of defined bone flex drivers
extern DmElementHandle_t g_hDmeBoneFlexDriverList;

// the first time these are called, the name of the model/QC file is printed so that when 
// running in batch mode, no echo, when dumping to a file, it can be determined which file is broke.
void MdlError( PRINTF_FORMAT_STRING char const *pMsg, ... );
void MdlWarning( PRINTF_FORMAT_STRING char const *pMsg, ... );

void CreateMakefile_AddDependency( const char *pFileName );
void EnsureDependencyFileCheckedIn( const char *pFileName );

bool ComparePath( const char *a, const char *b );

byte IsByte( int val );
char IsChar( int val );
int IsInt24( int val );
short IsShort( int val );
unsigned short IsUShort( int val );


extern CCheckUVCmd g_StudioMdlCheckUVCmd;


#endif // STUDIOMDL_H