/*****************************************************************************
The Dark Mod GPL Source Code

This file is part of the The Dark Mod Source Code, originally based
on the Doom 3 GPL Source Code as published in 2011.

The Dark Mod 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. For details, see LICENSE.TXT.

Project: The Dark Mod (http://www.thedarkmod.com/)

******************************************************************************/

#ifndef __TR_LOCAL_H__
#define __TR_LOCAL_H__

#include <atomic>

#include "renderer/resources/Image.h"

class idRenderWorldLocal;

const int FALLOFF_TEXTURE_SIZE =	64;

const float	DEFAULT_FOG_DISTANCE = 500.0f;

const int FOG_ENTER_SIZE = 64;
const float FOG_ENTER = ( FOG_ENTER_SIZE + 1.0f ) / ( FOG_ENTER_SIZE * 2 );
// picky to get the bilerp correct at terminator


typedef struct renderCrop_s {
	int		x, y, width, height;	// these are in physical, OpenGL Y-at-bottom pixels
} renderCrop_t;

// idScreenRect gets carried around with each drawSurf, so it makes sense
// to keep it compact, instead of just using the idBounds class
class idScreenRect {
public:
	short		x1, y1, x2, y2;							// inclusive pixel bounds inside viewport
	float       zmin, zmax;								// for depth bounds test

	void		Clear();								// clear to backwards values
	void		ClearWithZ();
	void		AddPoint( float x, float y );			// adds a point
	void		Expand( int pixels = 1 );				// expand by X pixels each way to fix roundoffs
	void		Intersect( const idScreenRect &rect );
	void		IntersectWithZ( const idScreenRect &rect );
	void		Union( const idScreenRect &rect );
	void		UnionWithZ( const idScreenRect &rect );
	bool		Equals( const idScreenRect& rect ) const {
		return ( x1 == rect.x1 && x2 == rect.x2 && y1 == rect.y1 && y2 == rect.y2 );
	}
	bool		Overlaps( const idScreenRect& rect ) const {
		// The rectangles don't overlap if
		// one rectangle's minimum in some dimension 
		// is greater than the other's maximum in
		// that dimension.

		bool noOverlap = rect.x1 > x2 ||
			x1 > rect.x2 ||
			rect.y1 > y2 ||
			y1 > rect.y2;

		return !noOverlap;
	}
	bool		IsEmpty() const;
	bool		IsEmptyWithZ() const;
	int			GetArea() const { //anon
		return GetWidth() * GetHeight();
	}
	// duzenko: got tired of all the inline subtractions
	int GetWidth() const {
		return x2 - x1 + 1;
	}
	int GetHeight() const {
		return y2 - y1 + 1;
	}
};

idScreenRect R_ScreenRectFromViewFrustumBounds( const idBounds &bounds );
void R_ShowColoredScreenRect( const idScreenRect &rect, int colorIndex );


typedef enum {
	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,
	DC_SET_PLAYER_PORTAL_LOSS	// grayman #3042
} demoCommand_t;

typedef enum {
	LS_NONE,
	LS_STENCIL,
	LS_MAPS
} lightShadows_t;

typedef enum {
	XR_IGNORE,
	XR_ONLY,
	XR_SUBSTITUTE
} xrayEntityMask_t;

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

SURFACES

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

#include "renderer/resources/ModelDecal.h"
#include "renderer/resources/ModelOverlay.h"
#include "renderer/frontend/Interaction.h"

idMat4 RB_GetShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture );

// 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
// drawSurf_t are initialized manually, so check all places they're created if adding a member.

static const int DSF_VIEW_INSIDE_SHADOW	= 1;
static const int DSF_SOFT_PARTICLE = 2; // #3878
static const int DSF_BLOCK_SELF_SHADOWS = 4; // #6571: used when light interaction and self-shadows are computed in one draw call

struct viewLight_s;

typedef struct drawSurf_s {
	const srfTriangles_t	*frontendGeo;			// do not use in the backend; may be modified by the frontend
	int						numIndexes;				// these four are frame-safe copies for backend use
	int						numVerts;
	vertCacheHandle_t		indexCache;				// int				
	vertCacheHandle_t		ambientCache;			// idDrawVert
	vertCacheHandle_t		shadowCache;			// shadowCache_t

	const struct viewEntity_s *space;
	const idMaterial		*material;			// may be NULL for shadow volumes
	idImage					*dynamicImageOverride;	// stgatilov #6434: if not NULL, then texture of material should be replaced with this one (for subviews)
	float					sort;				// material->sort, modified by gui / entity sort offsets
	const float				*shaderRegisters;	// evaluated and adjusted for referenceShaders
	/*const*/ struct drawSurf_s	*nextOnLight;	// viewLight chains

	idScreenRect			scissorRect;		// for scissor clipping, local inside renderView viewport
	int						dsFlags;			// DSF_VIEW_INSIDE_SHADOW, etc
	float					particle_radius;	// The radius of individual quads for soft particles #3878

	void CopyGeo( const srfTriangles_t *tri ) {
		frontendGeo = tri;
		numIndexes = tri->numIndexes;
		numVerts = tri->numVerts;
		indexCache = tri->indexCache;
		ambientCache = tri->ambientCache;
		shadowCache = tri->shadowCache;
	}

	idVec4 GetRegisterVec4( const int registerIndices[4] ) const {
		idVec4 res;
		for (int d = 0; d < 4; d++)
			res[d] = shaderRegisters[ registerIndices[d] ];
		return res;
	}
	bool IsStageEnabled( const shaderStage_t *pStage ) const {
		return shaderRegisters[ pStage->conditionRegister ] != 0.0f;
	}
	idVec4 GetStageColor( const shaderStage_t *pStage ) const {
		return GetRegisterVec4( pStage->color.registers );
	}
	idMat4 GetTextureMatrix( const shaderStage_t *pStage ) const {
		return RB_GetShaderTextureMatrix( shaderRegisters, &pStage->texture );
	}
} drawSurf_t;


typedef struct {
	int		numPlanes;		// this is always 6 for now
	idPlane	planes[6];
	// positive sides facing inward
	// plane 5 is always the plane the projection is going to, the
	// other planes are just clip planes
	// all planes are in global coordinates

	bool	makeClippedPlanes;
	// a projected light with a single frustum needs to make sil planes
	// from triangles that clip against side planes, but a point light
	// that has adjacent frustums doesn't need to
} shadowFrustum_t;


// stgatilov #6296: linked list of references to the areas that an entity/light belongs to
// this is inverse correspondence for portalArea_t::entityRefs/lightRefs
// it is designed to work in O(1) time, but otherwise its speed is not important
typedef struct areaReference_s {
	int areaIdx;
	int idxInArea;
	struct areaReference_s *next;
} areaReference_t;

// stgatilov #5172: fully stored results of FlowLightThroughPortals for a light
// we store not only the areas light can reach, but also the portal-limited windings we get along
struct lightPortalFlow_t {
	struct areaRef_t {
		int areaIdx;
		// planeStorage[planeBeg..planeEnd) define winding for this reference
		int planeBeg, planeEnd;

		bool operator< (const areaRef_t &b) const { return areaIdx < b.areaIdx; }
	};
	idList<areaRef_t> areaRefs;
	idList<idPlane> planeStorage;

	void Clear() {
		areaRefs.Clear();
		planeStorage.Clear();
	}
};


