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

#ifndef GL_MODEL_PRIVATE_H
#define GL_MODEL_PRIVATE_H

#ifdef _WIN32
#pragma once
#endif

#include "mathlib/vector4d.h"
#include "tier0/dbg.h"
#include "tier1/utlsymbol.h"
#include "idispinfo.h"
#include "shadowmgr.h"
#include "vcollide.h"
#include "studio.h"
#include "qlimits.h"
#include "host.h"
#include "gl_model.h"
#include "cmodel.h"
#include "bspfile.h"
#include "Overlay.h"
//#include "datamap.h"
#include "surfacehandle.h"
#include "mathlib/compressed_light_cube.h"
#include "datacache/imdlcache.h"
#include "bitmap/cubemap.h"


//-----------------------------------------------------------------------------
// forward declarations
//-----------------------------------------------------------------------------
struct studiomeshdata_t;
struct decal_t;
struct msurface1_t;
struct msurfacelighting_t;
struct msurfacenormal_t;
class ITexture;
class CEngineSprite;

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

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

class IMaterial;
class IMaterialVar;

// This is here for b/w compatibility with world surfaces that use
// WorldVertexTransition. We can get rid of it when we rev the engine.
#define TEXINFO_USING_BASETEXTURE2	0x0001

struct mtexinfo_t
{
	Vector4D	textureVecsTexelsPerWorldUnits[2];	// [s/t] unit vectors in world space. 
							                        // [i][3] is the s/t offset relative to the origin.
	Vector4D	lightmapVecsLuxelsPerWorldUnits[2];
	float		luxelsPerWorldUnit;
	float		worldUnitsPerLuxel;
	unsigned short flags;		// SURF_ flags.
	unsigned short texinfoFlags;// TEXINFO_ flags.
	IMaterial	*material;

	mtexinfo_t( mtexinfo_t const& src )
	{
		// copy constructor needed since Vector4D has no copy constructor
		memcpy( this, &src, sizeof(mtexinfo_t) );
	}
};

struct mnode_t
{
	// common with leaf
	int			contents;		// <0 to differentiate from leafs
	// -1 means check the node for visibility
	// -2 means don't check the node for visibility

	int			visframe;		// node needs to be traversed if current

	mnode_t		*parent;
	short		area;			// If all leaves below this node are in the same area, then
	// this is the area index. If not, this is -1.
	short		flags;

	VectorAligned		m_vecCenter;
	VectorAligned		m_vecHalfDiagonal;

// node specific
	cplane_t	*plane;
	mnode_t		*children[2];	

	unsigned short		firstsurface;
	unsigned short		numsurfaces;
};


struct mleaf_t
{
public:

	// common with node
	int			contents;		// contents mask
	int			visframe;		// node needs to be traversed if current

	mnode_t		*parent;

	short		area;
	short		flags;
	VectorAligned		m_vecCenter;
	VectorAligned		m_vecHalfDiagonal;


// leaf specific
	short		cluster;
	short		leafWaterDataID;

	unsigned short		firstmarksurface;
	unsigned short		nummarksurfaces;

	short		nummarknodesurfaces;
	short		unused;

	unsigned short	dispListStart;			// index into displist of first displacement
	unsigned short	dispCount;				// number of displacements in the list for this leaf
};


struct mleafwaterdata_t
{
	float	surfaceZ;
	float	minZ;
	short	surfaceTexInfoID;
	short	firstLeafIndex;
};


struct mcubemapsample_t
{
	Vector origin;
	ITexture *pTexture;
	unsigned char size; // default (mat_envmaptgasize) if 0, 1<<(size-1) otherwise.
};


typedef struct mportal_s
{
	unsigned short	*vertList;
	int				numportalverts;
	cplane_t		*plane;
	unsigned short	cluster[2];
//	int				visframe;
} mportal_t;


typedef struct mcluster_s
{
	unsigned short	*portalList;
	int				numportals;
} mcluster_t;


struct mmodel_t
{
	Vector		mins, maxs;
	Vector		origin;		// for sounds or lights
	float		radius;
	int			headnode;
	int			firstface, numfaces;
};

