text: /*
  ===========================================================================
  
  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 __TR_LOCAL_H__
  #define __TR_LOCAL_H__
  
  #include "../idlib/precompiled.h"
  
  #include "GLState.h"
  #include "ScreenRect.h"
  #include "ImageOpts.h"
  #include "Image.h"
  #include "RenderTexture.h"
  #include "Font.h"
  
  // everything that is needed by the backend needs
  // to be double buffered to allow it to run in
  // parallel on a dual cpu machine
  const int SMP_FRAMES				= 1;
  
  // maximum texture units
  const int MAX_PROG_TEXTURE_PARMS	= 16;
  
  const int FALLOFF_TEXTURE_SIZE		= 64;
  
  const float	DEFAULT_FOG_DISTANCE	= 500.0f;
  
  // picky to get the bilerp correct at terminator
  const int FOG_ENTER_SIZE			= 64;
  const float FOG_ENTER				= (FOG_ENTER_SIZE+1.0f)/(FOG_ENTER_SIZE*2);
  
  enum demoCommand_t {
  	DC_BAD,
  	DC_RENDERVIEW,
  	DC_UPDATE_ENTITYDEF,
  	DC_DELETE_ENTITYDEF,
  	DC_UPDATE_LIGHTDEF,
  	DC_DELETE_LIGHTDEF,
  	DC_LOADMAP,
  	DC_CROP_RENDER,
  	DC_UNCROP_RENDER,
  	DC_CAPTURE_RENDER,
  	DC_END_FRAME,
  	DC_DEFINE_MODEL,
  	DC_SET_PORTAL_STATE,
  	DC_UPDATE_SOUNDOCCLUSION,
  	DC_GUI_MODEL
  };
  
  /*
  ==============================================================================
  
  SURFACES
  
  ==============================================================================
  */
  
  #include "ModelDecal.h"
  #include "ModelOverlay.h"
  #include "Interaction.h"
  
  class idRenderWorldLocal;
  struct viewEntity_t;
  struct viewLight_t;
  
  // drawSurf_t structures command the back end to render surfaces
  // a given srfTriangles_t may be used with multiple viewEntity_t,
  // as when viewed in a subview or multiple viewport render, or
  // with multiple shaders when skinned, or, possibly with multiple
  // lights, although currently each lighting interaction creates
  // unique srfTriangles_t
  // drawSurf_t are always allocated and freed every frame, they are never cached
  
  struct drawSurf_t {
  	const srfTriangles_t *	frontEndGeo;		// don't use on the back end, it may be updated by the front end!
  	int						numIndexes;
  	vertCacheHandle_t		indexCache;			// triIndex_t
  	vertCacheHandle_t		ambientCache;		// idDrawVert
  	vertCacheHandle_t		shadowCache;		// idShadowVert / idShadowVertSkinned
  	vertCacheHandle_t		jointCache;			// idJointMat
  	const viewEntity_t *	space;
  	const idMaterial *		material;			// may be NULL for shadow volumes
  	uint64					extraGLState;		// Extra GL state |'d with material->stage[].drawStateBits
  	float					sort;				// material->sort, modified by gui / entity sort offsets
  	const float	 *			shaderRegisters;	// evaluated and adjusted for referenceShaders
  	drawSurf_t *			nextOnLight;		// viewLight chains
  	drawSurf_t **			linkChain;			// defer linking to lights to a serial section to avoid a mutex
  	idScreenRect			scissorRect;		// for scissor clipping, local inside renderView viewport
  	int						renderZFail;
  	volatile shadowVolumeState_t shadowVolumeState;
  };
  
  // areas have references to hold all the lights and entities in them
  struct areaReference_t {
  	areaReference_t *		areaNext;				// chain in the area
  	areaReference_t *		areaPrev;
  	areaReference_t *		ownerNext;				// chain on either the entityDef or lightDef
  	idRenderEntityLocal *	entity;					// only one of entity / light will be non-NULL
  	idRenderLightLocal *	light;					// only one of entity / light will be non-NULL
  	struct portalArea_s	*	area;					// so owners can find all the areas they are in
  };
  
  
  // idRenderLight should become the new public interface replacing the qhandle_t to light defs in the idRenderWorld interface
  class idRenderLight {
  public:
  	virtual					~idRenderLight() {}
  
  	virtual void			FreeRenderLight() = 0;
  	virtual void			UpdateRenderLight( const renderLight_t *re, bool forceUpdate = false ) = 0;
  	virtual void			GetRenderLight( renderLight_t *re ) = 0;
  	virtual void			ForceUpdate() = 0;
  	virtual int				GetIndex() = 0;
  };
  
  
  // idRenderEntity should become the new public interface replacing the qhandle_t to entity defs in the idRenderWorld interface
  class idRenderEntity {
  public:
  	virtual					~idRenderEntity() {}
  
  	virtual void			FreeRenderEntity() = 0;
  	virtual void			UpdateRenderEntity( const renderEntity_t *re, bool forceUpdate = false ) = 0;
  	virtual void			GetRenderEntity( renderEntity_t *re ) = 0;
  	virtual void			ForceUpdate() = 0;
  	virtual int				GetIndex() = 0;
  
  	// overlays are extra polygons that deform with animating models for blood and damage marks
  	virtual void			ProjectOverlay( const idPlane localTextureAxis[2], const idMaterial *material ) = 0;
  	virtual void			RemoveDecals() = 0;
  };
  
  
  class idRenderLightLocal : public idRenderLight {
  public:
  							idRenderLightLocal();
  
  	virtual void			FreeRenderLight();
  	virtual void			UpdateRenderLight( const renderLight_t *re, bool forceUpdate = false );
  	virtual void			GetRenderLight( renderLight_t *re );
  	virtual void			ForceUpdate();
  	virtual int				GetIndex();
  
  	bool					LightCastsShadows() const { return parms.forceShadows || ( !parms.noShadows && lightShader->LightCastsShadows() ); }
  
  	renderLight_t			parms;					// specification
  
  	bool					lightHasMoved;			// the light has changed its position since it was
  													// first added, so the prelight model is not valid
  	idRenderWorldLocal *	world;
  	int						index;					// in world lightdefs
  
  	int						areaNum;				// if not -1, we may be able to cull all the light's
  													// interactions if !viewDef->connectedAreas[areaNum]
  
  	int						lastModifiedFrameNum;	// to determine if it is constantly changing,
  													// and should go in the dynamic frame memory, or kept
  													// in the cached memory
  	bool					archived;				// for demo writing
  
  
  	// derived information
  	idPlane					lightProject[4];		// old style light projection where Z and W are flipped and projected lights lightProject[3] is divided by ( zNear + zFar )
  	idRenderMatrix			baseLightProject;		// global xyz1 to projected light strq
  	idRenderMatrix			inverseBaseLightProject;// transforms the zero-to-one cube to exactly cover the light in world space
  
  	const idMaterial *		lightShader;			// guaranteed to be valid, even if parms.shader isn't
  	idImage *				falloffImage;
  
  	idVec3					globalLightOrigin;		// accounting for lightCenter and parallel
  	idBounds				globalLightBounds;
  
  	int						viewCount;				// if == tr.viewCount, the light is on the viewDef->viewLights list
  	viewLight_t *			viewLight;
  
  	areaReference_t *		references;				// each area the light is present in will have a lightRef
  	idInteraction *			firstInteraction;		// doubly linked list
  	idInteraction *			lastInteraction;
  
  	struct doublePortal_s *	foggedPortals;
  };
  
  
  class idRenderEntityLocal : public idRenderEntity {
  public:
  							idRenderEntityLocal();
  
  	virtual void			FreeRenderEntity();
  	virtual void			UpdateRenderEntity( const renderEntity_t *re, bool forceUpdate = false );
  	virtual void			GetRenderEntity( renderEntity_t *re );
  	virtual void			ForceUpdate();
  	virtual int				GetIndex();
  
  	// overlays are extra polygons that deform with animating models for blood and damage marks
  	virtual void			ProjectOverlay( const idPlane localTextureAxis[2], const idMaterial *material );
  	virtual void			RemoveDecals();
  
  	bool					IsDirectlyVisible() const;
  
  	renderEntity_t			parms;
  
  	float					modelMatrix[16];		// this is just a rearrangement of parms.axis and parms.origin
  	idRenderMatrix			modelRenderMatrix;
  	idRenderMatrix			inverseBaseModelProject;// transforms the unit cube to exactly cover the model in world space
  
  	idRenderWorldLocal *	world;
  	int						index;					// in world entityDefs
  
  	int						lastModifiedFrameNum;	// to determine if it is constantly changing,
  													// and should go in the dynamic frame memory, or kept
  													// in the cached memory
  	bool					archived;				// for demo writing
  
  	idRenderModel *			dynamicModel;			// if parms.model->IsDynamicModel(), this is the generated data
  	int						dynamicModelFrameCount;	// continuously animating dynamic models will recreate
  													// dynamicModel if this doesn't == tr.viewCount
  	idRenderModel *			cachedDynamicModel;
  
  
  	// the local bounds used to place entityRefs, either from parms for dynamic entities, or a model bounds
  	idBounds				localReferenceBounds;	
  
  	// axis aligned bounding box in world space, derived from refernceBounds and
  	// modelMatrix in R_CreateEntityRefs()
  	idBounds				globalReferenceBounds;
  
  	// a viewEntity_t is created whenever a idRenderEntityLocal is considered for inclusion
  	// in a given view, even if it turns out to not be visible
  	int						viewCount;				// if tr.viewCount == viewCount, viewEntity is valid,
  													// but the entity may still be off screen
  	viewEntity_t *			viewEntity;				// in frame temporary memory
  
  	idRenderModelDecal *	decals;					// decals that have been projected on this model
  	idRenderModelOverlay *	overlays;				// blood overlays on animated models
  
  	areaReference_t *		entityRefs;				// chain of all references
  	idInteraction *			firstInteraction;		// doubly linked list
  	idInteraction *			lastInteraction;
  
  	bool					needsPortalSky;
  };
  
  struct shadowOnlyEntity_t {
  	shadowOnlyEntity_t *	next;
  	idRenderEntityLocal	*	edef;
  };
  
  // viewLights are allocated on the frame temporary stack memory
  // a viewLight contains everything that the back end needs out of an idRenderLightLocal,
  // which the front end may be modifying simultaniously if running in SMP mode.
  // a viewLight may exist even without any surfaces, and may be relevent for fogging,
  // but should never exist if its volume does not intersect the view frustum
  struct viewLight_t {
  	viewLight_t *			next;
  
  	// back end should NOT reference the lightDef, because it can change when running SMP
  	idRenderLightLocal *	lightDef;
  
  	// for scissor clipping, local inside renderView viewport
  	// scissorRect.Empty() is true if the viewEntity_t was never actually
  	// seen through any portals
  	idScreenRect			scissorRect;
  
  	// R_AddSingleLight() determined that the light isn't actually needed
  	bool					removeFromList;
  
  	// R_AddSingleLight builds this list of entities that need to be added
  	// to the viewEntities list because they potentially cast shadows into
  	// the view, even though the aren't directly visible
  	shadowOnlyEntity_t *	shadowOnlyViewEntities;
  
  	enum interactionState_t {
  		INTERACTION_UNCHECKED,
  		INTERACTION_NO,
  		INTERACTION_YES
  	};
  	byte *					entityInteractionState;		// [numEntities]
  
  	idVec3					globalLightOrigin;			// global light origin used by backend
  	idPlane					lightProject[4];			// light project used by backend
  	idPlane					fogPlane;					// fog plane for backend fog volume rendering
  	idRenderMatrix			inverseBaseLightProject;	// the matrix for deforming the 'zeroOneCubeModel' to exactly cover the light volume in world space
  	const idMaterial *		lightShader;				// light shader used by backend
  	const float	*			shaderRegisters;			// shader registers used by backend
  	idImage *				falloffImage;				// falloff image used by backend
  
  	drawSurf_t *			globalShadows;				// shadow everything
  	drawSurf_t *			localInteractions;			// don't get local shadows
  	drawSurf_t *			localShadows;				// don't shadow local surfaces
  	drawSurf_t *			globalInteractions;			// get shadows from everything
  	drawSurf_t *			translucentInteractions;	// translucent interactions don't get shadows
  
  	// R_AddSingleLight will build a chain of parameters here to setup shadow volumes
  	preLightShadowVolumeParms_t *	preLightShadowVolumes;
  };
  
  // a viewEntity is created whenever a idRenderEntityLocal is considered for inclusion
  // in the current view, but it may still turn out to be culled.
  // viewEntity are allocated on the frame temporary stack memory
  // a viewEntity contains everything that the back end needs out of a idRenderEntityLocal,
  // which the front end may be modifying simultaneously if running in SMP mode.
  // A single entityDef can generate multiple viewEntity_t in a single frame, as when seen in a mirror
  struct viewEntity_t {
  	viewEntity_t *			next;
  
  	// back end should NOT reference the entityDef, because it can change when running SMP
  	idRenderEntityLocal	*	entityDef;
  
  	// for scissor clipping, local inside renderView viewport
  	// scissorRect.Empty() is true if the viewEntity_t was never actually
  	// seen through any portals, but was created for shadow casting.
  	// a viewEntity can have a non-empty scissorRect, meaning that an area
  	// that it is in is visible, and still not be visible.
  	idScreenRect			scissorRect;
  
  	bool					isGuiSurface;			// force two sided and vertex colors regardless of material setting
  
  	bool					skipMotionBlur;
  
  	bool					weaponDepthHack;
  	float					modelDepthHack;
  		
  	float					modelMatrix[16];		// local coords to global coords
  	float					modelViewMatrix[16];	// local coords to eye coords
  
  	idRenderMatrix			mvp;
  
  	// parallelAddModels will build a chain of surfaces here that will need to
  	// be linked to the lights or added to the drawsurf list in a serial code section
  	drawSurf_t *			drawSurfs;
  
  	// R_AddSingleModel will build a chain of parameters here to setup shadow volumes
  	staticShadowVolumeParms_t *		staticShadowVolumes;
  	dynamicShadowVolumeParms_t *	dynamicShadowVolumes;
  };
  
  
  const int	MAX_CLIP_PLANES	= 1;				// we may expand this to six for some subview issues
  
  // viewDefs are allocated on the frame temporary stack memory
  struct viewDef_t {
  	// specified in the call to DrawScene()
  	renderView_t		renderView;
  
  	float				projectionMatrix[16];
  	idRenderMatrix		projectionRenderMatrix;	// tech5 version of projectionMatrix
  	viewEntity_t		worldSpace;
  
  	idRenderWorldLocal *renderWorld;
  
  	idVec3				initialViewAreaOrigin;
  	// Used to find the portalArea that view flooding will take place from.
  	// for a normal view, the initialViewOrigin will be renderView.viewOrg,
  	// but a mirror may put the projection origin outside
  	// of any valid area, or in an unconnected area of the map, so the view
  	// area must be based on a point just off the surface of the mirror / subview.
  	// It may be possible to get a failed portal pass if the plane of the
  	// mirror intersects a portal, and the initialViewAreaOrigin is on
  	// a different side than the renderView.viewOrg is.
  
  	bool				isSubview;				// true if this view is not the main view
  	bool				isMirror;				// the portal is a mirror, invert the face culling
  	bool				isXraySubview;
  
  	bool				isEditor;
  	bool				is2Dgui;
  
  	int					numClipPlanes;			// mirrors will often use a single clip plane
  	idPlane				clipPlanes[MAX_CLIP_PLANES];		// in world space, the positive side
  												// of the plane is the visible side
  	idScreenRect		viewport;				// in real pixels and proper Y flip
  
  	idScreenRect		scissor;
  	// for scissor clipping, local inside renderView viewport
  	// subviews may only be rendering part of the main view
  	// these are real physical pixel values, possibly scaled and offset from the
  	// renderView x/y/width/height
  
  	viewDef_t *			superView;				// never go into an infinite subview loop 
  	const drawSurf_t *	subviewSurface;
  
  	// drawSurfs are the visible surfaces of the viewEntities, sorted
  	// by the material sort parameter
  	drawSurf_t **		drawSurfs;				// we don't use an idList for this, because
  	int					numDrawSurfs;			// it is allocated in frame temporary memory
  	int					maxDrawSurfs;			// may be resized
  
  	viewLight_t	*		viewLights;			// chain of all viewLights effecting view
  	viewEntity_t *		viewEntitys;			// chain of all viewEntities effecting view, including off screen ones casting shadows
  	// we use viewEntities as a check to see if a given view consists solely
  	// of 2D rendering, which we can optimize in certain ways.  A 2D view will
  	// not have any viewEntities
  
  	idPlane				frustum[6];				// positive sides face outward, [4] is the front clip plane
  
  	int					areaNum;				// -1 = not in a valid area
  
  	// An array in frame temporary memory that lists if an area can be reached without
  	// crossing a closed door.  This is used to avoid drawing interactions
  	// when the light is behind a closed door.
  	bool *				connectedAreas;
  };
  
  
  // complex light / surface interactions are broken up into multiple passes of a
  // simple interaction shader
  struct drawInteraction_t {
  	const drawSurf_t *	surf;
  
  	idImage *			bumpImage;
  	idImage *			diffuseImage;
  	idImage *			specularImage;
  
  	idVec4				diffuseColor;	// may have a light color baked into it
  	idVec4				specularColor;	// may have a light color baked into it
  	stageVertexColor_t	vertexColor;	// applies to both diffuse and specular
  
  	int					ambientLight;	// use tr.ambientNormalMap instead of normalization cube map 
  
  	// these are loaded into the vertex program
  	idVec4				bumpMatrix[2];
  	idVec4				diffuseMatrix[2];
  	idVec4				specularMatrix[2];
  };
  
  /*
  =============================================================
  
  RENDERER BACK END COMMAND QUEUE
  
  TR_CMDS
  
  =============================================================
  */
  
  enum renderCommand_t {
  	RC_NOP,
  	RC_DRAW_VIEW_3D,	// may be at a reduced resolution, will be upsampled before 2D GUIs
  	RC_DRAW_VIEW_GUI,	// not resolution scaled
  	RC_SET_BUFFER,
  	RC_COPY_RENDER,
  	RC_POST_PROCESS,
  };
  
  struct emptyCommand_t {
  	renderCommand_t		commandId;
  	renderCommand_t *	next;
  };
  
  struct setBufferCommand_t {
  	renderCommand_t		commandId;
  	renderCommand_t *	next;
  	GLenum	buffer;
  };
  
  struct drawSurfsCommand_t {
  	renderCommand_t		commandId;
  	renderCommand_t *	next;
  	viewDef_t *			viewDef;
  };
  
  struct copyRenderCommand_t {
  	renderCommand_t		commandId;
  	renderCommand_t *	next;
  	int					x;
  	int					y;
  	int					imageWidth;
  	int					imageHeight;
  	idImage	*			image;
  	int					cubeFace;					// when copying to a cubeMap
  	bool				clearColorAfterCopy;
  };
  
  struct postProcessCommand_t {
  	renderCommand_t		commandId;
  	renderCommand_t *	next;
  	viewDef_t *			viewDef;
  };
  
  //=======================================================================
  
  // this is the inital allocation for max number of drawsurfs
  // in a given view, but it will automatically grow if needed
  const int INITIAL_DRAWSURFS =		2048;
  
  enum frameAllocType_t {
  	FRAME_ALLOC_VIEW_DEF,
  	FRAME_ALLOC_VIEW_ENTITY,
  	FRAME_ALLOC_VIEW_LIGHT,
  	FRAME_ALLOC_SURFACE_TRIANGLES,
  	FRAME_ALLOC_DRAW_SURFACE,
  	FRAME_ALLOC_INTERACTION_STATE,
  	FRAME_ALLOC_SHADOW_ONLY_ENTITY,
  	FRAME_ALLOC_SHADOW_VOLUME_PARMS,
  	FRAME_ALLOC_SHADER_REGISTER,
  	FRAME_ALLOC_DRAW_SURFACE_POINTER,
  	FRAME_ALLOC_DRAW_COMMAND,
  	FRAME_ALLOC_UNKNOWN,
  	FRAME_ALLOC_MAX
  };
  
  // all of the information needed by the back end must be
  // contained in a idFrameData.  This entire structure is
  // duplicated so the front and back end can run in parallel
  // on an SMP machine.
  class idFrameData {
  public:
  	idSysInterlockedInteger	frameMemoryAllocated;
  	idSysInterlockedInteger	frameMemoryUsed;
  	byte *					frameMemory;
  
  	int						highWaterAllocated;	// max used on any frame
  	int						highWaterUsed;
  
  	// the currently building command list commands can be inserted
  	// at the front if needed, as required for dynamically generated textures
  	emptyCommand_t *		cmdHead;	// may be of other command type based on commandId
  	emptyCommand_t *		cmdTail;
  };
  
  extern	idFrameData	*frameData;
  
  //=======================================================================
  
  void R_AddDrawViewCmd( viewDef_t *parms, bool guiOnly );
  void R_AddDrawPostProcess( viewDef_t *parms );
  
  void R_ReloadGuis_f( const idCmdArgs &args );
  void R_ListGuis_f( const idCmdArgs &args );
  
  void *R_GetCommandBuffer( int bytes );
  
  // this allows a global override of all materials
  bool R_GlobalShaderOverride( const idMaterial **shader );
  
  // this does various checks before calling the idDeclSkin
  const idMaterial *R_RemapShaderBySkin( const idMaterial *shader, const idDeclSkin *customSkin, const idMaterial *customShader );
  
  
  //====================================================
  
  
  /*
  ** performanceCounters_t
  */
  struct performanceCounters_t {
  	int		c_box_cull_in;
  	int		c_box_cull_out;
  	int		c_createInteractions;	// number of calls to idInteraction::CreateInteraction
  	int		c_createShadowVolumes;
  	int		c_generateMd5;
  	int		c_entityDefCallbacks;
  	int		c_alloc;			// counts for R_StaticAllc/R_StaticFree
  	int		c_free;
  	int		c_visibleViewEntities;
  	int		c_shadowViewEntities;
  	int		c_viewLights;
  	int		c_numViews;			// number of total views rendered
  	int		c_deformedSurfaces;	// idMD5Mesh::GenerateSurface
  	int		c_deformedVerts;	// idMD5Mesh::GenerateSurface
  	int		c_deformedIndexes;	// idMD5Mesh::GenerateSurface
  	int		c_tangentIndexes;	// R_DeriveTangents()
  	int		c_entityUpdates;
  	int		c_lightUpdates;
  	int		c_entityReferences;
  	int		c_lightReferences;
  	int		c_guiSurfs;
  	int		frontEndMicroSec;	// sum of time in all RE_RenderScene's in a frame
  };
  
  
  struct tmu_t {
  	unsigned int	current2DMap;
  	unsigned int	currentCubeMap;
  };
  
  
  const int MAX_MULTITEXTURE_UNITS =	8;
  
  enum vertexLayoutType_t {
  	LAYOUT_UNKNOWN = 0,
  	LAYOUT_DRAW_VERT,
  	LAYOUT_DRAW_SHADOW_VERT,
  	LAYOUT_DRAW_SHADOW_VERT_SKINNED
  };
  
  struct glstate_t {
  	tmu_t				tmu[MAX_MULTITEXTURE_UNITS];
  
  	int					currenttmu;
  
  	int					faceCulling;
  
  	vertexLayoutType_t	vertexLayout;
  	unsigned int		currentVertexBuffer;
  	unsigned int		currentIndexBuffer;
  
  	float				polyOfsScale;
  	float				polyOfsBias;
  
  	uint64				glStateBits;
  };
  
  struct backEndCounters_t {
  	int		c_surfaces;
  	int		c_shaders;
  
  	int		c_drawElements;
  	int		c_drawIndexes;
  
  	int		c_shadowElements;
  	int		c_shadowIndexes;
  
  	int		c_copyFrameBuffer;
  
  	float	c_overDraw;	
  
  	int		totalMicroSec;			// total microseconds for backend run
  	int		shadowMicroSec;
  };
  
  // all state modified by the back end is separated
  // from the front end state
  struct backEndState_t {
  	const viewDef_t	*	viewDef;
  	backEndCounters_t	pc;
  
  	const viewEntity_t *currentSpace;			// for detecting when a matrix must change
  	idScreenRect		currentScissor;			// for scissor clipping, local inside renderView viewport
  	glstate_t			glState;				// for OpenGL state deltas
  
  	bool				currentRenderCopied;	// true if any material has already referenced _currentRender
  
  	idRenderMatrix		prevMVP[2];				// world MVP from previous frame for motion blur, per-eye
  
  	// surfaces used for code-based drawing
  	drawSurf_t			unitSquareSurface;
  	drawSurf_t			zeroOneCubeSurface;
  	drawSurf_t			testImageSurface;
  };
  
  class idParallelJobList;
  
  const int MAX_GUI_SURFACES	= 1024;		// default size of the drawSurfs list for guis, will
  										// be automatically expanded as needed
  
  static const int MAX_RENDER_CROPS = 8;
  
  /*
  ** Most renderer globals are defined here.
  ** backend functions should never modify any of these fields,
  ** but may read fields that aren't dynamically modified
  ** by the frontend.
  */
  class idRenderSystemLocal : public idRenderSystem {
  public:
  	// external functions
  	virtual void			Init();
  	virtual void			Shutdown();
  	virtual void			ResetGuiModels();
  	virtual void			InitOpenGL();
  	virtual void			ShutdownOpenGL();
  	virtual bool			IsOpenGLRunning() const;
  	virtual bool			IsFullScreen() const;
  	virtual stereo3DMode_t	GetStereo3DMode() const;
  	virtual bool			HasQuadBufferSupport() const;
  	virtual bool			IsStereoScopicRenderingSupported() const;
  	virtual stereo3DMode_t	GetStereoScopicRenderingMode() const;
  	virtual void			EnableStereoScopicRendering( const stereo3DMode_t mode ) const;
  	virtual int				GetWidth() const;
  	virtual int				GetHeight() const;
  	virtual float			GetPixelAspect() const;
  	virtual float			GetPhysicalScreenWidthInCentimeters() const;
  	virtual idRenderWorld *	AllocRenderWorld();
  	virtual void			FreeRenderWorld( idRenderWorld *rw );
  	virtual void			BeginLevelLoad();
  	virtual void			EndLevelLoad();
  	virtual void			LoadLevelImages();
  	virtual void			Preload( const idPreloadManifest &manifest, const char *mapName );
  	virtual void			BeginAutomaticBackgroundSwaps( autoRenderIconType_t icon = AUTORENDER_DEFAULTICON );
  	virtual void			EndAutomaticBackgroundSwaps();
  	virtual bool			AreAutomaticBackgroundSwapsRunning( autoRenderIconType_t * usingAlternateIcon = NULL ) const;
  
  	virtual idFont *		RegisterFont( const char * fontName );
  	virtual void			ResetFonts();
  	virtual void			PrintMemInfo( MemInfo_t *mi );
  
  	virtual void			SetColor( const idVec4 & color );
  	virtual uint32			GetColor();
  	virtual void			SetGLState( const uint64 glState ) ;
  	virtual void			DrawFilled( const idVec4 & color, float x, float y, float w, float h );
  	virtual void			DrawStretchPic ( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *material );
  	virtual void			DrawStretchPic( const idVec4 & topLeft, const idVec4 & topRight, const idVec4 & bottomRight, const idVec4 & bottomLeft, const idMaterial * material );
  	virtual void			DrawStretchTri ( const idVec2 & p1, const idVec2 & p2, const idVec2 & p3, const idVec2 & t1, const idVec2 & t2, const idVec2 & t3, const idMaterial *material );
  	virtual idDrawVert *	AllocTris( int numVerts, const triIndex_t * indexes, int numIndexes, const idMaterial * material, const stereoDepthType_t stereoType = STEREO_DEPTH_TYPE_NONE );
  	virtual void			DrawSmallChar( int x, int y, int ch );
  	virtual void			DrawSmallStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor );
  	virtual void			DrawBigChar( int x, int y, int ch );
  	virtual void			DrawBigStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor );
  
  	virtual void			WriteDemoPics();
  	virtual void			DrawDemoPics();
  	virtual const emptyCommand_t *	SwapCommandBuffers( uint64 *frontEndMicroSec, uint64 *backEndMicroSec, uint64 *shadowMicroSec, uint64 *gpuMicroSec );
  
  	virtual void			SwapCommandBuffers_FinishRendering( uint64 *frontEndMicroSec, uint64 *backEndMicroSec, uint64 *shadowMicroSec, uint64 *gpuMicroSec );
  	virtual const emptyCommand_t *	SwapCommandBuffers_FinishCommandBuffers();
  
  	virtual void			RenderCommandBuffers( const emptyCommand_t * commandBuffers );
  	virtual void			TakeScreenshot( int width, int height, const char *fileName, int downSample, renderView_t *ref );
  	virtual void			CropRenderSize( int width, int height );
  	virtual void			CaptureRenderToImage( const char *imageName, bool clearColorAfterCopy = false );
  	virtual void			CaptureRenderToFile( const char *fileName, bool fixAlpha );
  	virtual void			UnCrop();
  	virtual bool			UploadImage( const char *imageName, const byte *data, int width, int height );
  
  	
  
  public:
  	// internal functions
  							idRenderSystemLocal();
  							~idRenderSystemLocal();
  
  	void					Clear();
  	void					GetCroppedViewport( idScreenRect * viewport );
  	void					PerformResolutionScaling( int& newWidth, int& newHeight );
  	int						GetFrameCount() const { return frameCount; };
  
  public:
  	// renderer globals
  	bool					registered;		// cleared at shutdown, set at InitOpenGL
  
  	bool					takingScreenshot;
  
  	int						frameCount;		// incremented every frame
  	int						viewCount;		// incremented every view (twice a scene if subviewed)
  											// and every R_MarkFragments call
  
  	float					frameShaderTime;	// shader time for all non-world 2D rendering
  
  	idVec4					ambientLightVector;	// used for "ambient bump mapping"
  
  	idList<idRenderWorldLocal*>worlds;
  
  	idRenderWorldLocal *	primaryWorld;
  	renderView_t			primaryRenderView;
  	viewDef_t *				primaryView;
  	// many console commands need to know which world they should operate on
  
  	const idMaterial *		whiteMaterial;
  	const idMaterial *		charSetMaterial;
  	const idMaterial *		defaultPointLight;
  	const idMaterial *		defaultProjectedLight;
  	const idMaterial *		defaultMaterial;
  	idImage *				testImage;
  	idCinematic *			testVideo;
  	int						testVideoStartTime;
  
  	idImage *				ambientCubeImage;	// hack for testing dependent ambient lighting
  
  	viewDef_t *				viewDef;
  
  	performanceCounters_t	pc;					// performance counters
  
  	viewEntity_t			identitySpace;		// can use if we don't know viewDef->worldSpace is valid
  
  	idScreenRect			renderCrops[MAX_RENDER_CROPS];
  	int						currentRenderCrop;
  
  	// GUI drawing variables for surface creation
  	int						guiRecursionLevel;		// to prevent infinite overruns
  	uint32					currentColorNativeBytesOrder;
  	uint64					currentGLState;
  	class idGuiModel *		guiModel;
  
  	idList<idFont *, TAG_FONT>		fonts;
  
  	unsigned short			gammaTable[256];	// brightness / gamma modify this
  
  	srfTriangles_t *		unitSquareTriangles;
  	srfTriangles_t *		zeroOneCubeTriangles;
  	srfTriangles_t *		testImageTriangles;
  
  	// these are allocated at buffer swap time, but
  	// the back end should only use the ones in the backEnd stucture,
  	// which are copied over from the frame that was just swapped.
  	drawSurf_t				unitSquareSurface_;
  	drawSurf_t				zeroOneCubeSurface_;
  	drawSurf_t				testImageSurface_;
  
  	idParallelJobList *		frontEndJobList;
  
  	unsigned				timerQueryId;		// for GL_TIME_ELAPSED_EXT queries
  };
  
  extern backEndState_t		backEnd;
  extern idRenderSystemLocal	tr;
  extern glconfig_t			glConfig;		// outside of TR since it shouldn't be cleared during ref re-init
  
  //
  // cvars
  //
  extern idCVar r_debugContext;				// enable various levels of context debug
  extern idCVar r_glDriver;					// "opengl32", etc
  extern idCVar r_skipIntelWorkarounds;		// skip work arounds for Intel driver bugs
  extern idCVar r_vidMode;					// video mode number
  extern idCVar r_displayRefresh;				// optional display refresh rate option for vid mode
  extern idCVar r_fullscreen;					// 0 = windowed, 1 = full screen
  extern idCVar r_multiSamples;				// number of antialiasing samples
  
  extern idCVar r_znear;						// near Z clip plane
  
  extern idCVar r_swapInterval;				// changes wglSwapIntarval
  extern idCVar r_offsetFactor;				// polygon offset parameter
  extern idCVar r_offsetUnits;				// polygon offset parameter
  extern idCVar r_singleTriangle;				// only draw a single triangle per primitive
  extern idCVar r_logFile;					// number of frames to emit GL logs
  extern idCVar r_clear;						// force screen clear every frame
  extern idCVar r_subviewOnly;				// 1 = don't render main view, allowing subviews to be debugged
  extern idCVar r_lightScale;					// all light intensities are multiplied by this, which is normally 2
  extern idCVar r_flareSize;					// scale the flare deforms from the material def
  
  extern idCVar r_gamma;						// changes gamma tables
  extern idCVar r_brightness;					// changes gamma tables
  
  extern idCVar r_checkBounds;				// compare all surface bounds with precalculated ones
  extern idCVar r_maxAnisotropicFiltering;	// texture filtering parameter
  extern idCVar r_useTrilinearFiltering;		// Extra quality filtering
  extern idCVar r_lodBias;					// lod bias
  
  extern idCVar r_useLightPortalFlow;			// 1 = do a more precise area reference determination
  extern idCVar r_useShadowSurfaceScissor;	// 1 = scissor shadows by the scissor rect of the interaction surfaces
  extern idCVar r_useConstantMaterials;		// 1 = use pre-calculated material registers if possible
  extern idCVar r_useNodeCommonChildren;		// stop pushing reference bounds early when possible
  extern idCVar r_useSilRemap;				// 1 = consider verts with the same XYZ, but different ST the same for shadows
  extern idCVar r_useLightPortalCulling;		// 0 = none, 1 = box, 2 = exact clip of polyhedron faces, 3 MVP to plane culling
  extern idCVar r_useLightAreaCulling;		// 0 = off, 1 = on
  extern idCVar r_useLightScissors;			// 1 = use custom scissor rectangle for each light
  extern idCVar r_useEntityPortalCulling;		// 0 = none, 1 = box
  extern idCVar r_skipPrelightShadows;		// 1 = skip the dmap generated static shadow volumes
  extern idCVar r_useCachedDynamicModels;		// 1 = cache snapshots of dynamic models
  extern idCVar r_useScissor;					// 1 = scissor clip as portals and lights are processed
  extern idCVar r_usePortals;					// 1 = use portals to perform area culling, otherwise draw everything
  extern idCVar r_useStateCaching;			// avoid redundant state changes in GL_*() calls
  extern idCVar r_useEntityCallbacks;			// if 0, issue the callback immediately at update time, rather than defering
  extern idCVar r_lightAllBackFaces;			// light all the back faces, even when they would be shadowed
  extern idCVar r_useLightDepthBounds;		// use depth bounds test on lights to reduce both shadow and interaction fill
  extern idCVar r_useShadowDepthBounds;		// use depth bounds test on individual shadows to reduce shadow fill
  
  extern idCVar r_skipStaticInteractions;		// skip interactions created at level load
  extern idCVar r_skipDynamicInteractions;	// skip interactions created after level load
  extern idCVar r_skipPostProcess;			// skip all post-process renderings
  extern idCVar r_skipSuppress;				// ignore the per-view suppressions
  extern idCVar r_skipInteractions;			// skip all light/surface interaction drawing
  extern idCVar r_skipFrontEnd;				// bypasses all front end work, but 2D gui rendering still draws
  extern idCVar r_skipBackEnd;				// don't draw anything
  extern idCVar r_skipCopyTexture;			// do all rendering, but don't actually copyTexSubImage2D
  extern idCVar r_skipRender;					// skip 3D rendering, but pass 2D
  extern idCVar r_skipRenderContext;			// NULL the rendering context during backend 3D rendering
  extern idCVar r_skipTranslucent;			// skip the translucent interaction rendering
  extern idCVar r_skipAmbient;				// bypasses all non-interaction drawing
  extern idCVar r_skipNewAmbient;				// bypasses all vertex/fragment program ambients
  extern idCVar r_skipBlendLights;			// skip all blend lights
  extern idCVar r_skipFogLights;				// skip all fog lights
  extern idCVar r_skipSubviews;				// 1 = don't render any mirrors / cameras / etc
  extern idCVar r_skipGuiShaders;				// 1 = don't render any gui elements on surfaces
  extern idCVar r_skipParticles;				// 1 = don't render any particles
  extern idCVar r_skipUpdates;				// 1 = don't accept any entity or light updates, making everything static
  extern idCVar r_skipDeforms;				// leave all deform materials in their original state
  extern idCVar r_skipDynamicTextures;		// don't dynamically create textures
  extern idCVar r_skipBump;					// uses a flat surface instead of the bump map
  extern idCVar r_skipSpecular;				// use black for specular
  extern idCVar r_skipDiffuse;				// use black for diffuse
  extern idCVar r_skipDecals;					// skip decal surfaces
  extern idCVar r_skipOverlays;				// skip overlay surfaces
  extern idCVar r_skipShadows;				// disable shadows
  
  extern idCVar r_ignoreGLErrors;
  
  extern idCVar r_screenFraction;				// for testing fill rate, the resolution of the entire screen can be changed
  extern idCVar r_showUnsmoothedTangents;		// highlight geometry rendered with unsmoothed tangents
  extern idCVar r_showSilhouette;				// highlight edges that are casting shadow planes
  extern idCVar r_showVertexColor;			// draws all triangles with the solid vertex color
  extern idCVar r_showUpdates;				// report entity and light updates and ref counts
  extern idCVar r_showDemo;					// report reads and writes to the demo file
  extern idCVar r_showDynamic;				// report stats on dynamic surface generation
  extern idCVar r_showIntensity;				// draw the screen colors based on intensity, red = 0, green = 128, blue = 255
  extern idCVar r_showTrace;					// show the intersection of an eye trace with the world
  extern idCVar r_showDepth;					// display the contents of the depth buffer and the depth range
  extern idCVar r_showTris;					// enables wireframe rendering of the world
  extern idCVar r_showSurfaceInfo;			// show surface material name under crosshair
  extern idCVar r_showNormals;				// draws wireframe normals
  extern idCVar r_showEdges;					// draw the sil edges
  extern idCVar r_showViewEntitys;			// displays the bounding boxes of all view models and optionally the index
  extern idCVar r_showTexturePolarity;		// shade triangles by texture area polarity
  extern idCVar r_showTangentSpace;			// shade triangles by tangent space
  extern idCVar r_showDominantTri;			// draw lines from vertexes to center of dominant triangles
  extern idCVar r_showTextureVectors;			// draw each triangles texture (tangent) vectors
  extern idCVar r_showLights;					// 1 = print light info, 2 = also draw volumes
  extern idCVar r_showLightCount;				// colors surfaces based on light count
  extern idCVar r_showShadows;				// visualize the stencil shadow volumes
  extern idCVar r_showLightScissors;			// show light scissor rectangles
  extern idCVar r_showMemory;					// print frame memory utilization
  extern idCVar r_showCull;					// report sphere and box culling stats
  extern idCVar r_showAddModel;				// report stats from tr_addModel
  extern idCVar r_showSurfaces;				// report surface/light/shadow counts
  extern idCVar r_showPrimitives;				// report vertex/index/draw counts
  extern idCVar r_showPortals;				// draw portal outlines in color based on passed / not passed
  extern idCVar r_showSkel;					// draw the skeleton when model animates
  extern idCVar r_showOverDraw;				// show overdraw
  extern idCVar r_jointNameScale;				// size of joint names when r_showskel is set to 1
  extern idCVar r_jointNameOffset;			// offset of joint names when r_showskel is set to 1
  
  extern idCVar r_testGamma;					// draw a grid pattern to test gamma levels
  extern idCVar r_testGammaBias;				// draw a grid pattern to test gamma levels
  
  extern idCVar r_singleLight;				// suppress all but one light
  extern idCVar r_singleEntity;				// suppress all but one entity
  extern idCVar r_singleArea;					// only draw the portal area the view is actually in
  extern idCVar r_singleSurface;				// suppress all but one surface on each entity
  extern idCVar r_shadowPolygonOffset;		// bias value added to depth test for stencil shadow drawing
  extern idCVar r_shadowPolygonFactor;		// scale value for stencil shadow drawing
  
  extern idCVar r_jitter;						// randomly subpixel jitter the projection matrix
  extern idCVar r_orderIndexes;				// perform index reorganization to optimize vertex use
  
  extern idCVar r_debugLineDepthTest;			// perform depth test on debug lines
  extern idCVar r_debugLineWidth;				// width of debug lines
  extern idCVar r_debugArrowStep;				// step size of arrow cone line rotation in degrees
  extern idCVar r_debugPolygonFilled;
  
  extern idCVar r_materialOverride;			// override all materials
  
  extern idCVar r_debugRenderToTexture;
  
  extern idCVar stereoRender_deGhost;			// subtract from opposite eye to reduce ghosting
  
  extern idCVar r_useGPUSkinning;
  
  /*
  ====================================================================
  
  INITIALIZATION
  
  ====================================================================
  */
  
  void R_Init();
  void R_InitOpenGL();
  
  void R_SetColorMappings();
  
  void R_ScreenShot_f( const idCmdArgs &args );
  void R_StencilShot();
  
  /*
  ====================================================================
  
  IMPLEMENTATION SPECIFIC FUNCTIONS
  
  ====================================================================
  */
  
  struct vidMode_t {
      int width;
  	int height;
  	int displayHz;
  
  	bool operator==( const vidMode_t & a ) {
  		return a.width == width && a.height == height && a.displayHz == displayHz;
  	}
  };
  
  // the number of displays can be found by itterating this until it returns false
  // displayNum is the 0 based value passed to EnumDisplayDevices(), you must add
  // 1 to this to get an r_fullScreen value.
  bool R_GetModeListForDisplay( const int displayNum, idList<vidMode_t> & modeList );
  
  struct glimpParms_t {
  	int			x;				// ignored in fullscreen
  	int			y;				// ignored in fullscreen
  	int			width;
  	int			height;
  	int			fullScreen;		// 0 = windowed, otherwise 1 based monitor number to go full screen on
  								// -1 = borderless window for spanning multiple displays
  	bool		stereo;
  	int			displayHz;
  	int			multiSamples;
  };
  
  bool		GLimp_Init( glimpParms_t parms );
  // If the desired mode can't be set satisfactorily, false will be returned.
  // If succesful, sets glConfig.nativeScreenWidth, glConfig.nativeScreenHeight, and glConfig.pixelAspect
  
  // The renderer will then reset the glimpParms to "safe mode" of 640x480
  // fullscreen and try again.  If that also fails, the error will be fatal.
  
  bool		GLimp_SetScreenParms( glimpParms_t parms );
  // will set up gl up with the new parms
  
  void		GLimp_Shutdown();
  // Destroys the rendering context, closes the window, resets the resolution,
  // and resets the gamma ramps.
  
  void		GLimp_SetGamma( unsigned short red[256], 
  						    unsigned short green[256],
  							unsigned short blue[256] );
  // Sets the hardware gamma ramps for gamma and brightness adjustment.
  // These are now taken as 16 bit values, so we can take full advantage
  // of dacs with >8 bits of precision
  
  
  bool		GLimp_SpawnRenderThread( void (*function)() );
  // Returns false if the system only has a single processor
  
  void *		GLimp_BackEndSleep();
  void		GLimp_FrontEndSleep();
  void		GLimp_WakeBackEnd( void *data );
  // these functions implement the dual processor syncronization
  
  void		GLimp_ActivateContext();
  void		GLimp_DeactivateContext();
  // These are used for managing SMP handoffs of the OpenGL context
  // between threads, and as a performance tunining aid.  Setting
  // 'r_skipRenderContext 1' will call GLimp_DeactivateContext() before
  // the 3D rendering code, and GLimp_ActivateContext() afterwards.  On
  // most OpenGL implementations, this will result in all OpenGL calls
  // being immediate returns, which lets us guage how much time is
  // being spent inside OpenGL.
  
  void		GLimp_EnableLogging( bool enable );
  
  
  /*
  ============================================================
  
  RENDERWORLD_DEFS
  
  ============================================================
  */
  
  void R_DeriveEntityData( idRenderEntityLocal *def );
  void R_CreateEntityRefs( idRenderEntityLocal *def );
  void R_FreeEntityDefDerivedData( idRenderEntityLocal *def, bool keepDecals, bool keepCachedDynamicModel );
  void R_FreeEntityDefCachedDynamicModel( idRenderEntityLocal *def );
  void R_FreeEntityDefDecals( idRenderEntityLocal *def );
  void R_FreeEntityDefOverlay( idRenderEntityLocal *def );
  void R_FreeEntityDefFadedDecals( idRenderEntityLocal *def, int time );
  
  void R_CreateLightRefs( idRenderLightLocal *light );
  void R_FreeLightDefDerivedData( idRenderLightLocal *light );
  
  void R_FreeDerivedData();
  void R_ReCreateWorldReferences();
  void R_CheckForEntityDefsUsingModel( idRenderModel *model );
  void R_ModulateLights_f( const idCmdArgs &args );
  
  /*
  ============================================================
  
  RENDERWORLD_PORTALS
  
  ============================================================
  */
  
  viewEntity_t *R_SetEntityDefViewEntity( idRenderEntityLocal *def );
  viewLight_t *R_SetLightDefViewLight( idRenderLightLocal *def );
  
  /*
  ====================================================================
  
  TR_FRONTEND_MAIN
  
  ====================================================================
  */
  
  void R_InitFrameData();
  void R_ShutdownFrameData();
  void R_ToggleSmpFrame();
  void *R_FrameAlloc( int bytes, frameAllocType_t type = FRAME_ALLOC_UNKNOWN );
  void *R_ClearedFrameAlloc( int bytes, frameAllocType_t type = FRAME_ALLOC_UNKNOWN );
  
  void *R_StaticAlloc( int bytes, const memTag_t tag = TAG_RENDER_STATIC );		// just malloc with error checking
  void *R_ClearedStaticAlloc( int bytes );	// with memset
  void R_StaticFree( void *data );
  
  void R_RenderView( viewDef_t *parms );
  void R_RenderPostProcess( viewDef_t *parms );
  
  /*
  ============================================================
  
  TR_FRONTEND_ADDLIGHTS
  
  ============================================================
  */
  
  void R_ShadowBounds( const idBounds & modelBounds, const idBounds & lightBounds, const idVec3 & lightOrigin, idBounds & shadowBounds );
  
  ID_INLINE bool R_CullModelBoundsToLight( const idRenderLightLocal * light, const idBounds & localBounds, const idRenderMatrix & modelRenderMatrix ) {
  	idRenderMatrix modelLightProject;
  	idRenderMatrix::Multiply( light->baseLightProject, modelRenderMatrix, modelLightProject );
  	return idRenderMatrix::CullBoundsToMVP( modelLightProject, localBounds, true );
  }
  
  void R_AddLights();
  void R_OptimizeViewLightsList();
  
  /*
  ============================================================
  
  TR_FRONTEND_ADDMODELS
  
  ============================================================
  */
  
  bool R_IssueEntityDefCallback( idRenderEntityLocal *def );
  idRenderModel *R_EntityDefDynamicModel( idRenderEntityLocal *def );
  void R_ClearEntityDefDynamicModel( idRenderEntityLocal *def );
  
  void R_SetupDrawSurfShader( drawSurf_t * drawSurf, const idMaterial * shader, const renderEntity_t * renderEntity );
  void R_SetupDrawSurfJoints( drawSurf_t * drawSurf, const srfTriangles_t * tri, const idMaterial * shader );
  void R_LinkDrawSurfToView( drawSurf_t * drawSurf, viewDef_t * viewDef );
  
  void R_AddModels();
  
  /*
  =============================================================
  
  TR_FRONTEND_DEFORM
  
  =============================================================
  */
  
  drawSurf_t * R_DeformDrawSurf( drawSurf_t * drawSurf );
  
  /*
  =============================================================
  
  TR_FRONTEND_GUISURF
  
  =============================================================
  */
  
  void R_SurfaceToTextureAxis( const srfTriangles_t *tri, idVec3 &origin, idVec3 axis[3] );
  void R_AddInGameGuis( const drawSurf_t * const drawSurfs[], const int numDrawSurfs );
  
  /*
  ============================================================
  
  TR_FRONTEND_SUBVIEW
  
  ============================================================
  */
  
  bool R_PreciseCullSurface( const drawSurf_t *drawSurf, idBounds &ndcBounds );
  bool R_GenerateSubViews( const drawSurf_t * const drawSurfs[], const int numDrawSurfs );
  
  /*
  ============================================================
  
  TR_TRISURF
  
  ============================================================
  */
  
  srfTriangles_t *	R_AllocStaticTriSurf();
  void				R_AllocStaticTriSurfVerts( srfTriangles_t *tri, int numVerts );
  void				R_AllocStaticTriSurfIndexes( srfTriangles_t *tri, int numIndexes );
  void				R_AllocStaticTriSurfPreLightShadowVerts( srfTriangles_t *tri, int numVerts );
  void				R_AllocStaticTriSurfSilIndexes( srfTriangles_t *tri, int numIndexes );
  void				R_AllocStaticTriSurfDominantTris( srfTriangles_t *tri, int numVerts );
  void				R_AllocStaticTriSurfSilEdges( srfTriangles_t *tri, int numSilEdges );
  void				R_AllocStaticTriSurfMirroredVerts( srfTriangles_t *tri, int numMirroredVerts );
  void				R_AllocStaticTriSurfDupVerts( srfTriangles_t *tri, int numDupVerts );
  
  srfTriangles_t *	R_CopyStaticTriSurf( const srfTriangles_t *tri );
  
  void				R_ResizeStaticTriSurfVerts( srfTriangles_t *tri, int numVerts );
  void				R_ResizeStaticTriSurfIndexes( srfTriangles_t *tri, int numIndexes );
  void				R_ReferenceStaticTriSurfVerts( srfTriangles_t *tri, const srfTriangles_t *reference );
  void				R_ReferenceStaticTriSurfIndexes( srfTriangles_t *tri, const srfTriangles_t *reference );
  
  void				R_FreeStaticTriSurfSilIndexes( srfTriangles_t *tri );
  void				R_FreeStaticTriSurf( srfTriangles_t *tri );
  void				R_FreeStaticTriSurfVerts( srfTriangles_t *tri );
  void				R_FreeStaticTriSurfVertexCaches( srfTriangles_t *tri );
  int					R_TriSurfMemory( const srfTriangles_t *tri );
  
  void				R_BoundTriSurf( srfTriangles_t *tri );
  void				R_RemoveDuplicatedTriangles( srfTriangles_t *tri );
  void				R_CreateSilIndexes( srfTriangles_t *tri );
  void				R_RemoveDegenerateTriangles( srfTriangles_t *tri );
  void				R_RemoveUnusedVerts( srfTriangles_t *tri );
  void				R_RangeCheckIndexes( const srfTriangles_t *tri );
  void				R_CreateVertexNormals( srfTriangles_t *tri );		// also called by dmap
  void				R_CleanupTriangles( srfTriangles_t *tri, bool createNormals, bool identifySilEdges, bool useUnsmoothedTangents );
  void				R_ReverseTriangles( srfTriangles_t *tri );
  
  // Only deals with vertexes and indexes, not silhouettes, planes, etc.
  // Does NOT perform a cleanup triangles, so there may be duplicated verts in the result.
  srfTriangles_t *	R_MergeSurfaceList( const srfTriangles_t **surfaces, int numSurfaces );
  srfTriangles_t *	R_MergeTriangles( const srfTriangles_t *tri1, const srfTriangles_t *tri2 );
  
  // if the deformed verts have significant enough texture coordinate changes to reverse the texture
  // polarity of a triangle, the tangents will be incorrect
  void				R_DeriveTangents( srfTriangles_t *tri );
  
  // copy data from a front-end srfTriangles_t to a back-end drawSurf_t
  void				R_InitDrawSurfFromTri( drawSurf_t & ds, srfTriangles_t & tri );
  
  // For static surfaces, the indexes, ambient, and shadow buffers can be pre-created at load
  // time, rather than being re-created each frame in the frame temporary buffers.
  void				R_CreateStaticBuffersForTri( srfTriangles_t & tri );
  
  // deformable meshes precalculate as much as possible from a base frame, then generate
  // complete srfTriangles_t from just a new set of vertexes
  struct deformInfo_t {
  	int					numSourceVerts;
  
  	// numOutputVerts may be smaller if the input had duplicated or degenerate triangles
  	// it will often be larger if the input had mirrored texture seams that needed
  	// to be busted for proper tangent spaces
  	int					numOutputVerts;
  	idDrawVert *		verts;
  
  	int					numIndexes;
  	triIndex_t *		indexes;
  
  	triIndex_t *		silIndexes;				// indexes changed to be the first vertex with same XYZ, ignoring normal and texcoords
  
  	int					numMirroredVerts;		// this many verts at the end of the vert list are tangent mirrors
  	int *				mirroredVerts;			// tri->mirroredVerts[0] is the mirror of tri->numVerts - tri->numMirroredVerts + 0
  
  	int					numDupVerts;			// number of duplicate vertexes
  	int *				dupVerts;				// pairs of the number of the first vertex and the number of the duplicate vertex
  
  	int					numSilEdges;			// number of silhouette edges
  	silEdge_t *			silEdges;				// silhouette edges
  
  	vertCacheHandle_t	staticIndexCache;		// GL_INDEX_TYPE
  	vertCacheHandle_t	staticAmbientCache;		// idDrawVert
  	vertCacheHandle_t	staticShadowCache;		// idShadowCacheSkinned
  };
  
  
  // if outputVertexes is not NULL, it will point to a newly allocated set of verts that includes the mirrored ones
  deformInfo_t *		R_BuildDeformInfo( int numVerts, const idDrawVert *verts, int numIndexes, const int *indexes, 
  										bool useUnsmoothedTangents );
  void				R_FreeDeformInfo( deformInfo_t *deformInfo );
  int					R_DeformInfoMemoryUsed( deformInfo_t *deformInfo );
  
  /*
  =============================================================
  
  TR_TRACE
  
  =============================================================
  */
  
  struct localTrace_t {
  	float		fraction;
  	// only valid if fraction < 1.0
  	idVec3		point;
  	idVec3		normal;
  	int			indexes[3];
  };
  
  localTrace_t R_LocalTrace( const idVec3 &start, const idVec3 &end, const float radius, const srfTriangles_t *tri );
  void RB_ShowTrace( drawSurf_t **drawSurfs, int numDrawSurfs );
  
  /*
  =============================================================
  
  BACKEND
  
  =============================================================
  */
  
  void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds );
  
  /*
  ============================================================
  
  TR_BACKEND_DRAW
  
  ============================================================
  */
  
  void RB_DrawElementsWithCounters( const drawSurf_t *surf );
  void RB_DrawViewInternal( const viewDef_t * viewDef, const int stereoEye );
  void RB_DrawView( const void *data, const int stereoEye );
  void RB_CopyRender( const void *data );
  void RB_PostProcess( const void *data );
  
  /*
  =============================================================
  
  TR_BACKEND_RENDERTOOLS
  
  =============================================================
  */
  
  float RB_DrawTextLength( const char *text, float scale, int len );
  void RB_AddDebugText( const char *text, const idVec3 &origin, float scale, const idVec4 &color, const idMat3 &viewAxis, const int align, const int lifetime, const bool depthTest );
  void RB_ClearDebugText( int time );
  void RB_AddDebugLine( const idVec4 &color, const idVec3 &start, const idVec3 &end, const int lifeTime, const bool depthTest );
  void RB_ClearDebugLines( int time );
  void RB_AddDebugPolygon( const idVec4 &color, const idWinding &winding, const int lifeTime, const bool depthTest );
  void RB_ClearDebugPolygons( int time );
  void RB_DrawBounds( const idBounds &bounds );
  void RB_ShowLights( drawSurf_t **drawSurfs, int numDrawSurfs );
  void RB_ShowLightCount( drawSurf_t **drawSurfs, int numDrawSurfs );
  void RB_PolygonClear();
  void RB_ScanStencilBuffer();
  void RB_ShowDestinationAlpha();
  void RB_ShowOverdraw();
  void RB_RenderDebugTools( drawSurf_t **drawSurfs, int numDrawSurfs );
  void RB_ShutdownDebugTools();
  
  //=============================================
  
  #include "ResolutionScale.h"
  #include "RenderLog.h"
  #include "AutoRender.h"
  #include "AutoRenderBink.h"
  #include "jobs/ShadowShared.h"
  #include "jobs/prelightshadowvolume/PreLightShadowVolume.h"
  #include "jobs/staticshadowvolume/StaticShadowVolume.h"
  #include "jobs/dynamicshadowvolume/DynamicShadowVolume.h"
  #include "GraphicsAPIWrapper.h"
  #include "GLMatrix.h"
  
  
  
  #include "BufferObject.h"
  #include "RenderProgs.h"
  #include "RenderWorld_local.h"
  #include "GuiModel.h"
  #include "VertexCache.h"
  
  #endif /* !__TR_LOCAL_H__ */
  