class idRenderLightLocal {
public:
	idRenderLightLocal();

	void			FreeRenderLight();
	void			UpdateRenderLight( const renderLight_t *re, bool forceUpdate = false );
	void			GetRenderLight( renderLight_t *re );
	void			ForceUpdate();
	int				GetIndex();


	renderLight_t			parms;					// specification

	bool					lightHasMoved;			// the light has changed its position since it was
													// first added, so the prelight model is not valid

	float					modelMatrix[16];		// this is just a rearrangement of parms.axis and parms.origin

	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];
	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
	idImageAsset 			*falloffImage;

	idVec3					globalLightOrigin;		// accounting for lightCenter and parallel
	idBounds				globalLightBounds;

	lightShadows_t 			shadows;				// per-light shadowing mode, not always == r_shadows (only valid if light within view)


	idPlane					frustum[6];				// in global space, positive side facing out, last two are front/back
	idWinding				frustumWindings[6];		// used for culling
	srfTriangles_t 			*frustumTris;			// triangulated frustumWindings[]

	int						numShadowFrustums;		// one for projected lights, usually six for point lights
	shadowFrustum_t			shadowFrustums[6];

	int						viewCount;				// if == tr.viewCount, the light is on the viewDef->viewLights list
	int						viewCountGenBackendSurfs;	// stgatilov: it == tr.viewCount, some drawsurfs has been passed from this light to backend
	struct viewLight_s 		*viewLight;

	idInteraction 			*firstInteraction;		// doubly linked list
	idInteraction 			*lastInteraction;

	// light origin is outside light volume
	// BAD: objects between origin and volume don't cast shadows, or can cast culling-dependent partial shadows
	bool					isOriginOutsideVolume;
	// light origin and entering faces of light volume cover different sets of areas
	// BAD: it is questionable where to start light portal flow, so better not use it
	// note: spotlight is an important "origin outside volume" case which we still want to run portal flow on...
	bool					isOriginOutsideVolumeMajor;
	// light origin is inside void: it either is useless or is bad (see below)
	bool					isOriginInVoid;
	// light origin is inside void, but light still works because it was hackily assigned to area with entity origin
	// BAD: cannot use light portal flow for such lights
	bool					isOriginInVoidButActive;

	// information
	areaReference_t 		*references;			// each area the light is present in will have a lightRef
	lightPortalFlow_t		lightPortalFlow;		// stgatilov #5172: info about how light reaches areas


	// stgatilov #5172: list of areas where world geometry should give additional shadows
	// this can be non-empty when "portal flow" code is used for normal "references".
	idList<int>				areasForAdditionalWorldShadows;

	struct doublePortal_s 	*foggedPortals;
};


class idRenderEntityLocal {
public:
	idRenderEntityLocal();

	void			FreeRenderEntity();
	void			UpdateRenderEntity( const renderEntity_t *re, bool forceUpdate = false );
	void			GetRenderEntity( renderEntity_t *re );
	void			ForceUpdate();
	int				GetIndex();

	// overlays are extra polygons that deform with animating models for blood and damage marks
	void			ProjectOverlay( const idPlane localTextureAxis[2], const idMaterial *material );
	void			RemoveDecals();

	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;

	idBounds				referenceBounds;			// the local bounds used to place entityRefs, either from parms or a model
	// 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
	struct viewEntity_s 	*viewEntity;				// in frame temporary memory

	int						visibleCount;
	// if tr.viewCount == visibleCount, at least one ambient
	// surface has actually been added by R_AddAmbientDrawsurfs
	// note that an entity could still be in the view frustum and not be visible due
	// to portal passing

	idDecalOnRenderModel		*decals;					// chain of decals that have been projected on this model
	idOverlayOnRenderModel 	*overlay;					// blood overlays on animated models

	idList<idRenderEntityLocal*> children;				// #5867 children entities get some properties synchronized from parent
	idRenderEntityLocal		*parent;					// when this parent dies, children must die too

	areaReference_t 		*entityRefs;				// chain of all references
	idInteraction 			*firstInteraction;			// doubly linked list
	idInteraction 			*lastInteraction;

	bool					needsPortalSky;
	int						centerArea;

	static const int		TimedViewsPerFrame = 8;
	float					timeAddSingleModel[8];		// #6650. statistics of R_AddSingleModel per view on the last frame

	idSysMutex				mutex;						// needed to synchronize R_EntityDefDynamicModel over multiple threads
};

// 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
typedef struct viewLight_s {
	struct viewLight_s 		*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;

	// if the view isn't inside the light, we can use the non-reversed
	// shadow drawing, avoiding the draws of the front and rear caps
	bool					viewInsideLight;

	// true if globalLightOrigin is inside the view frustum, even if it may
	// be obscured by geometry.  This allows us to skip shadows from non-visible objects
	bool					viewSeesGlobalLightOrigin;

	// if !viewInsideLight, the corresponding bit for each of the shadowFrustum
	// projection planes that the view is on the negative side of will be set,
	// allowing us to skip drawing the projected caps of shadows if we can't see the face
	int						viewSeesShadowPlaneBits;
	renderCrop_t			shadowMapPage;
	float					maxLightDistance;			// maximum distance from light origin to light volume points

	bool					noFogBoundary;				// Stops fogs drawing and fogging their bounding boxes -- SteveL #3664
	bool                    noPortalFog;				// Prevents fog from prematurely closing portals and snapping off lights, matches the material flag from Doom 3	-- nbohr1more #6282		
	bool					singleLightOnly;			// multi-light shader can't handle it
	bool					pointLight;
	bool					noShadows;
	bool					noSpecular;
	bool					volumetricNoshadows;		// stgatilov #5816: ignore shadows in volumetric light

	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
	srfTriangles_t 			*frustumTris;				// light frustum for backend fog volume rendering
	lightShadows_t 			shadows;					// per-light shadowing mode, not always == r_shadows
	const idMaterial 		*lightShader;				// light shader used by backend
	const float				*shaderRegisters;			// shader registers used by backend
	idImage 				*falloffImage;				// falloff image used by backend
	float					volumetricDust;				// stgatilov #5816: strength of volumetric light

	/*const */struct drawSurf_s	*globalShadows;				// shadow everything
	/*const */struct drawSurf_s	*localInteractions;			// don't get local shadows
	/*const */struct drawSurf_s	*localShadows;				// don't shadow local Surfaces
	/*const */struct drawSurf_s	*globalInteractions;		// get shadows from everything
	/*const */struct drawSurf_s	*translucentInteractions;	// get shadows from everything

	uint32_t				lightMask;

	idVec4 GetRegisterVec4( const int registerIndices[4] ) const {
		idVec4 res;
		for (int d = 0; d < 4; d++)
			res[d] = shaderRegisters[ registerIndices[d] ];
		return res;
	}
	bool IsStageEnabled( const shaderStage_t *pStage ) const {
		return shaderRegisters[ pStage->conditionRegister ] != 0.0f;
	}
	idVec4 GetStageColor( const shaderStage_t *pStage ) const {
		return GetRegisterVec4( pStage->color.registers );
	}
	idMat4 GetTextureMatrix( const shaderStage_t *pStage ) const {
		return RB_GetShaderTextureMatrix( shaderRegisters, &pStage->texture );
	}
} viewLight_t;