struct mprimitive_t
{
	int	type;
	unsigned short	firstIndex;
	unsigned short	indexCount;
	unsigned short	firstVert;
	unsigned short	vertCount;
};

struct mprimvert_t
{
	Vector		pos;
	float		texCoord[2];
	float		lightCoord[2];
};

typedef dleafambientindex_t mleafambientindex_t;
typedef dleafambientlighting_t mleafambientlighting_t;

struct LightShadowZBufferSample_t
{
	float m_flTraceDistance;								// how far we traced. 0 = invalid
	float m_flHitDistance;									// where we hit
};

#define SHADOW_ZBUF_RES 8									// 6 * 64 * 2 * 4 = 3k bytes per light

typedef CCubeMap< LightShadowZBufferSample_t, SHADOW_ZBUF_RES> lightzbuffer_t;

#include "model_types.h"

#define MODELFLAG_MATERIALPROXY					0x0001	// we've got a material proxy
#define MODELFLAG_TRANSLUCENT					0x0002	// we've got a translucent model
#define MODELFLAG_VERTEXLIT						0x0004	// we've got a vertex-lit model
#define MODELFLAG_TRANSLUCENT_TWOPASS			0x0008	// render opaque part in opaque pass
#define MODELFLAG_FRAMEBUFFER_TEXTURE			0x0010	// we need the framebuffer as a texture
#define MODELFLAG_HAS_DLIGHT					0x0020	// need to check dlights
#define MODELFLAG_STUDIOHDR_USES_FB_TEXTURE		0x0100	// persisted from studiohdr
#define MODELFLAG_STUDIOHDR_USES_BUMPMAPPING	0x0200	// persisted from studiohdr
#define MODELFLAG_STUDIOHDR_USES_ENV_CUBEMAP	0x0400	// persisted from studiohdr
#define MODELFLAG_STUDIOHDR_AMBIENT_BOOST		0x0800	// persisted from studiohdr
#define MODELFLAG_STUDIOHDR_DO_NOT_CAST_SHADOWS	0x1000	// persisted from studiohdr

struct worldbrushdata_t
{
	int			numsubmodels;

	int			numplanes;
	cplane_t	*planes;

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

	int			numleafwaterdata;
	mleafwaterdata_t *leafwaterdata;

	int			numvertexes;
	mvertex_t	*vertexes;

	int			numoccluders;
	doccluderdata_t *occluders;

	int			numoccluderpolys;
	doccluderpolydata_t *occluderpolys;

	int			numoccludervertindices;
	int			*occludervertindices;

	int				numvertnormalindices;	// These index vertnormals.
	unsigned short	*vertnormalindices;

	int			numvertnormals;
	Vector		*vertnormals;

	int			numnodes;
	mnode_t		*nodes;
	unsigned short *m_LeafMinDistToWater;

	int			numtexinfo;
	mtexinfo_t	*texinfo;

	int			numtexdata;
	csurface_t	*texdata;

	int         numDispInfos;
	HDISPINFOARRAY	hDispInfos;	// Use DispInfo_Index to get IDispInfos..

	/*
	int         numOrigSurfaces;
	msurface_t  *pOrigSurfaces;
	*/

	int			numsurfaces;
	msurface1_t	*surfaces1;
	msurface2_t	*surfaces2;
	msurfacelighting_t *surfacelighting;
	msurfacenormal_t *surfacenormals;

	bool		unloadedlightmaps;

	int			numvertindices;
	unsigned short *vertindices;

	int nummarksurfaces;
	SurfaceHandle_t *marksurfaces;

	ColorRGBExp32		*lightdata;

	int			numworldlights;
	dworldlight_t *worldlights;

	lightzbuffer_t *shadowzbuffers;

	// non-polygon primitives (strips and lists)
	int			numprimitives;
	mprimitive_t *primitives;

	int			numprimverts;
	mprimvert_t *primverts;

	int			numprimindices;
	unsigned short *primindices;

	int				m_nAreas;
	darea_t			*m_pAreas;

	int				m_nAreaPortals;
	dareaportal_t	*m_pAreaPortals;