struct preparedSurf_t {
	drawSurf_t		*surf;
	idUserInterface *gui;
	preparedSurf_t	*next;
};
// 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 simultaniously if running in SMP mode.
// A single entityDef can generate multiple viewEntity_t in a single frame, as when seen in a mirror
typedef struct viewEntity_s {
	struct viewEntity_s	*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				weaponDepthHack;
	float				modelDepthHack;		  // Used by particles only. Causes the particle to be drawn in front of intersecting
	// geometry by up to modelDepthhack units, to remove some ugly intersections.

	float				modelMatrix[16];		// local coords to global coords
	float				modelViewMatrix[16];	// local coords to eye coords
	idRenderMatrix		mvp;

	preparedSurf_t		*preparedSurfs;

	int					drawCalls;				// perf tool
} viewEntity_t;

// viewDefs are allocated on the frame temporary stack memory
typedef struct viewDef_s {
	// specified in the call to DrawScene()
	renderView_t		renderView;

	float				projectionMatrix[16];
	idRenderMatrix		projectionRenderMatrix;
	idRenderMatrix		viewRenderMatrix;

	viewEntity_t		worldSpace;

	idRenderWorldLocal *renderWorld;

	int					viewCount;				// tr.viewCount recorded during R_RenderView 
	float				floatTime;

	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				isMirrorInverted;		// mirrored/inverted view: invert the face culling (false inside double-mirror)
	bool				isMirrorGen;			// true if view is generated for mirror
	bool				isPortalSky;			// true if view is generated for portalSky
	bool				isXray;					// true if view is generated for xray
	xrayEntityMask_t	xrayEntityMask;

	// stgatilov: the color output of this view should become background for the next view rendering
	// for this reason, do NOT clear color buffer at the beginning of the NEXT view render
	// example: portalsky is rendered before superview with no clear in between (at least some implementation)
	bool				outputColorIsBackground;

	bool				isEditor;

	int					numClipPlanes;
	idPlane				clipPlane[1];	// in world space, the positive side, K nested mirrors use K planes
	// 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

	struct viewDef_s 	*superView;				// never go into an infinite subview loop
	struct drawSurf_s 	*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
	int					numOffscreenSurfs;		// light occluders only, used by multi light shader

	struct viewLight_s	*viewLights;			// chain of all viewLights effecting view
	struct viewEntity_s	*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[5];				// positive sides face outward, [4] is the front clip plane
	idFrustum			viewFrustum;

	idVec3				lightSample;

	int					areaNum;				// -1 = not in a valid area

	bool 				*connectedAreas;
	// 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.

	// tools
	char				*portalStates;

	renderView_t 		*unlockedRenderView;	// NULL except when r_lockView is active

	bool				IsLightGem() const {
		return renderView.viewID < 0;
	}
} viewDef_t;


// complex light / surface interactions are broken up into multiple passes of a
// simple interaction shader
typedef struct {
	const drawSurf_t 	*surf;

	idImage 			*lightImage;
	idImage 			*lightFalloffImage;
	idImage 			*bumpImage;
	idImage 			*diffuseImage;
	idImage 			*specularImage;
	idImage				*parallaxImage;

	idVec4				diffuseColor;	// may have a light color baked into it, will be < tr.backEndRendererMaxLight
	idVec4				specularColor;	// may have a light color baked into it, will be < tr.backEndRendererMaxLight
	stageVertexColor_t	vertexColor;	// applies to both diffuse and specular

	idVec4				lightColor;
	int					ambientLight;	// use tr.ambientNormalMap instead of normalization cube map
										// (not a bool just to avoid an uninitialized memory check of the pad region by valgrind)
	int					cubicLight;		// nbohr1more #3881: dedicated cubemap light // probably not needed

	idVec4				lightProjection[4];		// transforms object coords into light-volume coords
	idVec4				lightTextureMatrix[2];	// transforms light-volume coords into lightImage texcoords
	idVec4				bumpMatrix[2];
	idVec4				parallaxMatrix[2];
	idVec4				diffuseMatrix[2];
	idVec4				specularMatrix[2];
	parallaxStage_t		parallax;
} drawInteraction_t;


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

RENDERER BACK END COMMAND QUEUE

TR_CMDS

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

typedef enum {
	RC_NOP,
	RC_DRAW_VIEW,
	RC_DRAW_LIGHTGEM,
	RC_SET_BUFFER,
	RC_COPY_RENDER,
	RC_BLOOM,
	RC_TONEMAP
} renderCommand_t;

struct baseCommand_t {
	renderCommand_t commandId;
};

struct emptyCommand_t : baseCommand_t {
	baseCommand_t* next;
};

struct bloomCommand_t : emptyCommand_t {
};

struct setBufferCommand_t : emptyCommand_t {
	int		frameCount;
};

struct drawSurfsCommand_t : emptyCommand_t {
	viewDef_t	*viewDef;
};

struct tonemapCommand_t : emptyCommand_t {
	bool forceOutputToBlack;
};

struct drawLightgemCommand_t : drawSurfsCommand_t {
	byte *dataBuffer;
};

struct copyRenderCommand_t : emptyCommand_t {
	int		x, y, imageWidth, imageHeight;
	idImageScratch	*image;
	int		cubeFace;			// when copying to a cubeMap
	unsigned char	*buffer;	// to memory instead of to texture
	bool	usePBO;				// lightgem optimization
	renderCrop_t scissor;		// only copy given scissor without image/buffer
};

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

// 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 =			0x4000;

// a request for frame memory will never fail
// (until malloc fails), but it may force the
// allocation of a new memory block that will
// be discontinuous with the existing memory
typedef struct frameMemoryBlock_s {
	struct frameMemoryBlock_s *next;
	int		size;
	int		used;
	int		poop;		// so that base is 16 byte aligned
	byte	base[4];	// dynamically allocated as [size]
} frameMemoryBlock_t;

// all of the information needed by the back end must be
// contained in a frameData_t.  This entire structure is
// duplicated so the front and back end can run in parallel
// on an SMP machine
typedef struct {
	std::atomic<int>	frameMemoryAllocated;
	std::atomic<int>	frameMemoryUsed;
	byte				*frameMemory;

	srfTriangles_t 		*firstDeferredFreeTriSurf;
	srfTriangles_t 		*lastDeferredFreeTriSurf;
	idSysMutex			deferredFreeMutex;

	int					memoryHighwater;	// max used on any frame

	// the currently building command list
	// commands can be inserted at the front if needed, as for required
	// dynamically generated textures
	emptyCommand_t		*cmdHead, *cmdTail;		// may be of other command type based on commandId
} frameData_t;

extern	frameData_t		*frameData;
extern	frameData_t		*backendFrameData;

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

void R_LockSurfaceScene( viewDef_t &parms );
void R_ClearCommandChain( frameData_t *frameData );
void R_AddDrawViewCmd( viewDef_t &parms );

void R_LockView_FrontendStart( viewDef_t &parms );
void R_LockView_BackendTransfer( viewDef_t &parms );

void R_ReloadGuis_f( const idCmdArgs &args );
void R_ListGuis_f( const idCmdArgs &args );

void *R_GetCommandBuffer( int bytes );
void R_IssueRenderCommands( frameData_t *frameData, bool swapBuffers );

// 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
*/
typedef struct {
	int		c_sphere_cull_in, c_sphere_cull_clip, c_sphere_cull_out;
	int		c_box_cull_in, c_box_cull_out;
	int		c_createInteractions;	// number of calls to idInteraction::CreateInteraction
	int		c_createLightTris;
	int		c_createShadowVolumes;
	int		c_generateMd5;
	int		c_entityDefCallbacks;
	int		c_alloc, c_free;		// counts for R_StaticAllc/R_StaticFree
	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, c_lightUpdates, c_entityReferences, c_lightReferences;
	int		c_guiSurfs, c_noshadowSurfs;
	int		frontEndMsec;			// sum of time in all RE_RenderScene's in a frame
	int		frontEndMsecLast;		// time in last RE_RenderScene
} performanceCounters_t;


typedef struct {
	int		current2DMap;
	int		currentCubeMap;
} tmu_t;

const int MAX_MULTITEXTURE_UNITS = 32;
typedef struct {
	tmu_t		tmu[MAX_MULTITEXTURE_UNITS];
	int			currenttmu;

	int			faceCulling;
	int			glStateBits;
	bool		forceGlState;		// the next GL_State will ignore glStateBits and set everything
} glstate_t;


// stgatilov: draw calls are tagged with this type for statistics
// see r_showPrimitives and backEndCounters_t
typedef enum {
	DCK_DEPTH_PREPASS,
	DCK_SURFACE_PASS,
	DCK_INTERACTION,
	DCK_SHADOW,
	DCK_LIGHT_PASS,
	DCK_MISC,			// other kinds
	DCK_NONE,			// ignore in all displayed stats
	DCK_COUNT			// auxilliary
} drawCallKind_t;

typedef struct {
	int		c_surfaces;

	int		c_drawCalls[DCK_COUNT];
	int		c_drawIndexes[DCK_COUNT];
	int		c_drawVerts[DCK_COUNT];

	int		c_copyFrameBuffer;
	int		c_copyDepthBuffer;

	uint	textureLoads, textureBackgroundLoads, textureLoadTime, textureUploadTime;

	int		msec;			// total msec for backend run
	int		msecLast;		// last msec for backend run
	char	waitedFor;		// . - backend, F = frontend, S - GPU Sync
} backEndCounters_t;

// all state modified by the back end is separated
// from the front end state
typedef struct {
	int					frameCount;		// used to track all images used in a frame
	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

	viewLight_t 		*vLight;
	int					depthFunc;			// GLS_DEPTHFUNC_EQUAL, or GLS_DEPTHFUNC_LESS for translucent
	float				lightColor[4];		// evaluation of current light's color stage

	float				lightScale;			// Every light color calaculation will be multiplied by this,
	// which will guarantee that the result is < tr.backEndRendererMaxLight
	// A card with high dynamic range will have this set to 1.0
	float				overBright;			// The amount that all light interactions must be multiplied by
	// with post processing to get the desired total light level.
	// A high dynamic range card will have this set to 1.0.

	// our OpenGL state deltas
	glstate_t			glState;
} backEndState_t;

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;

struct ImageForSubview {
	bool purged = false;
	int width = -1, height = -1;
	idImageScratch *image = nullptr;
	int lastUsedFrameCount = INT_MIN;
};

/*
** 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.
*/
// #4395 Duzenko lightem pixel pack buffer optimization
class idRenderSystemLocal : public idRenderSystem {
public:
	// external functions
	virtual void			Init( void ) override;
	virtual void			Shutdown( void ) override;
	virtual void			InitOpenGL( void ) override;
	virtual void			ShutdownOpenGL( void ) override;
	virtual bool			IsOpenGLRunning( void ) const override;
	virtual bool			IsFullScreen( void ) const override;
	virtual int				GetScreenWidth( void ) const override;
	virtual int				GetScreenHeight( void ) const override;
	virtual idRenderWorld 	*AllocRenderWorld( void ) override;
	virtual void			FreeRenderWorld( idRenderWorld *rw ) override;
	virtual void			BeginLevelLoad( void ) override;
	virtual void			EndLevelLoad( void ) override;
	virtual bool			RegisterFont( const char *fontName, const fontParameters_t &params, fontInfoEx_t &font ) override;
	virtual void			SetColor( const idVec4 &rgba ) override;
	virtual void			SetColor4( float r, float g, float b, float a ) override;
	virtual void			DrawStretchPic( const idDrawVert *verts, const glIndex_t *indexes, int vertCount, int indexCount, const idMaterial *material,
											bool clip = true, float x = 0.0f, float y = 0.0f, float w = 640.0f, float h = 0.0f ) override;
	virtual void			DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *material ) override;

	virtual void			DrawStretchTri( idVec2 p1, idVec2 p2, idVec2 p3, idVec2 t1, idVec2 t2, idVec2 t3, const idMaterial *material ) override;
	virtual void			GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ) override;
	virtual void			GetGLSettings( int &width, int &height ) override;
	virtual void			PrintMemInfo( MemInfo_t *mi ) override;

	virtual void			DrawSmallChar( int x, int y, int ch, const idMaterial *material ) override;
	virtual void			DrawSmallStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor, const idMaterial *material ) override;
	virtual void			DrawBigChar( int x, int y, int ch, const idMaterial *material ) override;
	virtual void			DrawBigStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor, const idMaterial *material ) override;
	virtual void			WriteDemoPics() override;
	virtual void			DrawDemoPics() override;
	virtual void			BeginFrame( int windowWidth, int windowHeight ) override;
	virtual void			EndFrame( int *frontEndMsec, int *backEndMsec ) override;
	virtual void			TakeScreenshot( int width, int height, const char *fileName, int downSample, renderView_t *ref, bool envshot = false ) override;
	virtual void			CropRenderSize( int width, int height, bool makePowerOfTwo = false, bool forceDimensions = false ) override;
	virtual void			GetCurrentRenderCropSize( int &width, int &height ) override;
	virtual void			CaptureRenderToImage( idImageScratch &image, const renderCrop_t *scissor = nullptr ) override;
	virtual void			CaptureRenderToBuffer( unsigned char *buffer, bool usePbo = false ) override;
	virtual void			PostProcess() override;
	virtual void			UnCrop() override;

public:
	// internal functions
							idRenderSystemLocal() { Clear(); }
	virtual					~idRenderSystemLocal() override {}

	void					Clear( void );
	void					RenderViewToViewport( const renderView_t &renderView, idScreenRect &viewport );

	idImageScratch *		CreateImageForSubview();	// create or reuse intermediate texture for currently set render crop
	void					PurgeOldSubviewImages();	// free intermediate textures not used for some time, but keep images alive