	int				m_nClipPortalVerts;
	Vector			*m_pClipPortalVerts;

	mcubemapsample_t  *m_pCubemapSamples;
	int				   m_nCubemapSamples;

	int				m_nDispInfoReferences;
	unsigned short	*m_pDispInfoReferences;

	mleafambientindex_t		*m_pLeafAmbient;
	mleafambientlighting_t	*m_pAmbientSamples;
#if 0
	int			numportals;
	mportal_t	*portals;

	int			numclusters;
	mcluster_t	*clusters;

	int			numportalverts;
	unsigned short *portalverts;

	int			numclusterportals;
	unsigned short *clusterportals;
#endif
};
// only models with type "mod_brush" have this data
struct brushdata_t
{
	worldbrushdata_t	*pShared;
	int			firstmodelsurface, nummodelsurfaces;

	unsigned short	renderHandle;
	unsigned short	firstnode;
};

// only models with type "mod_sprite" have this data
struct spritedata_t
{
	int				numframes;
	int				width;
	int				height;
	CEngineSprite	*sprite;
};

struct model_t
{
	FileNameHandle_t	fnHandle;
	CUtlString			strName;

	int					nLoadFlags;		// mark loaded/not loaded
	int					nServerCount;	// marked at load
	IMaterial			**ppMaterials;	// null-terminated runtime material cache; ((intptr_t*)(ppMaterials))[-1] == nMaterials

	modtype_t			type;
	int					flags;			// MODELFLAG_???

	// volume occupied by the model graphics	
	Vector				mins, maxs;
	float				radius;

	union
	{
		brushdata_t		brush;
		MDLHandle_t		studio;
		spritedata_t	sprite;
	};
};


//-----------------------------------------------------------------------------
// Decals
//-----------------------------------------------------------------------------

struct decallist_t
{
	DECLARE_SIMPLE_DATADESC();

	Vector		position;
	char		name[ 128 ];
	short		entityIndex;
	byte		depth;
	byte		flags;

	// This is the surface plane that we hit so that we can move certain decals across
	//  transitions if they hit similar geometry
	Vector		impactPlaneNormal;
};


inline class IDispInfo *MLeaf_Disaplcement( mleaf_t *pLeaf, int index, worldbrushdata_t *pData = host_state.worldbrush )
{
	Assert(index<pLeaf->dispCount);
	int dispIndex = pData->m_pDispInfoReferences[pLeaf->dispListStart+index];
	return DispInfo_IndexArray( pData->hDispInfos, dispIndex );
}

#define	MAXLIGHTMAPS	4

// drawing surface flags
#define SURFDRAW_NOLIGHT		0x00000001		// no lightmap
#define	SURFDRAW_NODE			0x00000002		// This surface is on a node
#define	SURFDRAW_SKY			0x00000004		// portal to sky
#define SURFDRAW_BUMPLIGHT		0x00000008		// Has multiple lightmaps for bump-mapping
#define SURFDRAW_NODRAW			0x00000010		// don't draw this surface, not really visible
#define SURFDRAW_TRANS			0x00000020		// sort this surface from back to front
#define SURFDRAW_PLANEBACK		0x00000040		// faces away from plane of the node that stores this face
#define SURFDRAW_DYNAMIC		0x00000080		// Don't use a static buffer for this face
#define SURFDRAW_TANGENTSPACE	0x00000100		// This surface needs a tangent space
#define SURFDRAW_NOCULL			0x00000200		// Don't bother backface culling these
#define SURFDRAW_HASLIGHTSYTLES 0x00000400		// has a lightstyle other than 0
#define SURFDRAW_HAS_DISP		0x00000800		// has a dispinfo
#define SURFDRAW_ALPHATEST		0x00001000		// Is alphstested
#define SURFDRAW_NOSHADOWS		0x00002000		// No shadows baby
#define SURFDRAW_NODECALS		0x00004000		// No decals baby
#define SURFDRAW_HAS_PRIMS		0x00008000		// has a list of prims
#define SURFDRAW_WATERSURFACE	0x00010000	// This is a water surface
#define SURFDRAW_UNDERWATER		0x00020000
#define SURFDRAW_ABOVEWATER		0x00040000
#define SURFDRAW_HASDLIGHT		0x00080000	// Has some kind of dynamic light that must be checked
#define SURFDRAW_DLIGHTPASS		0x00100000	// Must be drawn in the dlight pass
#define SURFDRAW_UNUSED2		0x00200000	// unused
#define SURFDRAW_VERTCOUNT_MASK	0xFF000000	// 8 bits of vertex count
#define SURFDRAW_SORTGROUP_MASK	0x00C00000	// 2 bits of sortgroup