public:
	// renderer globals
	bool					takingScreenshot;

	int						frameCount;			// incremented every frame
	int						viewCount;			// incremented every view (twice a scene if subviewed)
												// and every R_MarkFragments call
	int						viewCountAtFrameStart;	// stgatilov: current frame has views [viewCountAtFrameStart .. viewCount)

	int						staticAllocCount;	// running total of bytes allocated

	float					frameShaderTime;	// shader time for all non-world 2D rendering

	int						viewportOffset[2];	// for doing larger-than-window tiled renderings
	int						tiledViewport[2];

	idVec4					ambientLightVector;	// used for "ambient bump mapping"

	float					sortOffset;				// for determinist sorting of equal sort materials

	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 		*defaultMaterial;
	const idMaterial 		*defaultShaderPoint;
	const idMaterial 		*defaultShaderProj;

	idImageAsset 			*testImage;
	bool					testImageIsCubemap;
	idCinematic 			*testVideo;
	idImageScratch			*testVideoFrame;
	float					testVideoStartTime;

	viewDef_t 				*viewDef;

	performanceCounters_t	pc;					// performance counters

	viewEntity_t			identitySpace;		// can use if we don't know viewDef->worldSpace is valid
	FILE 					*logFile;			// for logging GL calls and frame breaks

	renderCrop_t			renderCrops[MAX_RENDER_CROPS];
	int						currentRenderCrop;

	// GUI drawing variables for surface creation
	int						guiRecursionLevel;		// to prevent infinite overruns
	class idGuiModel 		*guiModel;
	class idGuiModel 		*demoGuiModel;

	idImageScratch			*xrayGuiImageOverride;

	unsigned short			gammaTable[256];	// brightness / gamma modify this
	idParallelJobList*		frontEndJobList;

	bool					lockedViewAvailable = false;	// debug only: for r_lockView 
	int						lockedViewSinceFrame = -1;		// ...
	renderView_t			lockedViewData;					// ...

	idList<ImageForSubview> subviewImages;
};

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_ext_vertex_array_range;

extern idCVar r_glDriver;				// "opengl32", etc
extern idCVar r_glDebugOutput;
extern idCVar r_glDebugContext;
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 idCVarBool r_fboSRGB;

extern idCVar r_ignore;					// used for random debugging without defining new vars
extern idCVar r_ignore2;				// used for random debugging without defining new vars
extern idCVar r_znear;					// near Z clip plane

extern idCVar r_finish;					// force a call to glFinish() every frame
extern idCVar r_frontBuffer;			// draw to front buffer for debugging
extern idCVar r_swapInterval;			// changes Vsync (wglSwapInterval)
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_shadows;				// enable shadows
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_ambientMinLevel;		// tweaking overall ambient brightness
extern idCVar r_ambientGamma;			// tweaking overall ambient brightness

extern idCVar r_checkBounds;			// compare all surface bounds with precalculated ones

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_useCulling;				// 0 = none, 1 = sphere, 2 = sphere + box
extern idCVar r_useLightPortalCulling;	// 0 = none, 1 = box, 2 = exact clip of polyhedron faces
extern idCVar r_useEntityPortalCulling;	// 0 = none, 1 = box
extern idCVar r_useLightScissors;		// 1 = use custom scissor rectangle for each light
extern idCVar r_useClippedLightScissors;// 0 = full screen when near clipped, 1 = exact when near clipped, 2 = exact always
extern idCVar r_useEntityCulling;		// 0 = none, 1 = box
extern idCVar r_useEntityScissors;		// 1 = use custom scissor rectangle for each entity
extern idCVar r_useInteractionCulling;	// 1 = cull interactions
extern idCVar r_useInteractionScissors;	// 1 = use a custom scissor rectangle for each interaction
extern idCVar r_useFrustumFarDistance;	// if != 0 force the view frustum far distance to this distance
extern idCVar r_useShadowCulling;		// try to cull shadows from partially visible lights
extern idCVar r_usePreciseTriangleInteractions;	// 1 = do winding clipping to determine if each ambiguous tri should be lit
extern idCVar r_useTurboShadow;			// 1 = use the infinite projection with W technique for dynamic shadows
extern idCVar r_useInteractionTable;
extern idCVar r_useExternalShadows;		// 1 = skip drawing caps when outside the light volume
extern idCVar r_useOptimizedShadows;	// 1 = use the dmap generated static shadow volumes
extern idCVar r_useShadowProjectedCull;	// 1 = discard triangles outside light volume before shadowing
extern idCVar r_useDeferredTangents;	// 1 = don't always calc tangents after deform
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_useVertexBuffers;		// if 0, don't use ARB_vertex_buffer_object for vertexes
extern idCVar r_useIndexBuffers;		// if 0, don't use ARB_vertex_buffer_object for indexes
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_useDepthBoundsTest;     // use depth bounds test to reduce shadow fill

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_skipEntities;			// skip non-world geometry
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 idCVarInt r_skipNewAmbient;			// bypasses all vertex/fragment program ambients
extern idCVar r_skipBlendLights;		// skip all blend lights
extern idCVarInt r_skipFogLights;			// skip all fog lights
extern idCVarBool 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_skipParallax;

extern idCVar r_skipOverlays;			// skip overlay surfaces
extern idCVar r_skipROQ;
extern idCVar r_skipDepthCapture;		// skip capture of early depth pass. revelator + SteveL #3877
extern idCVar r_useSoftParticles;		// SteveL #3878
extern idCVar r_lockView;

extern idCVar r_ignoreGLErrors;

extern idCVar r_forceLoadImages;		// draw all images to screen after registration
extern idCVar r_demonstrateBug;			// used during development to show IHV's their problems
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_showDefs;				// report the number of modeDefs and lightDefs in view
extern idCVar r_showTrace;				// show the intersection of an eye trace with the world
extern idCVar r_showSmp;				// show which end (front or back) is blocking
extern idCVar com_smp;					// enable SMP
extern idCVar r_showDepth;				// display the contents of the depth buffer and the depth range
extern idCVar r_showImages;				// draw all images to screen instead of rendering
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 idCVarInt r_showEntityDraws;
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 idCVarInt 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_showShadowCount;		// colors screen based on shadow volume depth complexity
extern idCVar r_showLightScissors;		// show light scissor rectangles
extern idCVar r_showEntityScissors;		// show entity scissor rectangles
extern idCVar r_showInteractionFrustums;// show a frustum for each interaction
extern idCVar r_showInteractionScissors;// show screen rectangle which contains the interaction frustum
extern idCVar r_showMemory;				// print frame memory utilization
extern idCVar r_showCull;				// report sphere and box culling stats
extern idCVar r_showInteractions;		// report interaction generation activity
extern idCVar r_showSurfaces;			// report surface/light/shadow counts
extern idCVar r_showPrimitives;			// report vertex/index/draw counts
extern idCVarInt r_showPortals;			// draw portal outlines in color based on passed / not passed
extern idCVar r_showAlloc;				// report alloc/free counts
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_testStepGamma;			// draw a grid pattern to test gamma levels
extern idCVar r_testGammaBias;			// draw a grid pattern to test gamma levels

extern idCVar r_interactionProgram;			// experiment with vertex/fragment programs

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_skipModels;

extern idCVar r_jitter;					// randomly subpixel jitter the projection matrix
extern idCVar r_lightSourceRadius;		// for soft-shadow sampling
extern idCVar r_lockSurfaces;
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_showRenderToTexture;

// rebb: dedicated ambient
extern idCVar r_dedicatedAmbient;

extern idCVar r_softShadowsQuality;
extern idCVar r_softShadowsRadius;
extern idCVar r_useBumpmapLightTogglingFix;

extern idCVar r_useAnonreclaimer;
extern idCVar r_shadowMapSinglePass;

// stgatilov ROQ
extern idCVar r_cinematic_legacyRoq;

//stgatilov: temporary cvars, to be removed when ARB->GLSL migration is complete and settled
extern idCVar r_glCoreProfile;

//stgatilov #5816: volumetric light config
extern idCVar r_volumetricSamples;
extern idCVar r_volumetricDither;

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

GL wrapper/helper functions

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

void	GL_SelectTexture( int unit );
void	GL_CheckErrors( void );
void	GL_ClearStateDelta( void );
void	GL_State( int stateVector );
void	GL_Cull( int cullType );

/* Set scissor region in absolute screen coordinates */
void	GL_ScissorAbsolute( int x /* left*/, int y /* bottom */, int w, int h );
/* Set scissor region in glConfig vidSize screen coordinates, scaled by current FBO resolution */
void	GL_ScissorVidSize( int x /* left*/, int y /* bottom */, int w, int h );
/* Set scissor region in relative coordinates [0,1] */
void	GL_ScissorRelative( float x /* left*/, float y /* bottom */, float w, float h );

/* Set viewport in absolute screen coordinates */
void	GL_ViewportAbsolute( int x /* left */, int y /* bottom */, int w, int h );
/* Set viewport in glConfig vidSize screen coordinates, scaled by current FBO resolution */
void	GL_ViewportVidSize( int x /* left */, int y /* bottom */, int w, int h );
/* Set viewport in relative coordinates [0,1] */
void	GL_ViewportRelative( float x /* left */, float y /* bottom */, float w, float h );

void	GL_SetProjection( float* matrix );

// RAII helper to apply all surface-specific depth customizations:
//	* polygon offset
//  * weapon depth hack
struct ApplyDepthTweaks {
	const drawSurf_t *drawSurf = nullptr;
	ApplyDepthTweaks(const drawSurf_t *surf);
	~ApplyDepthTweaks();
};

// RAII-style wrapper for qglDepthBoundsEXT
class DepthBoundsTest {
public:
	DepthBoundsTest( const idScreenRect &scissorRect );
	void Update( const idScreenRect &scissorRect );
	~DepthBoundsTest();
};

const int GLS_SRCBLEND_ONE						= 0x0;
const int GLS_SRCBLEND_ZERO						= 0x00000001;
const int GLS_SRCBLEND_DST_COLOR				= 0x00000003;
const int GLS_SRCBLEND_ONE_MINUS_DST_COLOR		= 0x00000004;
const int GLS_SRCBLEND_SRC_ALPHA				= 0x00000005;
const int GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA		= 0x00000006;
const int GLS_SRCBLEND_DST_ALPHA				= 0x00000007;
const int GLS_SRCBLEND_ONE_MINUS_DST_ALPHA		= 0x00000008;
const int GLS_SRCBLEND_ALPHA_SATURATE			= 0x00000009;
const int GLS_SRCBLEND_BITS						= 0x0000000f;

const int GLS_DSTBLEND_ZERO						= 0x0;
const int GLS_DSTBLEND_ONE						= 0x00000020;
const int GLS_DSTBLEND_SRC_COLOR				= 0x00000030;
const int GLS_DSTBLEND_ONE_MINUS_SRC_COLOR		= 0x00000040;
const int GLS_DSTBLEND_SRC_ALPHA				= 0x00000050;
const int GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA		= 0x00000060;
const int GLS_DSTBLEND_DST_ALPHA				= 0x00000070;
const int GLS_DSTBLEND_ONE_MINUS_DST_ALPHA		= 0x00000080;
const int GLS_DSTBLEND_BITS						= 0x000000f0;


// these masks are the inverse, meaning when set the glColorMask value will be 0,
// preventing that channel from being written
const int GLS_DEPTHMASK							= 0x00000100;
const int GLS_REDMASK							= 0x00000200;
const int GLS_GREENMASK							= 0x00000400;
const int GLS_BLUEMASK							= 0x00000800;
const int GLS_ALPHAMASK							= 0x00001000;
const int GLS_COLORMASK							= ( GLS_REDMASK | GLS_GREENMASK | GLS_BLUEMASK );

const int GLS_POLYMODE_LINE						= 0x00002000;

const int GLS_DEPTHFUNC_ALWAYS					= 0x00010000;
const int GLS_DEPTHFUNC_EQUAL					= 0x00020000;
const int GLS_DEPTHFUNC_LESS					= 0x0;

/*const int GLS_ATEST_EQ_255						= 0x10000000;
const int GLS_ATEST_LT_128						= 0x20000000;
const int GLS_ATEST_GE_128						= 0x40000000;
const int GLS_ATEST_BITS						= 0x70000000;*/

const int GLS_DEFAULT							= GLS_DEPTHFUNC_ALWAYS;

void R_InitOpenGL( void );
void R_DoneFreeType( void );
void R_SetColorMappings( void );

void R_ScreenShot_f( const idCmdArgs &args );
void R_StencilShot( void );


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

IMPLEMENTATION SPECIFIC FUNCTIONS

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

typedef struct {
	int			width;
	int			height;
	bool		fullScreen;
	bool		stereo;
	int			displayHz;
	int			multiSamples;
} glimpParms_t;

bool		GLimp_Init( glimpParms_t parms );
// If the desired mode can't be set satisfactorily, false will be returned.
// 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( void );
// Destroys the rendering context, closes the window, resets the resolution,
// and resets the gamma ramps.

void		GLimp_SwapBuffers( void );
// Calls the system specific swapbuffers routine, and may also perform
// other system specific cvar checks that happen every frame.
// This will not be called if 'r_drawBuffer GL_FRONT'

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 )( void ) );
// Returns false if the system only has a single processor

void 		*GLimp_BackEndSleep( void );
void		GLimp_FrontEndSleep( void );
void		GLimp_WakeBackEnd( void *data );
// these functions implement the dual processor syncronization

void		GLimp_ActivateContext( void );
void		GLimp_DeactivateContext( void );
// 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 );

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

MAIN

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

void R_RenderView( viewDef_t &parms );

idSphere R_BoundingSphereOfLocalBox( const idBounds &bounds, const float modelMatrix[16] );
bool R_CullFrustumSphere( const idSphere &bounds, int numPlanes, const idPlane *planes );
bool R_RadiusCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes );
bool R_CornerCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes );
/*
=================
R_CullLocalBox

// performs radius cull first, then corner cull
Performs quick test before expensive test
Returns true if the box is outside the given global frustum, (positive sides are out)
Moved from tr_main.cpp to save on the function call cost
=================
*/
ID_INLINE bool R_CullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
	if ( R_RadiusCullLocalBox( bounds, modelMatrix, numPlanes, planes ) ) {
		return true;
	}
	return R_CornerCullLocalBox( bounds, modelMatrix, numPlanes, planes );
}

void R_AxisToModelMatrix( const idMat3 &axis, const idVec3 &origin, float modelMatrix[16] );

// note that many of these assume a normalized matrix, and will not work with scaled axis
void R_GlobalPointToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out );
void R_GlobalVectorToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out );
void R_GlobalPlaneToLocal( const float modelMatrix[16], const idPlane &in, idPlane &out );
void R_PointTimesMatrix( const float modelMatrix[16], const idVec4 &in, idVec4 &out );
void R_LocalPointToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out );
void R_LocalVectorToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out );
void R_LocalPlaneToGlobal( const float modelMatrix[16], const idPlane &in, idPlane &out );
void R_TransformEyeZToDepth( float src_z, const float *projectionMatrix, float &dst_depth );
void R_TransformDepthToEyeZ( float src_depth, const float *projectionMatrix, float &dst_z );