#define SURFDRAW_VERTCOUNT_SHIFT	24
#define SURFDRAW_SORTGROUP_SHIFT	22

// NOTE: 16-bytes, preserve size/alignment - we index this alot
struct msurface1_t
{
	// garymct - are these needed? - used by decal projection code
	int		textureMins[2];		// smallest unnormalized s/t position on the surface.
	short	textureExtents[2];	// ?? s/t texture size, 1..512 for all non-sky surfaces

	struct
	{
		unsigned short numPrims;
		unsigned short firstPrimID;			// index into primitive list if numPrims > 0
	} prims;
};

#pragma pack(1)
struct msurfacenormal_t
{
	unsigned int firstvertnormal;
//	unsigned short	firstvertnormal;
	// FIXME: Should I just point to the leaf here since it has this data?????????????
//	short fogVolumeID;			// -1 if not in fog  
};
#pragma pack()

// This is a single cache line (32 bytes)
struct msurfacelighting_t
{
	// You read that minus sign right. See the comment below.
	ColorRGBExp32 *AvgLightColor( int nLightStyleIndex ) { return m_pSamples - (nLightStyleIndex + 1); }

	// Lightmap info
	short m_LightmapMins[2];
	short m_LightmapExtents[2];
	short m_OffsetIntoLightmapPage[2];

	int m_nLastComputedFrame;	// last frame the surface's lightmap was recomputed
	int m_fDLightBits;			// Indicates which dlights illuminates this surface.
	int m_nDLightFrame;			// Indicates the last frame in which dlights illuminated this surface

	unsigned char m_nStyles[MAXLIGHTMAPS];	// index into d_lightstylevalue[] for animated lights 
											// no one surface can be effected by more than 4 
											// animated lights.

	// NOTE: This is tricky. To get this to fit in a single cache line,
	// and to save the extra memory of not having to store average light colors for
	// lightstyles that are not used, I store between 0 and 4 average light colors +before+
	// the samples, depending on how many lightstyles there are. Naturally, accessing
	// an average color for an undefined lightstyle on the surface results in undefined results.
	// 0->4 avg light colors, *in reverse order from m_nStyles* + [numstyles*surfsize]
	ColorRGBExp32 *m_pSamples;
};

const int WORLD_DECAL_HANDLE_INVALID = 0xFFFF;
typedef unsigned short WorldDecalHandle_t;

#pragma pack(1)
// NOTE: 32-bytes.  Aligned/indexed often
struct msurface2_t
{
	unsigned int			flags;			// see SURFDRAW_ #defines (only 22-bits right now)
	// These are packed in to flags now
	//unsigned char			vertCount;		// number of verts for this surface
	//unsigned char			sortGroup;		// only uses 2 bits, subdivide?
	cplane_t				*plane;			// pointer to shared plane	
	int						firstvertindex;	// look up in model->vertindices[] (only uses 17-18 bits?)
	WorldDecalHandle_t		decals;
	ShadowDecalHandle_t		m_ShadowDecals; // unsigned short
	OverlayFragmentHandle_t m_nFirstOverlayFragment;	// First overlay fragment on the surface (short)
	short					materialSortID;
	unsigned short			vertBufferIndex;

	unsigned short			m_bDynamicShadowsEnabled : 1;	// Can this surface receive dynamic shadows?
	unsigned short			texinfo : 15;

	IDispInfo				*pDispInfo;         // displacement map information
	int						visframe;		// should be drawn when node is crossed
};
#pragma pack()