void R_GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc );

void R_TransformModelToClip( const idVec3 &src, const float *modelMatrix, const float *projectionMatrix, idPlane &eye, idPlane &dst );

void R_TransformClipToDevice( const idPlane &clip, const viewDef_t *view, idVec3 &normalized );

void R_TransposeGLMatrix( const float in[16], float out[16] );

void R_SetViewMatrix( viewDef_t &viewDef );
void R_SetupViewFrustum( viewDef_t &viewDef );
void R_SetupProjection( viewDef_t &viewDef );

// corrected this one.
// note: "out" transform is equivalent to first applying transform "a", then transform "b"
void myGlMultMatrix( const float a[16], const float b[16], float out[16] );

void R_IdentityGLMatrix( float out[16] );

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

LIGHT

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

void R_ListRenderLightDefs_f( const idCmdArgs &args );
void R_ListRenderEntityDefs_f( const idCmdArgs &args );

bool R_IssueEntityDefCallback( idRenderEntityLocal *def );
idRenderModel *R_EntityDefDynamicModel( idRenderEntityLocal *def );

viewEntity_t *R_SetEntityDefViewEntity( idRenderEntityLocal *def );
viewLight_t *R_SetLightDefViewLight( idRenderLightLocal *def );

void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity,
					const idMaterial *shader, const idScreenRect &scissor, const float soft_particle_radius = -1.0f, bool deferred = false ); // soft particles in #3878

drawSurf_t *R_PrepareLightSurf( const srfTriangles_t *tri, const viewEntity_t *space,
					const idMaterial *shader, const idScreenRect &scissor, bool viewInsideShadow, bool blockSelfShadows );

bool R_CreateAmbientCache( srfTriangles_t *tri, bool needsLighting );
void R_CreatePrivateShadowCache( srfTriangles_t *tri );
void R_CreateVertexProgramShadowCache( srfTriangles_t *tri );

void R_AssignShadowMapAtlasPages( void );

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

LIGHTRUN

============================================================
*/
void R_RegenerateWorld_f( const idCmdArgs &args );

void R_ModulateLights_f( const idCmdArgs &args );

void R_SetLightProject( idPlane lightProject[4], const idVec3 origin, const idVec3 targetPoint,
						const idVec3 rightVector, const idVec3 upVector, const idVec3 start, const idVec3 stop );

void R_AddLightSurfaces( void );
void R_AddModelSurfaces( void );
void R_RemoveUnecessaryViewLights( void );

void R_FreeDerivedData( void );
void R_ReCreateWorldReferences( void );
//anon begin
void R_DeriveEntityData( idRenderEntityLocal *def );
//anon end

void R_CreateEntityRefs( idRenderEntityLocal *def );
void R_CreateLightRefs( idRenderLightLocal *light );

void R_SetLightFrustum( const idPlane lightProject[4], idPlane frustum[6] );
void R_DeriveLightData( idRenderLightLocal *light );
void R_FreeLightDefDerivedData( idRenderLightLocal *light );
void R_CheckForEntityDefsUsingModel( idRenderModel *model );

void R_ClearEntityDefDynamicModel( idRenderEntityLocal *def );
void R_FreeEntityDefDerivedData( idRenderEntityLocal *def, bool keepDecals, bool keepCachedDynamicModel );
void R_FreeEntityDefDecals( idRenderEntityLocal *def );
void R_FreeEntityDefOverlay( idRenderEntityLocal *def );
void R_FreeEntityDefChildren( idRenderEntityLocal *def );
void R_FreeEntityDefFadedDecals( idRenderEntityLocal *def, int time );
void R_InitRenderParmsForChildEntity( renderEntity_t &parms, idRenderEntityLocal *def, idRenderModel *model );

void R_CreateLightDefFogPortals( idRenderLightLocal *ldef );

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

POLYTOPE

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

srfTriangles_t *R_PolytopeSurface( int numPlanes, const idPlane *planes, idWinding *windings );
bool R_PolytopeSurfaceFrustumLike( const idPlane planes[6], idVec3 vertices[8], idWinding windings[6], srfTriangles_t* *surface = NULL );

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

RENDER

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

void RB_EnterWeaponDepthHack();
void RB_EnterModelDepthHack( float depth );
void RB_LeaveDepthHack();
void RB_DrawElementsImmediate( const srfTriangles_t *tri );
void RB_RenderTriangleSurface( const drawSurf_t *surf );
void RB_T_RenderTriangleSurface( const drawSurf_t *surf );
void RB_RenderDrawSurfListWithFunction( drawSurf_t **drawSurfs, int numDrawSurfs,
										void ( *triFunc_ )( const drawSurf_t * ) );
void RB_RenderDrawSurfChainWithFunction( const drawSurf_t *drawSurfs,
		void ( *triFunc_ )( const drawSurf_t * ) );
void RB_LoadShaderTextureMatrix( const float *shaderRegisters, const shaderStage_t* pStage );
void RB_GetShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture, float matrix[16] );

void RB_BeginDrawingView( bool colorIsBackground );

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

DRAW_STANDARD

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

void RB_DrawElementsWithCounters( const drawSurf_t* surf, drawCallKind_t kind = DCK_MISC );
void RB_DrawElementsInstanced( const drawSurf_t *surf, int instances, drawCallKind_t kind = DCK_MISC );
void RB_DrawTriangles( const srfTriangles_t& tri );
void RB_BindVariableStageImage( const textureStage_t *texture, const float *shaderRegisters );

// postprocessing related
void RB_DrawFullScreenQuad( float e = 1 );
void RB_DrawFullScreenTri();

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

TR_STENCILSHADOWS

"facing" should have one more element than tri->numIndexes / 3, which should be set to 1

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

void R_MakeShadowFrustums( idRenderLightLocal *def );

typedef enum {
	SG_DYNAMIC,		// use infinite projections
	SG_STATIC,		// clip to bounds
	SG_OFFLINE		// perform very time consuming optimizations
} shadowGen_t;

srfTriangles_t *R_CreateShadowVolume( const idRenderEntityLocal *ent,
									  const srfTriangles_t *tri, const idRenderLightLocal *light,
									  shadowGen_t optimize, srfCullInfo_t &cullInfo );

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

TR_TURBOSHADOW

Fast, non-clipped overshoot shadow volumes

"facing" should have one more element than tri->numIndexes / 3, which should be set to 1
calling this function may modify "facing" based on culling

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

extern idCVar r_modelBvhShadowsGranularity;

srfTriangles_t *R_CreateVertexProgramTurboShadowVolume( const idRenderEntityLocal *ent,
		const srfTriangles_t *tri, const idRenderLightLocal *light,
		srfCullInfo_t &cullInfo );

// stgatilov #5886: BVH-accelerated equivalent of turbo shadow volume generation
srfTriangles_t *R_CreateVertexProgramBvhShadowVolume( const idRenderEntityLocal *ent,
	const srfTriangles_t *tri, const idRenderLightLocal *light );


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

util/shadowopt3

dmap time optimization of shadow volumes, called from R_CreateShadowVolume

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


typedef struct {
	idVec3	*verts;			// includes both front and back projections, caller should free
	int		numVerts;
	glIndex_t	*indexes;	// caller should free

	// indexes must be sorted frontCap, rearCap, silPlanes so the caps can be removed
	// when the viewer is in a position that they don't need to see them
	int		numFrontCapIndexes;
	int		numRearCapIndexes;
	int		numSilPlaneIndexes;
	int		totalIndexes;
} optimizedShadow_t;