inline unsigned short MSurf_AreDynamicShadowsEnabled( SurfaceHandle_t surfID )
{
	return surfID->m_bDynamicShadowsEnabled;
}

inline int MSurf_Index( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	int surfaceIndex = surfID - pData->surfaces2;
	Assert(surfaceIndex >= 0 && surfaceIndex < pData->numsurfaces);
	return surfaceIndex;
}

inline const SurfaceHandle_t SurfaceHandleFromIndex( int surfaceIndex, const worldbrushdata_t *pData )
{
	return &pData->surfaces2[surfaceIndex];
}

inline SurfaceHandle_t SurfaceHandleFromIndex( int surfaceIndex, worldbrushdata_t *pData = host_state.worldbrush )
{
	return &pData->surfaces2[surfaceIndex];
}

#if _DEBUG
#define ASSERT_SURF_VALID(surfID) MSurf_Index(surfID)
#else
#define ASSERT_SURF_VALID(surfID)
#endif

inline unsigned int& MSurf_Flags( SurfaceHandle_t surfID )
{
	return surfID->flags;
}

inline bool SurfaceHasDispInfo( SurfaceHandle_t surfID )
{
	return ( MSurf_Flags( surfID ) & SURFDRAW_HAS_DISP ) ? true : false;
}

inline bool SurfaceHasPrims( SurfaceHandle_t surfID )
{
	return ( MSurf_Flags( surfID ) & SURFDRAW_HAS_PRIMS ) ? true : false;
}

inline int& MSurf_VisFrame( SurfaceHandle_t surfID )
{
	return surfID->visframe;
}

inline int MSurf_SortGroup( SurfaceHandle_t surfID )
{
	return (surfID->flags & SURFDRAW_SORTGROUP_MASK) >> SURFDRAW_SORTGROUP_SHIFT;
}

inline void MSurf_SetSortGroup( SurfaceHandle_t surfID, int sortGroup )
{
	unsigned int flags = (sortGroup << SURFDRAW_SORTGROUP_SHIFT) & SURFDRAW_SORTGROUP_MASK;
	surfID->flags |= flags;
}

/*
inline int& MSurf_DLightFrame( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfacelighting[surfID].dlightframe;
}
*/
inline int& MSurf_DLightBits( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	int surfaceIndex = MSurf_Index(surfID,pData);
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfacelighting[surfaceIndex].m_fDLightBits;
}

inline cplane_t& MSurf_Plane( SurfaceHandle_t surfID )
{
	return *surfID->plane;
}

inline int& MSurf_FirstVertIndex( SurfaceHandle_t surfID )
{
	return surfID->firstvertindex;
}

inline int MSurf_VertCount( SurfaceHandle_t surfID )
{
	return (surfID->flags >> SURFDRAW_VERTCOUNT_SHIFT) & 0xFF;
}

inline void MSurf_SetVertCount( SurfaceHandle_t surfID, int vertCount )
{
	int flags = (vertCount << SURFDRAW_VERTCOUNT_SHIFT) & SURFDRAW_VERTCOUNT_MASK;
	surfID->flags |= flags;
}

inline int *MSurf_TextureMins( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	int surfaceIndex = MSurf_Index(surfID,pData);
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfaces1[surfaceIndex].textureMins;
}

inline short *MSurf_TextureExtents( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	int surfaceIndex = MSurf_Index(surfID,pData);
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfaces1[surfaceIndex].textureExtents;
}

inline short *MSurf_LightmapMins( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	int surfaceIndex = MSurf_Index(surfID,pData);
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfacelighting[surfaceIndex].m_LightmapMins;
}

inline short *MSurf_LightmapExtents( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	int surfaceIndex = MSurf_Index(surfID,pData);
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfacelighting[surfaceIndex].m_LightmapExtents;
}

inline short MSurf_MaxLightmapSizeWithBorder( SurfaceHandle_t surfID )
{
//	ASSERT_SURF_VALID( surfID );
	return SurfaceHasDispInfo( surfID ) ? MAX_DISP_LIGHTMAP_DIM_INCLUDING_BORDER : MAX_BRUSH_LIGHTMAP_DIM_INCLUDING_BORDER;
}

inline short MSurf_MaxLightmapSizeWithoutBorder( SurfaceHandle_t surfID )
{
//	ASSERT_SURF_VALID( surfID );
	return SurfaceHasDispInfo( surfID ) ? MAX_DISP_LIGHTMAP_DIM_WITHOUT_BORDER : MAX_BRUSH_LIGHTMAP_DIM_WITHOUT_BORDER;
}

inline mtexinfo_t *MSurf_TexInfo( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	return &pData->texinfo[surfID->texinfo];
}

inline WorldDecalHandle_t& MSurf_Decals( SurfaceHandle_t surfID )
{
	return surfID->decals;
}

inline bool SurfaceHasDecals( SurfaceHandle_t surfID )
{
	return ( MSurf_Decals( surfID ) != WORLD_DECAL_HANDLE_INVALID ) ? true : false;
}

inline ShadowDecalHandle_t& MSurf_ShadowDecals( SurfaceHandle_t surfID )
{
	return surfID->m_ShadowDecals;
}


inline ColorRGBExp32 *MSurf_AvgLightColor( SurfaceHandle_t surfID, int nIndex, worldbrushdata_t *pData = host_state.worldbrush )
{
	int surfaceIndex = MSurf_Index(surfID,pData);
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfacelighting[surfaceIndex].AvgLightColor(nIndex);
}

inline byte *MSurf_Styles( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	int surfaceIndex = MSurf_Index(surfID,pData);
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfacelighting[surfaceIndex].m_nStyles;
}

/*
inline int *MSurf_CachedLight( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfacelighting[surfID].cached_light;
}

inline short& MSurf_CachedDLight( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfacelighting[surfID].cached_dlight;
}
*/

inline unsigned short MSurf_NumPrims( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	if ( SurfaceHasDispInfo( surfID ) || !SurfaceHasPrims( surfID ))
		return 0;

	int surfaceIndex = MSurf_Index(surfID,pData);
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfaces1[surfaceIndex].prims.numPrims;
}

inline unsigned short MSurf_FirstPrimID( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	if ( SurfaceHasDispInfo( surfID ) )
		return 0;
	int surfaceIndex = MSurf_Index(surfID,pData);
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfaces1[surfaceIndex].prims.firstPrimID;
}

inline ColorRGBExp32 *MSurf_Samples( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	int surfaceIndex = MSurf_Index(surfID,pData);
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfacelighting[surfaceIndex].m_pSamples;
}

inline IDispInfo *MSurf_DispInfo( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	return surfID->pDispInfo;
}

//inline unsigned short &MSurf_FirstVertNormal( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
inline unsigned int &MSurf_FirstVertNormal( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	int surfaceIndex = MSurf_Index(surfID,pData);
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	Assert( pData->surfacenormals[surfaceIndex].firstvertnormal < MAX_MAP_VERTNORMALINDICES );
	return pData->surfacenormals[surfaceIndex].firstvertnormal;
}

inline unsigned short &MSurf_VertBufferIndex( SurfaceHandle_t surfID )
{
	return surfID->vertBufferIndex;
}

inline short& MSurf_MaterialSortID( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	return surfID->materialSortID;
}

inline short *MSurf_OffsetIntoLightmapPage( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	int surfaceIndex = MSurf_Index(surfID,pData);
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return pData->surfacelighting[surfaceIndex].m_OffsetIntoLightmapPage;
}

inline VPlane MSurf_GetForwardFacingPlane( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
//	ASSERT_SURF_VALID( surfID );
	Assert( pData );
	return VPlane( MSurf_Plane( surfID).normal, MSurf_Plane( surfID ).dist );
}


inline OverlayFragmentHandle_t &MSurf_OverlayFragmentList( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	return surfID->m_nFirstOverlayFragment;
}

inline msurfacelighting_t *SurfaceLighting( SurfaceHandle_t surfID, worldbrushdata_t *pData = host_state.worldbrush )
{
	int surfaceIndex = MSurf_Index(surfID,pData);
	Assert( pData );
	return &pData->surfacelighting[surfaceIndex];
}

#endif // GL_MODEL_PRIVATE_H