optimizedShadow_t SuperOptimizeOccluders( idVec4 *verts, glIndex_t *indexes, int numIndexes,
		idPlane projectionPlane, idVec3 projectionOrigin );

void CleanupOptimizedShadowTris( srfTriangles_t *tri );

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

TRISURF

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

//#define USE_TRI_DATA_ALLOCATOR

void				R_InitTriSurfData( void );
void				R_ShutdownTriSurfData( void );
void				R_PurgeTriSurfData( frameData_t *frame );
void				R_ShowTriSurfMemory_f( const idCmdArgs &args );

srfTriangles_t 	*R_AllocStaticTriSurf( void );
srfTriangles_t 	*R_CopyStaticTriSurf( const srfTriangles_t *tri );
void				R_AllocStaticTriSurfVerts( srfTriangles_t *tri, int numVerts );
void				R_AllocStaticTriSurfIndexes( srfTriangles_t *tri, int numIndexes );
void				R_AllocStaticTriSurfShadowVerts( srfTriangles_t *tri, int numVerts );
void				R_AllocStaticTriSurfPlanes( srfTriangles_t *tri, int numIndexes );
void				R_ResizeStaticTriSurfVerts( srfTriangles_t *tri, int numVerts );
void				R_ResizeStaticTriSurfIndexes( srfTriangles_t *tri, int numIndexes );
void				R_ResizeStaticTriSurfShadowVerts( srfTriangles_t *tri, int numVerts );
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_FreeStaticTriSurfSilEdges( srfTriangles_t *tri );
void				R_FreeStaticTriSurf( srfTriangles_t *tri );
void				R_FreeStaticTriSurfVertexCaches( srfTriangles_t *tri );
void				R_FreeStaticTriSurfIndexes( srfTriangles_t *tri );
void				R_ReallyFreeStaticTriSurf( srfTriangles_t *tri );
void				R_FreeDeferredTriSurfs( frameData_t *frame );
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_IdentifySilEdges( srfTriangles_t *tri, bool omitCoplanarEdges );
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_DeriveFacePlanes( srfTriangles_t *tri );		// also called by renderbump
void				R_CleanupTriangles( srfTriangles_t *tri, bool createNormals, bool identifySilEdges, bool useUnsmoothedTangents );
void				R_ReverseTriangles( srfTriangles_t *tri );
void				R_BuildBvhForTri( 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, bool allocFacePlanes = true );

// 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
typedef struct deformInfo_s {
	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;

	int				numMirroredVerts;
	int 			*mirroredVerts;

	int				numIndexes;
	glIndex_t 		*indexes;

	glIndex_t 		*silIndexes;

	int				numDupVerts;
	int 			*dupVerts;

	int				numSilEdges;
	silEdge_t 		*silEdges;

	dominantTri_t 	*dominantTris;
} deformInfo_t;


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 );

typedef enum {
	BVH_TRI_SURELY_WITHIN_LIGHT = 0x1,
	BVH_TRI_SURELY_GOOD_ORI = 0x2,
	BVH_TRI_SURELY_MATCH = BVH_TRI_SURELY_WITHIN_LIGHT | BVH_TRI_SURELY_GOOD_ORI,
} bvhTriRangeInfo_t;

// range including all triangles with indices in [beg..end)
typedef struct triRange_s {
	int beg;				// first triangle of range
	int end;				// first triangle after range
	int info;				// bvhTriRangeInfo_t bitmask
	float box[2][3];		// bounding box of triangles in range

	// ("box" is not idBounds to avoid initialization cost inside idFlexListHuge)
	ID_FORCE_INLINE const idBounds& GetBox() const { return * (idBounds*) &box[0][0]; }
	ID_FORCE_INLINE idBounds& GetBox() { return * (idBounds*) &box[0][0]; }
} bvhTriRange_t;

void R_CullBvhByFrustumAndOrigin(
	const idBounds &rootBounds, const bvhNode_t *nodes,
	const idPlane frustum[6], int filterOri, const idVec3 &origin,
	int forceUnknown, int granularity,
	idFlexList<bvhTriRange_t, 128> &outIntervals
);

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

SUBVIEW

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

bool	R_PreciseCullSurface( const drawSurf_t *drawSurf, idBounds &ndcBounds );
bool	R_GenerateSubViews( void );

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

SCENE GENERATION

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

void R_InitFrameData( void );
void R_ShutdownFrameData( void );
void R_ToggleSmpFrame( void );
void *R_FrameAlloc( int bytes );
void *R_ClearedFrameAlloc( int bytes );
void R_FrameFree( void *data );

void *R_StaticAlloc( int bytes );		// just malloc with error checking
void *R_ClearedStaticAlloc( int bytes );	// with memset
void R_StaticFree( void *data );


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

RENDERER DEBUG TOOLS

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

float R_DrawTextLength( const char *text, float scale, int len );
void R_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 R_ClearDebugText( int time );
void R_AddDebugLine( const idVec4 &color, const idVec3 &start, const idVec3 &end, const int lifeTime, const bool depthTest );
void R_ClearDebugLines( int time );
void R_AddDebugPolygon( const idVec4 &color, const idWinding &winding, const int lifeTime, const bool depthTest );
void R_ClearDebugPolygons( int time );
void RB_ShowLights( void );
void RB_ShowLightCount( void );
void RB_ScanStencilBuffer( void );
void RB_ShowDestinationAlpha( void );
void RB_ShowOverdraw( void );
void R_Tools();
void RB_RenderDebugTools( drawSurf_t **drawSurfs, int numDrawSurfs );
void RB_InitDebugTools( void );
void RB_ShutdownDebugTools( void );
void RB_CopyDebugPrimitivesToBackend( void );

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

TR_BACKEND

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

void RB_SetDefaultGLState( void );
void RB_SetGL2D( void );
void RB_ShowImages( void );

void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds );
void RB_SwapBuffers();


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

TR_GUISURF

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

void R_SurfaceToTextureAxis( const srfTriangles_t *tri, idVec3 &origin, idVec3 axis[3] );
void R_RenderGuiSurf( idUserInterface *gui, drawSurf_t *drawSurf );

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

TR_ORDERINDEXES

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

void R_OrderIndexes( int numIndexes, glIndex_t *indexes );

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

TR_DEFORM

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

void R_DeformDrawSurf( drawSurf_t *drawSurf );

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

TR_TRACE

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

typedef struct {
	float		fraction;
	// only valid if fraction < 1.0
	idVec3		point;
	idVec3		normal;
	int			indexes[3];
	bool		backHit;
} localTrace_t;

localTrace_t R_LocalTrace( const idVec3 &start, const idVec3 &end, const float radius, bool frontOnly, const srfTriangles_t *tri );

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

TR_SHADOWBOUNDS

=============================================================
*/
idScreenRect R_CalcIntersectionScissor( const idRenderLightLocal *lightDef,
										const idRenderEntityLocal *entityDef,
										const viewDef_t *viewDef );

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

#include "renderer/frontend/RenderWorld_local.h"
#include "renderer/frontend/GuiModel.h"
#include "renderer/VertexCache.h"

#endif /* !__TR_LOCAL_H__ */
