DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

tr_backend_rendertools.cpp (65000B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 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.
     23 
     24 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.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #pragma hdrstop
     30 #include "../idlib/precompiled.h"
     31 
     32 #include "tr_local.h"
     33 #include "simplex.h"	// line font definition
     34 
     35 idCVar r_showCenterOfProjection( "r_showCenterOfProjection", "0", CVAR_RENDERER | CVAR_BOOL, "Draw a cross to show the center of projection" );
     36 idCVar r_showLines( "r_showLines", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = draw alternate horizontal lines, 2 = draw alternate vertical lines" );
     37 
     38 #define MAX_DEBUG_LINES			16384
     39 
     40 typedef struct debugLine_s {
     41 	idVec4		rgb;
     42 	idVec3		start;
     43 	idVec3		end;
     44 	bool		depthTest;
     45 	int			lifeTime;
     46 } debugLine_t;
     47 
     48 debugLine_t		rb_debugLines[ MAX_DEBUG_LINES ];
     49 int				rb_numDebugLines = 0;
     50 int				rb_debugLineTime = 0;
     51 
     52 #define MAX_DEBUG_TEXT			512
     53 
     54 typedef struct debugText_s {
     55 	idStr		text;
     56 	idVec3		origin;
     57 	float		scale;
     58 	idVec4		color;
     59 	idMat3		viewAxis;
     60 	int			align;
     61 	int			lifeTime;
     62 	bool		depthTest;
     63 } debugText_t;
     64 
     65 debugText_t		rb_debugText[ MAX_DEBUG_TEXT ];
     66 int				rb_numDebugText = 0;
     67 int				rb_debugTextTime = 0;
     68 
     69 #define MAX_DEBUG_POLYGONS		8192
     70 
     71 typedef struct debugPolygon_s {
     72 	idVec4		rgb;
     73 	idWinding	winding;
     74 	bool		depthTest;
     75 	int			lifeTime;
     76 } debugPolygon_t;
     77 
     78 debugPolygon_t	rb_debugPolygons[ MAX_DEBUG_POLYGONS ];
     79 int				rb_numDebugPolygons = 0;
     80 int				rb_debugPolygonTime = 0;
     81 
     82 static void RB_DrawText( const char *text, const idVec3 &origin, float scale, const idVec4 &color, const idMat3 &viewAxis, const int align );
     83 
     84 void RB_SetMVP( const idRenderMatrix & mvp );
     85 
     86 /*
     87 ================
     88 RB_DrawBounds
     89 ================
     90 */
     91 void RB_DrawBounds( const idBounds &bounds ) {
     92 	if ( bounds.IsCleared() ) {
     93 		return;
     94 	}
     95 	qglBegin( GL_LINE_LOOP );
     96 	qglVertex3f( bounds[0][0], bounds[0][1], bounds[0][2] );
     97 	qglVertex3f( bounds[0][0], bounds[1][1], bounds[0][2] );
     98 	qglVertex3f( bounds[1][0], bounds[1][1], bounds[0][2] );
     99 	qglVertex3f( bounds[1][0], bounds[0][1], bounds[0][2] );
    100 	qglEnd();
    101 	qglBegin( GL_LINE_LOOP );
    102 	qglVertex3f( bounds[0][0], bounds[0][1], bounds[1][2] );
    103 	qglVertex3f( bounds[0][0], bounds[1][1], bounds[1][2] );
    104 	qglVertex3f( bounds[1][0], bounds[1][1], bounds[1][2] );
    105 	qglVertex3f( bounds[1][0], bounds[0][1], bounds[1][2] );
    106 	qglEnd();
    107 
    108 	qglBegin( GL_LINES );
    109 	qglVertex3f( bounds[0][0], bounds[0][1], bounds[0][2] );
    110 	qglVertex3f( bounds[0][0], bounds[0][1], bounds[1][2] );
    111 
    112 	qglVertex3f( bounds[0][0], bounds[1][1], bounds[0][2] );
    113 	qglVertex3f( bounds[0][0], bounds[1][1], bounds[1][2] );
    114 
    115 	qglVertex3f( bounds[1][0], bounds[0][1], bounds[0][2] );
    116 	qglVertex3f( bounds[1][0], bounds[0][1], bounds[1][2] );
    117 
    118 	qglVertex3f( bounds[1][0], bounds[1][1], bounds[0][2] );
    119 	qglVertex3f( bounds[1][0], bounds[1][1], bounds[1][2] );
    120 	qglEnd();
    121 }
    122 
    123 
    124 /*
    125 ================
    126 RB_SimpleSurfaceSetup
    127 ================
    128 */
    129 static void RB_SimpleSurfaceSetup( const drawSurf_t *drawSurf ) {
    130 	// change the matrix if needed
    131 	if ( drawSurf->space != backEnd.currentSpace ) {
    132 		qglLoadMatrixf( drawSurf->space->modelViewMatrix );
    133 		backEnd.currentSpace = drawSurf->space;
    134 	}
    135 
    136 	// change the scissor if needed
    137 	if ( !backEnd.currentScissor.Equals( drawSurf->scissorRect ) && r_useScissor.GetBool() ) {
    138 		GL_Scissor( backEnd.viewDef->viewport.x1 + drawSurf->scissorRect.x1, 
    139 					backEnd.viewDef->viewport.y1 + drawSurf->scissorRect.y1,
    140 					drawSurf->scissorRect.x2 + 1 - drawSurf->scissorRect.x1,
    141 					drawSurf->scissorRect.y2 + 1 - drawSurf->scissorRect.y1 );
    142 		backEnd.currentScissor = drawSurf->scissorRect;
    143 	}
    144 }
    145 
    146 /*
    147 ================
    148 RB_SimpleWorldSetup
    149 ================
    150 */
    151 static void RB_SimpleWorldSetup() {
    152 	backEnd.currentSpace = &backEnd.viewDef->worldSpace;
    153 
    154 
    155 	qglLoadMatrixf( backEnd.viewDef->worldSpace.modelViewMatrix );
    156 
    157 	GL_Scissor( backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1,
    158 				backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1,
    159 				backEnd.viewDef->scissor.x2 + 1 - backEnd.viewDef->scissor.x1,
    160 				backEnd.viewDef->scissor.y2 + 1 - backEnd.viewDef->scissor.y1 );
    161 	backEnd.currentScissor = backEnd.viewDef->scissor;
    162 }
    163 
    164 /*
    165 =================
    166 RB_PolygonClear
    167 
    168 This will cover the entire screen with normal rasterization.
    169 Texturing is disabled, but the existing glColor, glDepthMask,
    170 glColorMask, and the enabled state of depth buffering and
    171 stenciling will matter.
    172 =================
    173 */
    174 void RB_PolygonClear() {
    175 	qglPushMatrix();
    176 	qglPushAttrib( GL_ALL_ATTRIB_BITS  );
    177 	qglLoadIdentity();
    178 	qglDisable( GL_TEXTURE_2D );
    179 	qglDisable( GL_DEPTH_TEST );
    180 	qglDisable( GL_CULL_FACE );
    181 	qglDisable( GL_SCISSOR_TEST );
    182 	qglBegin( GL_POLYGON );
    183 	qglVertex3f( -20, -20, -10 );
    184 	qglVertex3f( 20, -20, -10 );
    185 	qglVertex3f( 20, 20, -10 );
    186 	qglVertex3f( -20, 20, -10 );
    187 	qglEnd();
    188 	qglPopAttrib();
    189 	qglPopMatrix();
    190 }
    191 
    192 /*
    193 ====================
    194 RB_ShowDestinationAlpha
    195 ====================
    196 */
    197 void RB_ShowDestinationAlpha() {
    198 	GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS );
    199 	GL_Color( 1, 1, 1 );
    200 	RB_PolygonClear();
    201 }
    202 
    203 /*
    204 ===================
    205 RB_ScanStencilBuffer
    206 
    207 Debugging tool to see what values are in the stencil buffer
    208 ===================
    209 */
    210 void RB_ScanStencilBuffer() {
    211 	int		counts[256];
    212 	int		i;
    213 	byte	*stencilReadback;
    214 
    215 	memset( counts, 0, sizeof( counts ) );
    216 
    217 	stencilReadback = (byte *)R_StaticAlloc( renderSystem->GetWidth() * renderSystem->GetHeight(), TAG_RENDER_TOOLS );
    218 	qglReadPixels( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback );
    219 
    220 	for ( i = 0; i < renderSystem->GetWidth() * renderSystem->GetHeight(); i++ ) {
    221 		counts[ stencilReadback[i] ]++;
    222 	}
    223 
    224 	R_StaticFree( stencilReadback );
    225 
    226 	// print some stats (not supposed to do from back end in SMP...)
    227 	common->Printf( "stencil values:\n" );
    228 	for ( i = 0; i < 255; i++ ) {
    229 		if ( counts[i] ) {
    230 			common->Printf( "%i: %i\n", i, counts[i] );
    231 		}
    232 	}
    233 }
    234 
    235 
    236 /*
    237 ===================
    238 RB_CountStencilBuffer
    239 
    240 Print an overdraw count based on stencil index values
    241 ===================
    242 */
    243 static void RB_CountStencilBuffer() {
    244 	int		count;
    245 	int		i;
    246 	byte	*stencilReadback;
    247 
    248 
    249 	stencilReadback = (byte *)R_StaticAlloc( renderSystem->GetWidth() * renderSystem->GetHeight(), TAG_RENDER_TOOLS );
    250 	qglReadPixels( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback );
    251 
    252 	count = 0;
    253 	for ( i = 0; i < renderSystem->GetWidth() * renderSystem->GetHeight(); i++ ) {
    254 		count += stencilReadback[i];
    255 	}
    256 
    257 	R_StaticFree( stencilReadback );
    258 
    259 	// print some stats (not supposed to do from back end in SMP...)
    260 	common->Printf( "overdraw: %5.1f\n", (float)count/(renderSystem->GetWidth() * renderSystem->GetHeight())  );
    261 }
    262 
    263 /*
    264 ===================
    265 R_ColorByStencilBuffer
    266 
    267 Sets the screen colors based on the contents of the
    268 stencil buffer.  Stencil of 0 = black, 1 = red, 2 = green,
    269 3 = blue, ..., 7+ = white
    270 ===================
    271 */
    272 static void R_ColorByStencilBuffer() {
    273 	int		i;
    274 	static float	colors[8][3] = {
    275 		{0,0,0},
    276 		{1,0,0},
    277 		{0,1,0},
    278 		{0,0,1},
    279 		{0,1,1},
    280 		{1,0,1},
    281 		{1,1,0},
    282 		{1,1,1},
    283 	};
    284 
    285 	// clear color buffer to white (>6 passes)
    286 	GL_Clear( true, false, false, 0, 1.0f, 1.0f, 1.0f, 1.0f );
    287 
    288 	// now draw color for each stencil value
    289 	qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
    290 	for ( i = 0; i < 6; i++ ) {
    291 		GL_Color( colors[i] );
    292 		renderProgManager.BindShader_Color();
    293 		qglStencilFunc( GL_EQUAL, i, 255 );
    294 		RB_PolygonClear();
    295 	}
    296 
    297 	qglStencilFunc( GL_ALWAYS, 0, 255 );
    298 }
    299 
    300 //======================================================================
    301 
    302 /*
    303 ==================
    304 RB_ShowOverdraw
    305 ==================
    306 */
    307 void RB_ShowOverdraw() {
    308 	const idMaterial *	material;
    309 	int					i;
    310 	drawSurf_t * *		drawSurfs;
    311 	const drawSurf_t *	surf;
    312 	int					numDrawSurfs;
    313 	viewLight_t *		vLight;
    314 
    315 	if ( r_showOverDraw.GetInteger() == 0 ) {
    316 		return;
    317 	}
    318 
    319 	material = declManager->FindMaterial( "textures/common/overdrawtest", false );
    320 	if ( material == NULL ) {
    321 		return;
    322 	}
    323 
    324 	drawSurfs = backEnd.viewDef->drawSurfs;
    325 	numDrawSurfs = backEnd.viewDef->numDrawSurfs;
    326 
    327 	int interactions = 0;
    328 	for ( vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next ) {
    329 		for ( surf = vLight->localInteractions; surf; surf = surf->nextOnLight ) {
    330 			interactions++;
    331 		}
    332 		for ( surf = vLight->globalInteractions; surf; surf = surf->nextOnLight ) {
    333 			interactions++;
    334 		}
    335 	}
    336 
    337 	// FIXME: can't frame alloc from the renderer back-end
    338 	drawSurf_t **newDrawSurfs = (drawSurf_t **)R_FrameAlloc( numDrawSurfs + interactions * sizeof( newDrawSurfs[0] ), FRAME_ALLOC_DRAW_SURFACE_POINTER );
    339 
    340 	for ( i = 0; i < numDrawSurfs; i++ ) {
    341 		surf = drawSurfs[i];
    342 		if ( surf->material ) {
    343 			const_cast<drawSurf_t *>(surf)->material = material;
    344 		}
    345 		newDrawSurfs[i] = const_cast<drawSurf_t *>(surf);
    346 	}
    347 
    348 	for ( vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next ) {
    349 		for ( surf = vLight->localInteractions; surf; surf = surf->nextOnLight ) {
    350 			const_cast<drawSurf_t *>(surf)->material = material;
    351 			newDrawSurfs[i++] = const_cast<drawSurf_t *>(surf);
    352 		}
    353 		for ( surf = vLight->globalInteractions; surf; surf = surf->nextOnLight ) {
    354 			const_cast<drawSurf_t *>(surf)->material = material;
    355 			newDrawSurfs[i++] = const_cast<drawSurf_t *>(surf);
    356 		}
    357 		vLight->localInteractions = NULL;
    358 		vLight->globalInteractions = NULL;
    359 	}
    360 
    361 	switch( r_showOverDraw.GetInteger() ) {
    362 		case 1: // geometry overdraw
    363 			const_cast<viewDef_t *>(backEnd.viewDef)->drawSurfs = newDrawSurfs;
    364 			const_cast<viewDef_t *>(backEnd.viewDef)->numDrawSurfs = numDrawSurfs;
    365 			break;
    366 		case 2: // light interaction overdraw
    367 			const_cast<viewDef_t *>(backEnd.viewDef)->drawSurfs = &newDrawSurfs[numDrawSurfs];
    368 			const_cast<viewDef_t *>(backEnd.viewDef)->numDrawSurfs = interactions;
    369 			break;
    370 		case 3: // geometry + light interaction overdraw
    371 			const_cast<viewDef_t *>(backEnd.viewDef)->drawSurfs = newDrawSurfs;
    372 			const_cast<viewDef_t *>(backEnd.viewDef)->numDrawSurfs += interactions;
    373 			break;
    374 	}
    375 }
    376 
    377 /*
    378 ===================
    379 RB_ShowIntensity
    380 
    381 Debugging tool to see how much dynamic range a scene is using.
    382 The greatest of the rgb values at each pixel will be used, with
    383 the resulting color shading from red at 0 to green at 128 to blue at 255
    384 ===================
    385 */
    386 static void RB_ShowIntensity() {
    387 	byte	*colorReadback;
    388 	int		i, j, c;
    389 
    390 	if ( !r_showIntensity.GetBool() ) {
    391 		return;
    392 	}
    393 
    394 	colorReadback = (byte *)R_StaticAlloc( renderSystem->GetWidth() * renderSystem->GetHeight() * 4, TAG_RENDER_TOOLS );
    395 	qglReadPixels( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), GL_RGBA, GL_UNSIGNED_BYTE, colorReadback );
    396 
    397 	c = renderSystem->GetWidth() * renderSystem->GetHeight() * 4;
    398 	for ( i = 0; i < c; i+=4 ) {
    399 		j = colorReadback[i];
    400 		if ( colorReadback[i+1] > j ) {
    401 			j = colorReadback[i+1];
    402 		}
    403 		if ( colorReadback[i+2] > j ) {
    404 			j = colorReadback[i+2];
    405 		}
    406 		if ( j < 128 ) {
    407 			colorReadback[i+0] = 2*(128-j);
    408 			colorReadback[i+1] = 2*j;
    409 			colorReadback[i+2] = 0;
    410 		} else {
    411 			colorReadback[i+0] = 0;
    412 			colorReadback[i+1] = 2*(255-j);
    413 			colorReadback[i+2] = 2*(j-128);
    414 		}
    415 	}
    416 
    417 	// draw it back to the screen
    418 	qglLoadIdentity();
    419 	qglMatrixMode( GL_PROJECTION );
    420 	GL_State( GLS_DEPTHFUNC_ALWAYS );
    421 	qglPushMatrix();
    422 	qglLoadIdentity(); 
    423     qglOrtho( 0, 1, 0, 1, -1, 1 );
    424 	qglRasterPos2f( 0, 0 );
    425 	qglPopMatrix();
    426 	GL_Color( 1, 1, 1 );
    427 	globalImages->BindNull();
    428 	qglMatrixMode( GL_MODELVIEW );
    429 
    430 	qglDrawPixels( renderSystem->GetWidth(), renderSystem->GetHeight(), GL_RGBA , GL_UNSIGNED_BYTE, colorReadback );
    431 
    432 	R_StaticFree( colorReadback );
    433 }
    434 
    435 
    436 /*
    437 ===================
    438 RB_ShowDepthBuffer
    439 
    440 Draw the depth buffer as colors
    441 ===================
    442 */
    443 static void RB_ShowDepthBuffer() {
    444 	void	*depthReadback;
    445 
    446 	if ( !r_showDepth.GetBool() ) {
    447 		return;
    448 	}
    449 
    450 	qglPushMatrix();
    451 	qglLoadIdentity();
    452 	qglMatrixMode( GL_PROJECTION );
    453 	qglPushMatrix();
    454 	qglLoadIdentity(); 
    455     qglOrtho( 0, 1, 0, 1, -1, 1 );
    456 	qglRasterPos2f( 0, 0 );
    457 	qglPopMatrix();
    458 	qglMatrixMode( GL_MODELVIEW );
    459 	qglPopMatrix();
    460 
    461 	GL_State( GLS_DEPTHFUNC_ALWAYS );
    462 	GL_Color( 1, 1, 1 );
    463 	globalImages->BindNull();
    464 
    465 	depthReadback = R_StaticAlloc( renderSystem->GetWidth() * renderSystem->GetHeight()*4, TAG_RENDER_TOOLS );
    466 	memset( depthReadback, 0, renderSystem->GetWidth() * renderSystem->GetHeight()*4 );
    467 
    468 	qglReadPixels( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight(), GL_DEPTH_COMPONENT , GL_FLOAT, depthReadback );
    469 
    470 #if 0
    471 	for ( i = 0; i < renderSystem->GetWidth() * renderSystem->GetHeight(); i++ ) {
    472 		((byte *)depthReadback)[i*4] = 
    473 		((byte *)depthReadback)[i*4+1] = 
    474 		((byte *)depthReadback)[i*4+2] = 255 * ((float *)depthReadback)[i];
    475 		((byte *)depthReadback)[i*4+3] = 1;
    476 	}
    477 #endif
    478 
    479 	qglDrawPixels( renderSystem->GetWidth(), renderSystem->GetHeight(), GL_RGBA , GL_UNSIGNED_BYTE, depthReadback );
    480 	R_StaticFree( depthReadback );
    481 }
    482 
    483 /*
    484 =================
    485 RB_ShowLightCount
    486 
    487 This is a debugging tool that will draw each surface with a color
    488 based on how many lights are effecting it
    489 =================
    490 */
    491 static void RB_ShowLightCount() {
    492 	int		i;
    493 	const drawSurf_t	*surf;
    494 	const viewLight_t	*vLight;
    495 
    496 	if ( !r_showLightCount.GetBool() ) {
    497 		return;
    498 	}
    499 
    500 	RB_SimpleWorldSetup();
    501 
    502 	GL_Clear( false, false, true, 0, 0.0f, 0.0f, 0.0f, 0.0f );
    503 
    504 	// optionally count everything through walls
    505 	if ( r_showLightCount.GetInteger() >= 2 ) {
    506 		GL_State( GLS_DEPTHFUNC_EQUAL | GLS_STENCIL_OP_FAIL_KEEP | GLS_STENCIL_OP_ZFAIL_INCR | GLS_STENCIL_OP_PASS_INCR );
    507 	} else {
    508 		GL_State( GLS_DEPTHFUNC_EQUAL | GLS_STENCIL_OP_FAIL_KEEP | GLS_STENCIL_OP_ZFAIL_KEEP | GLS_STENCIL_OP_PASS_INCR );
    509 	}
    510 
    511 	globalImages->defaultImage->Bind();
    512 
    513 	for ( vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next ) {
    514 		for ( i = 0; i < 2; i++ ) {
    515 			for ( surf = i ? vLight->localInteractions: vLight->globalInteractions; surf; surf = (drawSurf_t *)surf->nextOnLight ) {
    516 				RB_SimpleSurfaceSetup( surf );
    517 				RB_DrawElementsWithCounters( surf );
    518 			}
    519 		}
    520 	}
    521 
    522 	// display the results
    523 	R_ColorByStencilBuffer();
    524 
    525 	if ( r_showLightCount.GetInteger() > 2 ) {
    526 		RB_CountStencilBuffer();
    527 	}
    528 }
    529 
    530 /*
    531 ===============
    532 RB_SetWeaponDepthHack
    533 ===============
    534 */
    535 static void RB_SetWeaponDepthHack() {
    536 }
    537 
    538 /*
    539 ===============
    540 RB_SetModelDepthHack
    541 ===============
    542 */
    543 static void RB_SetModelDepthHack( float depth ) {
    544 }
    545 
    546 /*
    547 ===============
    548 RB_EnterWeaponDepthHack
    549 ===============
    550 */
    551 static void RB_EnterWeaponDepthHack() {
    552 	float	matrix[16];
    553 
    554 	memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) );
    555 
    556 	const float modelDepthHack = 0.25f;
    557 	matrix[2] *= modelDepthHack;
    558 	matrix[6] *= modelDepthHack;
    559 	matrix[10] *= modelDepthHack;
    560 	matrix[14] *= modelDepthHack;
    561 
    562 	qglMatrixMode( GL_PROJECTION );
    563 	qglLoadMatrixf( matrix );
    564 	qglMatrixMode( GL_MODELVIEW );
    565 }
    566 
    567 /*
    568 ===============
    569 RB_EnterModelDepthHack
    570 ===============
    571 */
    572 static void RB_EnterModelDepthHack( float depth ) {
    573 	float matrix[16];
    574 
    575 	memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) );
    576 
    577 	matrix[14] -= depth;
    578 
    579 	qglMatrixMode( GL_PROJECTION );
    580 	qglLoadMatrixf( matrix );
    581 	qglMatrixMode( GL_MODELVIEW );
    582 }
    583 
    584 /*
    585 ===============
    586 RB_LeaveDepthHack
    587 ===============
    588 */
    589 static void RB_LeaveDepthHack() {
    590 	qglMatrixMode( GL_PROJECTION );
    591 	qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
    592 	qglMatrixMode( GL_MODELVIEW );
    593 }
    594 
    595 /*
    596 =============
    597 RB_LoadMatrixWithBypass
    598 
    599 does a glLoadMatrixf after optionally applying the low-latency bypass matrix
    600 =============
    601 */
    602 static void RB_LoadMatrixWithBypass( const float m[16] ) {
    603 	glLoadMatrixf( m );
    604 }
    605 
    606 /*
    607 ====================
    608 RB_RenderDrawSurfListWithFunction
    609 
    610 The triangle functions can check backEnd.currentSpace != surf->space
    611 to see if they need to perform any new matrix setup.  The modelview
    612 matrix will already have been loaded, and backEnd.currentSpace will
    613 be updated after the triangle function completes.
    614 ====================
    615 */
    616 static void RB_RenderDrawSurfListWithFunction( drawSurf_t **drawSurfs, int numDrawSurfs, void (*triFunc_)( const drawSurf_t *) ) {
    617 	backEnd.currentSpace = NULL;
    618 
    619 	for ( int i = 0 ; i < numDrawSurfs ; i++ ) {
    620 		const drawSurf_t * drawSurf = drawSurfs[i];
    621 		if ( drawSurf == NULL ) {
    622 			continue;
    623 		}
    624 		assert( drawSurf->space != NULL );
    625 		if ( drawSurf->space != NULL ) {	// is it ever NULL?  Do we need to check?
    626 			// Set these values ahead of time so we don't have to reconstruct the matrices on the consoles
    627 			if ( drawSurf->space->weaponDepthHack ) {
    628 				RB_SetWeaponDepthHack();
    629 			}
    630 
    631 			if ( drawSurf->space->modelDepthHack != 0.0f ) {
    632 				RB_SetModelDepthHack( drawSurf->space->modelDepthHack );
    633 			}
    634 
    635 			// change the matrix if needed
    636 			if ( drawSurf->space != backEnd.currentSpace ) {
    637 				RB_LoadMatrixWithBypass( drawSurf->space->modelViewMatrix );
    638 			}
    639 
    640 			if ( drawSurf->space->weaponDepthHack ) {
    641 				RB_EnterWeaponDepthHack();
    642 			}
    643 
    644 			if ( drawSurf->space->modelDepthHack != 0.0f ) {
    645 				RB_EnterModelDepthHack( drawSurf->space->modelDepthHack );
    646 			}
    647 		}
    648 
    649 		// change the scissor if needed
    650 		if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) {
    651 			backEnd.currentScissor = drawSurf->scissorRect;
    652 			GL_Scissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, 
    653 				backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
    654 				backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
    655 				backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
    656 		}
    657 
    658 		// render it
    659 		triFunc_( drawSurf );
    660 
    661 		if ( drawSurf->space != NULL && ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) ) {
    662 			RB_LeaveDepthHack();
    663 		}
    664 
    665 		backEnd.currentSpace = drawSurf->space;
    666 	}
    667 }
    668 
    669 /*
    670 =================
    671 RB_ShowSilhouette
    672 
    673 Blacks out all edges, then adds color for each edge that a shadow
    674 plane extends from, allowing you to see doubled edges
    675 
    676 FIXME: not thread safe!
    677 =================
    678 */
    679 static void RB_ShowSilhouette() {
    680 	int		i;
    681 	const drawSurf_t	*surf;
    682 	const viewLight_t	*vLight;
    683 
    684 	if ( !r_showSilhouette.GetBool() ) {
    685 		return;
    686 	}
    687 
    688 	//
    689 	// clear all triangle edges to black
    690 	//
    691 	globalImages->BindNull();
    692 	qglDisable( GL_TEXTURE_2D );
    693 
    694 	GL_Color( 0, 0, 0 );
    695 
    696 	GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE );
    697 
    698 	GL_Cull( CT_TWO_SIDED );
    699 
    700 	RB_RenderDrawSurfListWithFunction( backEnd.viewDef->drawSurfs, backEnd.viewDef->numDrawSurfs, 
    701 		RB_DrawElementsWithCounters );
    702 
    703 
    704 	//
    705 	// now blend in edges that cast silhouettes
    706 	//
    707 	RB_SimpleWorldSetup();
    708 	GL_Color( 0.5, 0, 0 );
    709 	GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
    710 
    711 	for ( vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next ) {
    712 		for ( i = 0; i < 2; i++ ) {
    713 			for ( surf = i ? vLight->localShadows : vLight->globalShadows
    714 				; surf; surf = (drawSurf_t *)surf->nextOnLight ) {
    715 				RB_SimpleSurfaceSetup( surf );
    716 
    717 				const srfTriangles_t * tri = surf->frontEndGeo;
    718 
    719 				idVertexBuffer vertexBuffer;
    720 				if ( !vertexCache.GetVertexBuffer( tri->shadowCache, &vertexBuffer ) ) {
    721 					continue;
    722 				}
    723 
    724 				qglBindBufferARB( GL_ARRAY_BUFFER_ARB, (GLuint)vertexBuffer.GetAPIObject() );
    725 				int vertOffset = vertexBuffer.GetOffset();
    726 
    727 				qglVertexPointer( 3, GL_FLOAT, sizeof( idShadowVert ), (void *)vertOffset );
    728 				qglBegin( GL_LINES );
    729 
    730 				for ( int j = 0; j < tri->numIndexes; j+=3 ) {
    731 					int		i1 = tri->indexes[j+0];
    732 					int		i2 = tri->indexes[j+1];
    733 					int		i3 = tri->indexes[j+2];
    734 
    735 					if ( (i1 & 1) + (i2 & 1) + (i3 & 1) == 1 ) {
    736 						if ( (i1 & 1) + (i2 & 1) == 0 ) {
    737 							qglArrayElement( i1 );
    738 							qglArrayElement( i2 );
    739 						} else if ( (i1 & 1 ) + (i3 & 1) == 0 ) {
    740 							qglArrayElement( i1 );
    741 							qglArrayElement( i3 );
    742 						}
    743 					}
    744 				}
    745 				qglEnd();
    746 
    747 			}
    748 		}
    749 	}
    750 
    751 	GL_State( GLS_DEFAULT );
    752 	GL_Color( 1,1,1 );
    753 	GL_Cull( CT_FRONT_SIDED );
    754 }
    755 
    756 /*
    757 =====================
    758 RB_ShowTris
    759 
    760 Debugging tool
    761 =====================
    762 */
    763 static void RB_ShowTris( drawSurf_t **drawSurfs, int numDrawSurfs ) {
    764 
    765 	modelTrace_t mt;
    766 	idVec3 end;
    767 
    768 	if ( r_showTris.GetInteger() == 0 ) {
    769 		return;
    770 	}
    771 
    772 	float color[4] = { 1, 1, 1, 1 };
    773 
    774 	GL_PolygonOffset( -1.0f, -2.0f );
    775 	
    776 	switch ( r_showTris.GetInteger() ) {			
    777 		case 1: // only draw visible ones
    778 			GL_State( GLS_DEPTHMASK | GLS_ALPHAMASK | GLS_POLYMODE_LINE | GLS_POLYGON_OFFSET );
    779 			break;
    780 		case 2:	// draw all front facing
    781 		case 3: // draw all
    782 			GL_State( GLS_DEPTHMASK | GLS_ALPHAMASK | GLS_POLYMODE_LINE | GLS_POLYGON_OFFSET | GLS_DEPTHFUNC_ALWAYS );
    783 			break;
    784 		case 4: // only draw visible ones with blended lines
    785 			GL_State( GLS_DEPTHMASK | GLS_ALPHAMASK | GLS_POLYMODE_LINE | GLS_POLYGON_OFFSET | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
    786 			color[3] = 0.4f;
    787 			break;
    788 	}
    789 
    790 	if ( r_showTris.GetInteger() == 3 ) {
    791 		GL_Cull( CT_TWO_SIDED );
    792 	}
    793 
    794 	GL_Color( color );
    795 	renderProgManager.BindShader_Color();
    796 
    797 	RB_RenderDrawSurfListWithFunction( drawSurfs, numDrawSurfs, RB_DrawElementsWithCounters );
    798 
    799 	if ( r_showTris.GetInteger() == 3 ) {
    800 		GL_Cull( CT_FRONT_SIDED );
    801 	}
    802 }
    803 
    804 /*
    805 =====================
    806 RB_ShowSurfaceInfo
    807 
    808 Debugging tool
    809 =====================
    810 */
    811 static void RB_ShowSurfaceInfo( drawSurf_t **drawSurfs, int numDrawSurfs ) {
    812 	modelTrace_t mt;
    813 	idVec3 start, end;
    814 	
    815 	if ( !r_showSurfaceInfo.GetBool() ) {
    816 		return;
    817 	}
    818 
    819 	// start far enough away that we don't hit the player model
    820 	start = tr.primaryView->renderView.vieworg + tr.primaryView->renderView.viewaxis[0] * 16;
    821 	end = start + tr.primaryView->renderView.viewaxis[0] * 1000.0f;
    822 	if ( !tr.primaryWorld->Trace( mt, start, end, 0.0f, false ) ) {
    823 		return;
    824 	}
    825 
    826 	globalImages->BindNull();
    827 	qglDisable( GL_TEXTURE_2D );
    828 
    829 	GL_Color( 1, 1, 1 );
    830 
    831 	static float scale = -1;
    832 	static float bias = -2;
    833 
    834 	GL_PolygonOffset( scale, bias );
    835 	GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE | GLS_POLYGON_OFFSET );
    836 
    837 	idVec3	trans[3];
    838 	float	matrix[16];
    839 
    840 	// transform the object verts into global space
    841 	R_AxisToModelMatrix( mt.entity->axis, mt.entity->origin, matrix );
    842 
    843 	tr.primaryWorld->DrawText( mt.entity->hModel->Name(), mt.point + tr.primaryView->renderView.viewaxis[2] * 12,
    844 		0.35f, colorRed, tr.primaryView->renderView.viewaxis );
    845 	tr.primaryWorld->DrawText( mt.material->GetName(), mt.point, 
    846 		0.35f, colorBlue, tr.primaryView->renderView.viewaxis );
    847 }
    848 
    849 /*
    850 =====================
    851 RB_ShowViewEntitys
    852 
    853 Debugging tool
    854 =====================
    855 */
    856 static void RB_ShowViewEntitys( viewEntity_t *vModels ) {
    857 	if ( !r_showViewEntitys.GetBool() ) {
    858 		return;
    859 	}
    860 	if ( r_showViewEntitys.GetInteger() >= 2 ) {
    861 		common->Printf( "view entities: " );
    862 		for ( const viewEntity_t * vModel = vModels; vModel; vModel = vModel->next ) {
    863 			if ( vModel->entityDef->IsDirectlyVisible() ) {
    864 				common->Printf( "<%i> ", vModel->entityDef->index );
    865 			} else {
    866 				common->Printf( "%i ", vModel->entityDef->index );
    867 			}
    868 		}
    869 		common->Printf( "\n" );
    870 	}
    871 
    872 	globalImages->BindNull();
    873 
    874 	renderProgManager.BindShader_Color();
    875 
    876 	GL_Color( 1, 1, 1 );
    877 	GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE );
    878 	GL_Cull( CT_TWO_SIDED );
    879 
    880 	for ( const viewEntity_t * vModel = vModels; vModel; vModel = vModel->next ) {
    881 		idBounds	b;
    882 
    883 		qglLoadMatrixf( vModel->modelViewMatrix );
    884 
    885 		const idRenderEntityLocal * edef = vModel->entityDef;
    886 		if ( !edef ) {
    887 			continue;
    888 		}
    889 
    890 
    891 
    892 		// draw the model bounds in white if directly visible,
    893 		// or, blue if it is only-for-sahdow
    894 		idVec4	color;
    895 		if ( edef->IsDirectlyVisible() ) {
    896 			color.Set( 1, 1, 1, 1 );
    897 		} else {
    898 			color.Set( 0, 0, 1, 1 );
    899 		}
    900 		GL_Color( color[0], color[1], color[2] );
    901 		RB_DrawBounds( edef->localReferenceBounds );
    902 
    903 		// transform the upper bounds corner into global space
    904 		if ( r_showViewEntitys.GetInteger() >= 2 ) {
    905 			idVec3 corner;
    906 			R_LocalPointToGlobal( vModel->modelMatrix, edef->localReferenceBounds[1], corner );
    907 
    908 			tr.primaryWorld->DrawText( 
    909 				va( "%i:%s", edef->index, edef->parms.hModel->Name() ), 
    910 				corner,
    911 				0.25f, color, 
    912 				tr.primaryView->renderView.viewaxis );
    913 		}
    914 
    915 		// draw the actual bounds in yellow if different
    916 		if ( r_showViewEntitys.GetInteger() >= 3 ) {
    917 			GL_Color( 1, 1, 0 );
    918 			// FIXME: cannot instantiate a dynamic model from the renderer back-end
    919 			idRenderModel *model = R_EntityDefDynamicModel( vModel->entityDef );
    920 			if ( !model ) {
    921 				continue;	// particles won't instantiate without a current view
    922 			}
    923 			b = model->Bounds( &vModel->entityDef->parms );
    924 			if ( b != vModel->entityDef->localReferenceBounds ) {
    925 				RB_DrawBounds( b );
    926 			}
    927 		}
    928 	}
    929 }
    930 
    931 /*
    932 =====================
    933 RB_ShowTexturePolarity
    934 
    935 Shade triangle red if they have a positive texture area
    936 green if they have a negative texture area, or blue if degenerate area
    937 =====================
    938 */
    939 static void RB_ShowTexturePolarity( drawSurf_t **drawSurfs, int numDrawSurfs ) {
    940 	int		i, j;
    941 	drawSurf_t	*drawSurf;
    942 	const srfTriangles_t	*tri;
    943 
    944 	if ( !r_showTexturePolarity.GetBool() ) {
    945 		return;
    946 	}
    947 	globalImages->BindNull();
    948 
    949 	GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
    950 
    951 	GL_Color( 1, 1, 1 );
    952 
    953 	for ( i = 0; i < numDrawSurfs; i++ ) {
    954 		drawSurf = drawSurfs[i];
    955 		tri = drawSurf->frontEndGeo;
    956 		if ( !tri->verts ) {
    957 			continue;
    958 		}
    959 
    960 		RB_SimpleSurfaceSetup( drawSurf );
    961 
    962 		qglBegin( GL_TRIANGLES );
    963 		for ( j = 0; j < tri->numIndexes; j+=3 ) {
    964 			idDrawVert	*a, *b, *c;
    965 			float		d0[5], d1[5];
    966 			float		area;
    967 
    968 			a = tri->verts + tri->indexes[j];
    969 			b = tri->verts + tri->indexes[j+1];
    970 			c = tri->verts + tri->indexes[j+2];
    971 
    972 			const idVec2 aST = a->GetTexCoord();
    973 			const idVec2 bST = b->GetTexCoord();
    974 			const idVec2 cST = c->GetTexCoord();
    975 
    976 			d0[3] = bST[0] - aST[0];
    977 			d0[4] = bST[1] - aST[1];
    978 
    979 			d1[3] = cST[0] - aST[0];
    980 			d1[4] = cST[1] - aST[1];
    981 
    982 			area = d0[3] * d1[4] - d0[4] * d1[3];
    983 
    984 			if ( idMath::Fabs( area ) < 0.0001 ) {
    985 				GL_Color( 0, 0, 1, 0.5 );
    986 			} else  if ( area < 0 ) {
    987 				GL_Color( 1, 0, 0, 0.5 );
    988 			} else {
    989 				GL_Color( 0, 1, 0, 0.5 );
    990 			}
    991 			qglVertex3fv( a->xyz.ToFloatPtr() );
    992 			qglVertex3fv( b->xyz.ToFloatPtr() );
    993 			qglVertex3fv( c->xyz.ToFloatPtr() );
    994 		}
    995 		qglEnd();
    996 	}
    997 
    998 	GL_State( GLS_DEFAULT );
    999 }
   1000 
   1001 /*
   1002 =====================
   1003 RB_ShowUnsmoothedTangents
   1004 
   1005 Shade materials that are using unsmoothed tangents
   1006 =====================
   1007 */
   1008 static void RB_ShowUnsmoothedTangents( drawSurf_t **drawSurfs, int numDrawSurfs ) {
   1009 	int		i, j;
   1010 	drawSurf_t	*drawSurf;
   1011 	const srfTriangles_t	*tri;
   1012 
   1013 	if ( !r_showUnsmoothedTangents.GetBool() ) {
   1014 		return;
   1015 	}
   1016 	globalImages->BindNull();
   1017 
   1018 	GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
   1019 
   1020 	GL_Color( 0, 1, 0, 0.5 );
   1021 
   1022 	for ( i = 0; i < numDrawSurfs; i++ ) {
   1023 		drawSurf = drawSurfs[i];
   1024 
   1025 		if ( !drawSurf->material->UseUnsmoothedTangents() ) {
   1026 			continue;
   1027 		}
   1028 
   1029 		RB_SimpleSurfaceSetup( drawSurf );
   1030 
   1031 		tri = drawSurf->frontEndGeo;
   1032 		qglBegin( GL_TRIANGLES );
   1033 		for ( j = 0; j < tri->numIndexes; j+=3 ) {
   1034 			idDrawVert	*a, *b, *c;
   1035 
   1036 			a = tri->verts + tri->indexes[j];
   1037 			b = tri->verts + tri->indexes[j+1];
   1038 			c = tri->verts + tri->indexes[j+2];
   1039 
   1040 			qglVertex3fv( a->xyz.ToFloatPtr() );
   1041 			qglVertex3fv( b->xyz.ToFloatPtr() );
   1042 			qglVertex3fv( c->xyz.ToFloatPtr() );
   1043 		}
   1044 		qglEnd();
   1045 	}
   1046 
   1047 	GL_State( GLS_DEFAULT );
   1048 }
   1049 
   1050 /*
   1051 =====================
   1052 RB_ShowTangentSpace
   1053 
   1054 Shade a triangle by the RGB colors of its tangent space
   1055 1 = tangents[0]
   1056 2 = tangents[1]
   1057 3 = normal
   1058 =====================
   1059 */
   1060 static void RB_ShowTangentSpace( drawSurf_t **drawSurfs, int numDrawSurfs ) {
   1061 	int		i, j;
   1062 	drawSurf_t	*drawSurf;
   1063 	const srfTriangles_t	*tri;
   1064 
   1065 	if ( !r_showTangentSpace.GetInteger() ) {
   1066 		return;
   1067 	}
   1068 	globalImages->BindNull();
   1069 
   1070 	GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
   1071 
   1072 	for ( i = 0; i < numDrawSurfs; i++ ) {
   1073 		drawSurf = drawSurfs[i];
   1074 
   1075 		RB_SimpleSurfaceSetup( drawSurf );
   1076 
   1077 		tri = drawSurf->frontEndGeo;
   1078 		if ( !tri->verts ) {
   1079 			continue;
   1080 		}
   1081 		qglBegin( GL_TRIANGLES );
   1082 		for ( j = 0; j < tri->numIndexes; j++ ) {
   1083 			const idDrawVert *v;
   1084 
   1085 			v = &tri->verts[tri->indexes[j]];
   1086 
   1087 			if ( r_showTangentSpace.GetInteger() == 1 ) {
   1088 				const idVec3 vertexTangent = v->GetTangent();
   1089 				GL_Color( 0.5 + 0.5 * vertexTangent[0],  0.5 + 0.5 * vertexTangent[1],  
   1090 					0.5 + 0.5 * vertexTangent[2], 0.5 );
   1091 			} else if ( r_showTangentSpace.GetInteger() == 2 ) {
   1092 				const idVec3 vertexBiTangent = v->GetBiTangent();
   1093 				GL_Color( 0.5 + 0.5 *vertexBiTangent[0],  0.5 + 0.5 * vertexBiTangent[1],  
   1094 					0.5 + 0.5 * vertexBiTangent[2], 0.5 );
   1095 			} else {
   1096 				const idVec3 vertexNormal = v->GetNormal();
   1097 				GL_Color( 0.5 + 0.5 * vertexNormal[0],  0.5 + 0.5 * vertexNormal[1],  
   1098 					0.5 + 0.5 * vertexNormal[2], 0.5 );
   1099 			}
   1100 			qglVertex3fv( v->xyz.ToFloatPtr() );
   1101 		}
   1102 		qglEnd();
   1103 	}
   1104 
   1105 	GL_State( GLS_DEFAULT );
   1106 }
   1107 
   1108 /*
   1109 =====================
   1110 RB_ShowVertexColor
   1111 
   1112 Draw each triangle with the solid vertex colors
   1113 =====================
   1114 */
   1115 static void RB_ShowVertexColor( drawSurf_t **drawSurfs, int numDrawSurfs ) {
   1116 	int		i, j;
   1117 	drawSurf_t	*drawSurf;
   1118 	const srfTriangles_t	*tri;
   1119 
   1120 	if ( !r_showVertexColor.GetBool() ) {
   1121 		return;
   1122 	}
   1123 	globalImages->BindNull();
   1124 
   1125 	GL_State( GLS_DEPTHFUNC_LESS );
   1126 
   1127 	for ( i = 0; i < numDrawSurfs; i++ ) {
   1128 		drawSurf = drawSurfs[i];
   1129 
   1130 		RB_SimpleSurfaceSetup( drawSurf );
   1131 
   1132 		tri = drawSurf->frontEndGeo;
   1133 		if ( !tri->verts ) {
   1134 			continue;
   1135 		}
   1136 		qglBegin( GL_TRIANGLES );
   1137 		for ( j = 0; j < tri->numIndexes; j++ ) {
   1138 			const idDrawVert *v;
   1139 
   1140 			v = &tri->verts[tri->indexes[j]];
   1141 			qglColor4ubv( v->color );
   1142 			qglVertex3fv( v->xyz.ToFloatPtr() );
   1143 		}
   1144 		qglEnd();
   1145 	}
   1146 
   1147 	GL_State( GLS_DEFAULT );
   1148 }
   1149 
   1150 /*
   1151 =====================
   1152 RB_ShowNormals
   1153 
   1154 Debugging tool
   1155 =====================
   1156 */
   1157 static void RB_ShowNormals( drawSurf_t **drawSurfs, int numDrawSurfs ) {
   1158 	int			i, j;
   1159 	drawSurf_t	*drawSurf;
   1160 	idVec3		end;
   1161 	const srfTriangles_t	*tri;
   1162 	float		size;
   1163 	bool		showNumbers;
   1164 	idVec3		pos;
   1165 
   1166 	if ( r_showNormals.GetFloat() == 0.0f ) {
   1167 		return;
   1168 	}
   1169 
   1170 	globalImages->BindNull();
   1171 
   1172 	if ( !r_debugLineDepthTest.GetBool() ) {
   1173 		GL_State( GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS );
   1174 	} else {
   1175 		GL_State( GLS_POLYMODE_LINE );
   1176 	}
   1177 
   1178 	size = r_showNormals.GetFloat();
   1179 	if ( size < 0.0f ) {
   1180 		size = -size;
   1181 		showNumbers = true;
   1182 	} else {
   1183 		showNumbers = false;
   1184 	}
   1185 
   1186 	for ( i = 0; i < numDrawSurfs; i++ ) {
   1187 		drawSurf = drawSurfs[i];
   1188 
   1189 		RB_SimpleSurfaceSetup( drawSurf );
   1190 
   1191 		tri = drawSurf->frontEndGeo;
   1192 		if ( !tri->verts ) {
   1193 			continue;
   1194 		}
   1195 
   1196 		qglBegin( GL_LINES );
   1197 		for ( j = 0; j < tri->numVerts; j++ ) {
   1198 			const idVec3 normal = tri->verts[j].GetNormal();
   1199 			const idVec3 tangent = tri->verts[j].GetTangent();
   1200 			const idVec3 bitangent = tri->verts[j].GetBiTangent();
   1201 			GL_Color( 0, 0, 1 );
   1202 			qglVertex3fv( tri->verts[j].xyz.ToFloatPtr() );
   1203 			VectorMA( tri->verts[j].xyz, size, normal, end );
   1204 			qglVertex3fv( end.ToFloatPtr() );
   1205 
   1206 			GL_Color( 1, 0, 0 );
   1207 			qglVertex3fv( tri->verts[j].xyz.ToFloatPtr() );
   1208 			VectorMA( tri->verts[j].xyz, size, tangent, end );
   1209 			qglVertex3fv( end.ToFloatPtr() );
   1210 
   1211 			GL_Color( 0, 1, 0 );
   1212 			qglVertex3fv( tri->verts[j].xyz.ToFloatPtr() );
   1213 			VectorMA( tri->verts[j].xyz, size, bitangent, end );
   1214 			qglVertex3fv( end.ToFloatPtr() );
   1215 		}
   1216 		qglEnd();
   1217 	}
   1218 
   1219 	if ( showNumbers ) {
   1220 		RB_SimpleWorldSetup();
   1221 		for ( i = 0; i < numDrawSurfs; i++ ) {
   1222 			drawSurf = drawSurfs[i];
   1223 			tri = drawSurf->frontEndGeo;
   1224 			if ( !tri->verts ) {
   1225 				continue;
   1226 			}
   1227 			
   1228 			for ( j = 0; j < tri->numVerts; j++ ) {
   1229 				const idVec3 normal = tri->verts[j].GetNormal();
   1230 				const idVec3 tangent = tri->verts[j].GetTangent();
   1231 				R_LocalPointToGlobal( drawSurf->space->modelMatrix, tri->verts[j].xyz + tangent + normal * 0.2f, pos );
   1232 				RB_DrawText( va( "%d", j ), pos, 0.01f, colorWhite, backEnd.viewDef->renderView.viewaxis, 1 );
   1233 			}
   1234 
   1235 			for ( j = 0; j < tri->numIndexes; j += 3 ) {
   1236 				const idVec3 normal = tri->verts[ tri->indexes[ j + 0 ] ].GetNormal();
   1237 				R_LocalPointToGlobal( drawSurf->space->modelMatrix, ( tri->verts[ tri->indexes[ j + 0 ] ].xyz + tri->verts[ tri->indexes[ j + 1 ] ].xyz + tri->verts[ tri->indexes[ j + 2 ] ].xyz ) * ( 1.0f / 3.0f ) + normal * 0.2f, pos );
   1238 				RB_DrawText( va( "%d", j / 3 ), pos, 0.01f, colorCyan, backEnd.viewDef->renderView.viewaxis, 1 );
   1239 			}
   1240 		}
   1241 	}
   1242 }
   1243 
   1244 #if 0 // compiler warning
   1245 
   1246 /*
   1247 =====================
   1248 RB_ShowNormals
   1249 
   1250 Debugging tool
   1251 =====================
   1252 */
   1253 static void RB_AltShowNormals( drawSurf_t **drawSurfs, int numDrawSurfs ) {
   1254 	if ( r_showNormals.GetFloat() == 0.0f ) {
   1255 		return;
   1256 	}
   1257 
   1258 	globalImages->BindNull();
   1259 
   1260 	GL_State( GLS_DEPTHFUNC_ALWAYS );
   1261 
   1262 	for ( int i = 0; i < numDrawSurfs; i++ ) {
   1263 		drawSurf_t * drawSurf = drawSurfs[i];
   1264 
   1265 		RB_SimpleSurfaceSetup( drawSurf );
   1266 
   1267 		const srfTriangles_t * tri = drawSurf->geo;
   1268 
   1269 		qglBegin( GL_LINES );
   1270 		for ( int j = 0; j < tri->numIndexes; j += 3 ) {
   1271 			const idDrawVert *v[3] = {
   1272 				&tri->verts[tri->indexes[j+0]],
   1273 				&tri->verts[tri->indexes[j+1]],
   1274 				&tri->verts[tri->indexes[j+2]]
   1275 			}
   1276 
   1277 			const idPlane plane( v[0]->xyz, v[1]->xyz, v[2]->xyz );
   1278 
   1279 			// make the midpoint slightly above the triangle
   1280 			const idVec3 mid = ( v[0]->xyz + v[1]->xyz + v[2]->xyz ) * ( 1.0f / 3.0f ) + 0.1f * plane.Normal();
   1281 
   1282 			for ( int k = 0; k < 3; k++ ) {
   1283 				const idVec3 pos = ( mid + v[k]->xyz * 3.0f ) * 0.25f;
   1284 				idVec3 end;
   1285 
   1286 				GL_Color( 0, 0, 1 );
   1287 				qglVertex3fv( pos.ToFloatPtr() );
   1288 				VectorMA( pos, r_showNormals.GetFloat(), v[k]->normal, end );
   1289 				qglVertex3fv( end.ToFloatPtr() );
   1290 
   1291 				GL_Color( 1, 0, 0 );
   1292 				qglVertex3fv( pos.ToFloatPtr() );
   1293 				VectorMA( pos, r_showNormals.GetFloat(), v[k]->tangents[0], end );
   1294 				qglVertex3fv( end.ToFloatPtr() );
   1295 
   1296 				GL_Color( 0, 1, 0 );
   1297 				qglVertex3fv( pos.ToFloatPtr() );
   1298 				VectorMA( pos, r_showNormals.GetFloat(), v[k]->tangents[1], end );
   1299 				qglVertex3fv( end.ToFloatPtr() );
   1300 
   1301 				GL_Color( 1, 1, 1 );
   1302 				qglVertex3fv( pos.ToFloatPtr() );
   1303 				qglVertex3fv( v[k]->xyz.ToFloatPtr() );
   1304 			}
   1305 		}
   1306 		qglEnd();
   1307 	}
   1308 }
   1309 
   1310 #endif
   1311 
   1312 /*
   1313 =====================
   1314 RB_ShowTextureVectors
   1315 
   1316 Draw texture vectors in the center of each triangle
   1317 =====================
   1318 */
   1319 static void RB_ShowTextureVectors( drawSurf_t **drawSurfs, int numDrawSurfs ) {
   1320 	if ( r_showTextureVectors.GetFloat() == 0.0f ) {
   1321 		return;
   1322 	}
   1323 
   1324 	GL_State( GLS_DEPTHFUNC_LESS );
   1325 
   1326 	globalImages->BindNull();
   1327 
   1328 	for ( int i = 0; i < numDrawSurfs; i++ ) {
   1329 		drawSurf_t * drawSurf = drawSurfs[i];
   1330 
   1331 		const srfTriangles_t * tri = drawSurf->frontEndGeo;
   1332 
   1333 		if ( tri->verts == NULL ) {
   1334 			continue;
   1335 		}
   1336 
   1337 		RB_SimpleSurfaceSetup( drawSurf );
   1338 
   1339 		// draw non-shared edges in yellow
   1340 		qglBegin( GL_LINES );
   1341 
   1342 		for ( int j = 0; j < tri->numIndexes; j+= 3 ) {
   1343 			float d0[5], d1[5];
   1344 			idVec3 temp;
   1345 			idVec3 tangents[2];
   1346 
   1347 			const idDrawVert *a = &tri->verts[tri->indexes[j+0]];
   1348 			const idDrawVert *b = &tri->verts[tri->indexes[j+1]];
   1349 			const idDrawVert *c = &tri->verts[tri->indexes[j+2]];
   1350 
   1351 			const idPlane plane( a->xyz, b->xyz, c->xyz );
   1352 
   1353 			// make the midpoint slightly above the triangle
   1354 			const idVec3 mid = ( a->xyz + b->xyz + c->xyz ) * ( 1.0f / 3.0f ) + 0.1f * plane.Normal();
   1355 
   1356 			// calculate the texture vectors
   1357 			const idVec2 aST = a->GetTexCoord();
   1358 			const idVec2 bST = b->GetTexCoord();
   1359 			const idVec2 cST = c->GetTexCoord();
   1360 
   1361 			d0[0] = b->xyz[0] - a->xyz[0];
   1362 			d0[1] = b->xyz[1] - a->xyz[1];
   1363 			d0[2] = b->xyz[2] - a->xyz[2];
   1364 			d0[3] = bST[0] - aST[0];
   1365 			d0[4] = bST[1] - aST[1];
   1366 
   1367 			d1[0] = c->xyz[0] - a->xyz[0];
   1368 			d1[1] = c->xyz[1] - a->xyz[1];
   1369 			d1[2] = c->xyz[2] - a->xyz[2];
   1370 			d1[3] = cST[0] - aST[0];
   1371 			d1[4] = cST[1] - aST[1];
   1372 
   1373 			const float area = d0[3] * d1[4] - d0[4] * d1[3];
   1374 			if ( area == 0 ) {
   1375 				continue;
   1376 			}
   1377 			const float inva = 1.0f / area;
   1378 
   1379 			temp[0] = (d0[0] * d1[4] - d0[4] * d1[0]) * inva;
   1380 			temp[1] = (d0[1] * d1[4] - d0[4] * d1[1]) * inva;
   1381 			temp[2] = (d0[2] * d1[4] - d0[4] * d1[2]) * inva;
   1382 			temp.Normalize();
   1383 			tangents[0] = temp;
   1384         
   1385 			temp[0] = (d0[3] * d1[0] - d0[0] * d1[3]) * inva;
   1386 			temp[1] = (d0[3] * d1[1] - d0[1] * d1[3]) * inva;
   1387 			temp[2] = (d0[3] * d1[2] - d0[2] * d1[3]) * inva;
   1388 			temp.Normalize();
   1389 			tangents[1] = temp;
   1390 
   1391 			// draw the tangents
   1392 			tangents[0] = mid + tangents[0] * r_showTextureVectors.GetFloat();
   1393 			tangents[1] = mid + tangents[1] * r_showTextureVectors.GetFloat();
   1394 
   1395 			GL_Color( 1, 0, 0 );
   1396 			qglVertex3fv( mid.ToFloatPtr() );
   1397 			qglVertex3fv( tangents[0].ToFloatPtr() );
   1398 
   1399 			GL_Color( 0, 1, 0 );
   1400 			qglVertex3fv( mid.ToFloatPtr() );
   1401 			qglVertex3fv( tangents[1].ToFloatPtr() );
   1402 		}
   1403 
   1404 		qglEnd();
   1405 	}
   1406 }
   1407 
   1408 /*
   1409 =====================
   1410 RB_ShowDominantTris
   1411 
   1412 Draw lines from each vertex to the dominant triangle center
   1413 =====================
   1414 */
   1415 static void RB_ShowDominantTris( drawSurf_t **drawSurfs, int numDrawSurfs ) {
   1416 	int			i, j;
   1417 	drawSurf_t	*drawSurf;
   1418 	const srfTriangles_t	*tri;
   1419 
   1420 	if ( !r_showDominantTri.GetBool() ) {
   1421 		return;
   1422 	}
   1423 
   1424 	GL_State( GLS_DEPTHFUNC_LESS );
   1425 
   1426 	GL_PolygonOffset( -1, -2 );
   1427 	qglEnable( GL_POLYGON_OFFSET_LINE );
   1428 
   1429 	globalImages->BindNull();
   1430 
   1431 	for ( i = 0; i < numDrawSurfs; i++ ) {
   1432 		drawSurf = drawSurfs[i];
   1433 
   1434 		tri = drawSurf->frontEndGeo;
   1435 
   1436 		if ( !tri->verts ) {
   1437 			continue;
   1438 		}
   1439 		if ( !tri->dominantTris ) {
   1440 			continue;
   1441 		}
   1442 		RB_SimpleSurfaceSetup( drawSurf );
   1443 
   1444 		GL_Color( 1, 1, 0 );
   1445 		qglBegin( GL_LINES );
   1446 
   1447 		for ( j = 0; j < tri->numVerts; j++ ) {
   1448 			const idDrawVert *a, *b, *c;
   1449 			idVec3		mid;
   1450 
   1451 			// find the midpoint of the dominant tri
   1452 
   1453 			a = &tri->verts[j];
   1454 			b = &tri->verts[tri->dominantTris[j].v2];
   1455 			c = &tri->verts[tri->dominantTris[j].v3];
   1456 
   1457 			mid = ( a->xyz + b->xyz + c->xyz ) * ( 1.0f / 3.0f );
   1458 
   1459 			qglVertex3fv( mid.ToFloatPtr() );
   1460 			qglVertex3fv( a->xyz.ToFloatPtr() );
   1461 		}
   1462 
   1463 		qglEnd();
   1464 	}
   1465 	qglDisable( GL_POLYGON_OFFSET_LINE );
   1466 }
   1467 
   1468 /*
   1469 =====================
   1470 RB_ShowEdges
   1471 
   1472 Debugging tool
   1473 =====================
   1474 */
   1475 static void RB_ShowEdges( drawSurf_t **drawSurfs, int numDrawSurfs ) {
   1476 	int			i, j, k, m, n, o;
   1477 	drawSurf_t	*drawSurf;
   1478 	const srfTriangles_t	*tri;
   1479 	const silEdge_t			*edge;
   1480 	int			danglePlane;
   1481 
   1482 	if ( !r_showEdges.GetBool() ) {
   1483 		return;
   1484 	}
   1485 
   1486 	globalImages->BindNull();
   1487 
   1488 	GL_State( GLS_DEPTHFUNC_ALWAYS );
   1489 
   1490 	for ( i = 0; i < numDrawSurfs; i++ ) {
   1491 		drawSurf = drawSurfs[i];
   1492 
   1493 		tri = drawSurf->frontEndGeo;
   1494 
   1495 		idDrawVert *ac = (idDrawVert *)tri->verts;
   1496 		if ( !ac ) {
   1497 			continue;
   1498 		}
   1499 
   1500 		RB_SimpleSurfaceSetup( drawSurf );
   1501 
   1502 		// draw non-shared edges in yellow
   1503 		GL_Color( 1, 1, 0 );
   1504 		qglBegin( GL_LINES );
   1505 
   1506 		for ( j = 0; j < tri->numIndexes; j+= 3 ) {
   1507 			for ( k = 0; k < 3; k++ ) {
   1508 				int		l, i1, i2;
   1509 				l = ( k == 2 ) ? 0 : k + 1;
   1510 				i1 = tri->indexes[j+k];
   1511 				i2 = tri->indexes[j+l];
   1512 
   1513 				// if these are used backwards, the edge is shared
   1514 				for ( m = 0; m < tri->numIndexes; m += 3 ) {
   1515 					for ( n = 0; n < 3; n++ ) {
   1516 						o = ( n == 2 ) ? 0 : n + 1;
   1517 						if ( tri->indexes[m+n] == i2 && tri->indexes[m+o] == i1 ) {
   1518 							break;
   1519 						}
   1520 					}
   1521 					if ( n != 3 ) {
   1522 						break;
   1523 					}
   1524 				}
   1525 
   1526 				// if we didn't find a backwards listing, draw it in yellow
   1527 				if ( m == tri->numIndexes ) {
   1528 					qglVertex3fv( ac[ i1 ].xyz.ToFloatPtr() );
   1529 					qglVertex3fv( ac[ i2 ].xyz.ToFloatPtr() );
   1530 				}
   1531 
   1532 			}
   1533 		}
   1534 
   1535 		qglEnd();
   1536 
   1537 		// draw dangling sil edges in red
   1538 		if ( !tri->silEdges ) {
   1539 			continue;
   1540 		}
   1541 
   1542 		// the plane number after all real planes
   1543 		// is the dangling edge
   1544 		danglePlane = tri->numIndexes / 3;
   1545 
   1546 		GL_Color( 1, 0, 0 );
   1547 
   1548 		qglBegin( GL_LINES );
   1549 		for ( j = 0; j < tri->numSilEdges; j++ ) {
   1550 			edge = tri->silEdges + j;
   1551 
   1552 			if ( edge->p1 != danglePlane && edge->p2 != danglePlane ) {
   1553 				continue;
   1554 			}
   1555 
   1556 			qglVertex3fv( ac[ edge->v1 ].xyz.ToFloatPtr() );
   1557 			qglVertex3fv( ac[ edge->v2 ].xyz.ToFloatPtr() );
   1558 		}
   1559 		qglEnd();
   1560 	}
   1561 }
   1562 
   1563 /*
   1564 ==============
   1565 RB_ShowLights
   1566 
   1567 Visualize all light volumes used in the current scene
   1568 r_showLights 1	: just print volumes numbers, highlighting ones covering the view
   1569 r_showLights 2	: also draw planes of each volume
   1570 r_showLights 3	: also draw edges of each volume
   1571 ==============
   1572 */
   1573 static void RB_ShowLights() {
   1574 	if ( !r_showLights.GetInteger() ) {
   1575 		return;
   1576 	}
   1577 
   1578 	GL_State( GLS_DEFAULT );
   1579 
   1580 	// we use the 'vLight->invProjectMVPMatrix'
   1581 	qglMatrixMode( GL_PROJECTION );
   1582 	qglLoadIdentity(); 
   1583 
   1584 	globalImages->BindNull();
   1585 
   1586 	renderProgManager.BindShader_Color();
   1587 
   1588 	GL_Cull( CT_TWO_SIDED );
   1589 
   1590 	common->Printf( "volumes: " );	// FIXME: not in back end!
   1591 
   1592 	int count = 0;
   1593 	for ( viewLight_t * vLight = backEnd.viewDef->viewLights; vLight != NULL; vLight = vLight->next ) {
   1594 		count++;
   1595 
   1596 		// depth buffered planes
   1597 		if ( r_showLights.GetInteger() >= 2 ) {
   1598 			GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK );
   1599 			GL_Color( 0.0f, 0.0f, 1.0f, 0.25f );
   1600 			idRenderMatrix invProjectMVPMatrix;
   1601 			idRenderMatrix::Multiply( backEnd.viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix );
   1602 			RB_SetMVP( invProjectMVPMatrix );
   1603 			RB_DrawElementsWithCounters( &backEnd.zeroOneCubeSurface );
   1604 		}
   1605 
   1606 		// non-hidden lines
   1607 		if ( r_showLights.GetInteger() >= 3 ) {
   1608 			GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE | GLS_DEPTHMASK  );
   1609 			GL_Color( 1.0f, 1.0f, 1.0f );
   1610 			idRenderMatrix invProjectMVPMatrix;
   1611 			idRenderMatrix::Multiply( backEnd.viewDef->worldSpace.mvp, vLight->inverseBaseLightProject, invProjectMVPMatrix );
   1612 			RB_SetMVP( invProjectMVPMatrix );
   1613 			RB_DrawElementsWithCounters( &backEnd.zeroOneCubeSurface );
   1614 		}
   1615 
   1616 		common->Printf( "%i ", vLight->lightDef->index );
   1617 	}
   1618 
   1619 	common->Printf( " = %i total\n", count );
   1620 
   1621 	// set back the default projection matrix
   1622 	qglMatrixMode( GL_PROJECTION );
   1623 	qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
   1624 	qglMatrixMode( GL_MODELVIEW );
   1625 	qglLoadIdentity();
   1626 }
   1627 
   1628 /*
   1629 =====================
   1630 RB_ShowPortals
   1631 
   1632 Debugging tool, won't work correctly with SMP or when mirrors are present
   1633 =====================
   1634 */
   1635 static void RB_ShowPortals() {
   1636 	if ( !r_showPortals.GetBool() ) {
   1637 		return;
   1638 	}
   1639 
   1640 	// all portals are expressed in world coordinates
   1641 	RB_SimpleWorldSetup();
   1642 
   1643 	globalImages->BindNull();
   1644 	renderProgManager.BindShader_Color();
   1645 	GL_State( GLS_DEPTHFUNC_ALWAYS );
   1646 
   1647 	((idRenderWorldLocal *)backEnd.viewDef->renderWorld)->ShowPortals();
   1648 }
   1649 
   1650 /*
   1651 ================
   1652 RB_ClearDebugText
   1653 ================
   1654 */
   1655 void RB_ClearDebugText( int time ) {
   1656 	int			i;
   1657 	int			num;
   1658 	debugText_t	*text;
   1659 
   1660 	rb_debugTextTime = time;
   1661 
   1662 	if ( !time ) {
   1663 		// free up our strings
   1664 		text = rb_debugText;
   1665 		for ( i = 0; i < MAX_DEBUG_TEXT; i++, text++ ) {
   1666 			text->text.Clear();
   1667 		}
   1668 		rb_numDebugText = 0;
   1669 		return;
   1670 	}
   1671 
   1672 	// copy any text that still needs to be drawn
   1673 	num	= 0;
   1674 	text = rb_debugText;
   1675 	for ( i = 0; i < rb_numDebugText; i++, text++ ) {
   1676 		if ( text->lifeTime > time ) {
   1677 			if ( num != i ) {
   1678 				rb_debugText[ num ] = *text;
   1679 			}
   1680 			num++;
   1681 		}
   1682 	}
   1683 	rb_numDebugText = num;
   1684 }
   1685 
   1686 /*
   1687 ================
   1688 RB_AddDebugText
   1689 ================
   1690 */
   1691 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 ) {
   1692 	debugText_t *debugText;
   1693 
   1694 	if ( rb_numDebugText < MAX_DEBUG_TEXT ) {
   1695 		debugText = &rb_debugText[ rb_numDebugText++ ];
   1696 		debugText->text			= text;
   1697 		debugText->origin		= origin;
   1698 		debugText->scale		= scale;
   1699 		debugText->color		= color;
   1700 		debugText->viewAxis		= viewAxis;
   1701 		debugText->align		= align;
   1702 		debugText->lifeTime		= rb_debugTextTime + lifetime;
   1703 		debugText->depthTest	= depthTest;
   1704 	}
   1705 }
   1706 
   1707 /*
   1708 ================
   1709 RB_DrawTextLength
   1710 
   1711   returns the length of the given text
   1712 ================
   1713 */
   1714 float RB_DrawTextLength( const char *text, float scale, int len ) {
   1715 	int i, num, index, charIndex;
   1716 	float spacing, textLen = 0.0f;
   1717 
   1718 	if ( text && *text ) {
   1719 		if ( !len ) {
   1720 			len = strlen(text);
   1721 		}
   1722 		for ( i = 0; i < len; i++ ) {
   1723 			charIndex = text[i] - 32;
   1724 			if ( charIndex < 0 || charIndex > NUM_SIMPLEX_CHARS ) {
   1725 				continue;
   1726 			}
   1727 			num = simplex[charIndex][0] * 2;
   1728 			spacing = simplex[charIndex][1];
   1729 			index = 2;
   1730 
   1731 			while( index - 2 < num ) {   
   1732 				if ( simplex[charIndex][index] < 0) {  
   1733 					index++;
   1734 					continue; 
   1735 				} 
   1736 				index += 2;
   1737 				if ( simplex[charIndex][index] < 0) {  
   1738 					index++;
   1739 					continue; 
   1740 				} 
   1741 			}   
   1742 			textLen += spacing * scale;  
   1743 		}
   1744 	}
   1745 	return textLen;
   1746 }
   1747 
   1748 /*
   1749 ================
   1750 RB_DrawText
   1751 
   1752   oriented on the viewaxis
   1753   align can be 0-left, 1-center (default), 2-right
   1754 ================
   1755 */
   1756 static void RB_DrawText( const char *text, const idVec3 &origin, float scale, const idVec4 &color, const idMat3 &viewAxis, const int align ) {
   1757 	renderProgManager.BindShader_Color();
   1758 
   1759 
   1760 
   1761 	int i, j, len, num, index, charIndex, line;
   1762 	float textLen = 1.0f, spacing = 1.0f;
   1763 	idVec3 org, p1, p2;
   1764 
   1765 	if ( text && *text ) {
   1766 		qglBegin( GL_LINES );
   1767 		qglColor3fv( color.ToFloatPtr() );
   1768 
   1769 		if ( text[0] == '\n' ) {
   1770 			line = 1;
   1771 		} else {
   1772 			line = 0;
   1773 		}
   1774 
   1775 		len = strlen( text );
   1776 		for ( i = 0; i < len; i++ ) {
   1777 
   1778 			if ( i == 0 || text[i] == '\n' ) {
   1779 				org = origin - viewAxis[2] * ( line * 36.0f * scale );
   1780 				if ( align != 0 ) {
   1781 					for ( j = 1; i+j <= len; j++ ) {
   1782 						if ( i+j == len || text[i+j] == '\n' ) {
   1783 							textLen = RB_DrawTextLength( text+i, scale, j );
   1784 							break;
   1785 						}
   1786 					}
   1787 					if ( align == 2 ) {
   1788 						// right
   1789 						org += viewAxis[1] * textLen;
   1790 					} else {
   1791 						// center
   1792 						org += viewAxis[1] * ( textLen * 0.5f );
   1793 					}
   1794 				}
   1795 				line++;
   1796 			}
   1797 
   1798 			charIndex = text[i] - 32;
   1799 			if ( charIndex < 0 || charIndex > NUM_SIMPLEX_CHARS ) {
   1800 				continue;
   1801 			}
   1802 			num = simplex[charIndex][0] * 2;
   1803 			spacing = simplex[charIndex][1];
   1804 			index = 2;
   1805 
   1806 			while( index - 2 < num ) {
   1807 				if ( simplex[charIndex][index] < 0) {  
   1808 					index++;
   1809 					continue; 
   1810 				}
   1811 				p1 = org + scale * simplex[charIndex][index] * -viewAxis[1] + scale * simplex[charIndex][index+1] * viewAxis[2];
   1812 				index += 2;
   1813 				if ( simplex[charIndex][index] < 0) {
   1814 					index++;
   1815 					continue;
   1816 				}
   1817 				p2 = org + scale * simplex[charIndex][index] * -viewAxis[1] + scale * simplex[charIndex][index+1] * viewAxis[2];
   1818 
   1819 				qglVertex3fv( p1.ToFloatPtr() );
   1820 				qglVertex3fv( p2.ToFloatPtr() );
   1821 			}
   1822 			org -= viewAxis[1] * ( spacing * scale );
   1823 		}
   1824 
   1825 		qglEnd();
   1826 	}
   1827 }
   1828 
   1829 /*
   1830 ================
   1831 RB_ShowDebugText
   1832 ================
   1833 */
   1834 void RB_ShowDebugText() {
   1835 	int			i;
   1836 	int			width;
   1837 	debugText_t	*text;
   1838 
   1839 	if ( !rb_numDebugText ) {
   1840 		return;
   1841 	}
   1842 
   1843 	// all lines are expressed in world coordinates
   1844 	RB_SimpleWorldSetup();
   1845 
   1846 	globalImages->BindNull();
   1847 
   1848 	width = r_debugLineWidth.GetInteger();
   1849 	if ( width < 1 ) {
   1850 		width = 1;
   1851 	} else if ( width > 10 ) {
   1852 		width = 10;
   1853 	}
   1854 
   1855 	// draw lines
   1856 	qglLineWidth( width );
   1857 
   1858 
   1859 	if ( !r_debugLineDepthTest.GetBool() ) {
   1860 		GL_State( GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS );
   1861 	} else {
   1862 		GL_State( GLS_POLYMODE_LINE );
   1863 	}
   1864 
   1865 	text = rb_debugText;
   1866 	for ( i = 0; i < rb_numDebugText; i++, text++ ) {
   1867 		if ( !text->depthTest ) {
   1868 			RB_DrawText( text->text, text->origin, text->scale, text->color, text->viewAxis, text->align );
   1869 		}
   1870 	}
   1871 
   1872 	if ( !r_debugLineDepthTest.GetBool() ) {
   1873 		GL_State( GLS_POLYMODE_LINE );
   1874 	}
   1875 
   1876 	text = rb_debugText;
   1877 	for ( i = 0; i < rb_numDebugText; i++, text++ ) {
   1878 		if ( text->depthTest ) {
   1879 			RB_DrawText( text->text, text->origin, text->scale, text->color, text->viewAxis, text->align );
   1880 		}
   1881 	}
   1882 
   1883 	qglLineWidth( 1 );
   1884 }
   1885 
   1886 /*
   1887 ================
   1888 RB_ClearDebugLines
   1889 ================
   1890 */
   1891 void RB_ClearDebugLines( int time ) {
   1892 	int			i;
   1893 	int			num;
   1894 	debugLine_t	*line;
   1895 
   1896 	rb_debugLineTime = time;
   1897 
   1898 	if ( !time ) {
   1899 		rb_numDebugLines = 0;
   1900 		return;
   1901 	}
   1902 
   1903 	// copy any lines that still need to be drawn
   1904 	num	= 0;
   1905 	line = rb_debugLines;
   1906 	for ( i = 0; i < rb_numDebugLines; i++, line++ ) {
   1907 		if ( line->lifeTime > time ) {
   1908 			if ( num != i ) {
   1909 				rb_debugLines[ num ] = *line;
   1910 			}
   1911 			num++;
   1912 		}
   1913 	}
   1914 	rb_numDebugLines = num;
   1915 }
   1916 
   1917 /*
   1918 ================
   1919 RB_AddDebugLine
   1920 ================
   1921 */
   1922 void RB_AddDebugLine( const idVec4 &color, const idVec3 &start, const idVec3 &end, const int lifeTime, const bool depthTest ) {
   1923 	debugLine_t *line;
   1924 
   1925 	if ( rb_numDebugLines < MAX_DEBUG_LINES ) {
   1926 		line = &rb_debugLines[ rb_numDebugLines++ ];
   1927 		line->rgb		= color;
   1928 		line->start		= start;
   1929 		line->end		= end;
   1930 		line->depthTest = depthTest;
   1931 		line->lifeTime	= rb_debugLineTime + lifeTime;
   1932 	}
   1933 }
   1934 
   1935 /*
   1936 ================
   1937 RB_ShowDebugLines
   1938 ================
   1939 */
   1940 void RB_ShowDebugLines() {
   1941 	int			i;
   1942 	int			width;
   1943 	debugLine_t	*line;
   1944 
   1945 	if ( !rb_numDebugLines ) {
   1946 		return;
   1947 	}
   1948 
   1949 	// all lines are expressed in world coordinates
   1950 	RB_SimpleWorldSetup();
   1951 
   1952 	globalImages->BindNull();
   1953 
   1954 	width = r_debugLineWidth.GetInteger();
   1955 	if ( width < 1 ) {
   1956 		width = 1;
   1957 	} else if ( width > 10 ) {
   1958 		width = 10;
   1959 	}
   1960 
   1961 	// draw lines
   1962 	qglLineWidth( width );
   1963 
   1964 	if ( !r_debugLineDepthTest.GetBool() ) {
   1965 		GL_State( GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS );
   1966 	} else {
   1967 		GL_State( GLS_POLYMODE_LINE );
   1968 	}
   1969 
   1970 	qglBegin( GL_LINES );
   1971 
   1972 	line = rb_debugLines;
   1973 	for ( i = 0; i < rb_numDebugLines; i++, line++ ) {
   1974 		if ( !line->depthTest ) {
   1975 			qglColor3fv( line->rgb.ToFloatPtr() );
   1976 			qglVertex3fv( line->start.ToFloatPtr() );
   1977 			qglVertex3fv( line->end.ToFloatPtr() );
   1978 		}
   1979 	}
   1980 	qglEnd();
   1981 
   1982 	if ( !r_debugLineDepthTest.GetBool() ) {
   1983 		GL_State( GLS_POLYMODE_LINE );
   1984 	}
   1985 
   1986 	qglBegin( GL_LINES );
   1987 
   1988 	line = rb_debugLines;
   1989 	for ( i = 0; i < rb_numDebugLines; i++, line++ ) {
   1990 		if ( line->depthTest ) {
   1991 			qglColor4fv( line->rgb.ToFloatPtr() );
   1992 			qglVertex3fv( line->start.ToFloatPtr() );
   1993 			qglVertex3fv( line->end.ToFloatPtr() );
   1994 		}
   1995 	}
   1996 
   1997 	qglEnd();
   1998 
   1999 	qglLineWidth( 1 );
   2000 	GL_State( GLS_DEFAULT );
   2001 }
   2002 
   2003 /*
   2004 ================
   2005 RB_ClearDebugPolygons
   2006 ================
   2007 */
   2008 void RB_ClearDebugPolygons( int time ) {
   2009 	int				i;
   2010 	int				num;
   2011 	debugPolygon_t	*poly;
   2012 
   2013 	rb_debugPolygonTime = time;
   2014 
   2015 	if ( !time ) {
   2016 		rb_numDebugPolygons = 0;
   2017 		return;
   2018 	}
   2019 
   2020 	// copy any polygons that still need to be drawn
   2021 	num	= 0;
   2022 
   2023 	poly = rb_debugPolygons;
   2024 	for ( i = 0; i < rb_numDebugPolygons; i++, poly++ ) {
   2025 		if ( poly->lifeTime > time ) {
   2026 			if ( num != i ) {
   2027 				rb_debugPolygons[ num ] = *poly;
   2028 			}
   2029 			num++;
   2030 		}
   2031 	}
   2032 	rb_numDebugPolygons = num;
   2033 }
   2034 
   2035 /*
   2036 ================
   2037 RB_AddDebugPolygon
   2038 ================
   2039 */
   2040 void RB_AddDebugPolygon( const idVec4 &color, const idWinding &winding, const int lifeTime, const bool depthTest ) {
   2041 	debugPolygon_t *poly;
   2042 
   2043 	if ( rb_numDebugPolygons < MAX_DEBUG_POLYGONS ) {
   2044 		poly = &rb_debugPolygons[ rb_numDebugPolygons++ ];
   2045 		poly->rgb		= color;
   2046 		poly->winding	= winding;
   2047 		poly->depthTest = depthTest;
   2048 		poly->lifeTime	= rb_debugPolygonTime + lifeTime;
   2049 	}
   2050 }
   2051 
   2052 /*
   2053 ================
   2054 RB_ShowDebugPolygons
   2055 ================
   2056 */
   2057 void RB_ShowDebugPolygons() {
   2058 	int				i, j;
   2059 	debugPolygon_t	*poly;
   2060 
   2061 	if ( !rb_numDebugPolygons ) {
   2062 		return;
   2063 	}
   2064 
   2065 	// all lines are expressed in world coordinates
   2066 	RB_SimpleWorldSetup();
   2067 
   2068 	globalImages->BindNull();
   2069 
   2070 	qglDisable( GL_TEXTURE_2D );
   2071 
   2072 	if ( r_debugPolygonFilled.GetBool() ) {
   2073 		GL_State( GLS_POLYGON_OFFSET | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK );
   2074 		GL_PolygonOffset( -1, -2 );
   2075 	} else {
   2076 		GL_State( GLS_POLYGON_OFFSET | GLS_POLYMODE_LINE );
   2077 		GL_PolygonOffset( -1, -2 );
   2078 	}
   2079 
   2080 	poly = rb_debugPolygons;
   2081 	for ( i = 0; i < rb_numDebugPolygons; i++, poly++ ) {
   2082 //		if ( !poly->depthTest ) {
   2083 
   2084 			qglColor4fv( poly->rgb.ToFloatPtr() );
   2085 
   2086 			qglBegin( GL_POLYGON );
   2087 
   2088 			for ( j = 0; j < poly->winding.GetNumPoints(); j++) {
   2089 				qglVertex3fv( poly->winding[j].ToFloatPtr() );
   2090 			}
   2091 
   2092 			qglEnd();
   2093 //		}
   2094 	}
   2095 
   2096 	GL_State( GLS_DEFAULT );
   2097 
   2098 	if ( r_debugPolygonFilled.GetBool() ) {
   2099 		qglDisable( GL_POLYGON_OFFSET_FILL );
   2100 	} else {
   2101 		qglDisable( GL_POLYGON_OFFSET_LINE );
   2102 	}
   2103 
   2104 	GL_State( GLS_DEFAULT );
   2105 }
   2106 
   2107 /*
   2108 ================
   2109 RB_ShowCenterOfProjection
   2110 ================
   2111 */
   2112 void RB_ShowCenterOfProjection() {
   2113 	if ( !r_showCenterOfProjection.GetBool() ) {
   2114 		return;
   2115 	}
   2116 
   2117 	const int w = backEnd.viewDef->scissor.GetWidth();
   2118 	const int h = backEnd.viewDef->scissor.GetHeight();
   2119 	qglClearColor( 1, 0, 0, 1 );
   2120 	for ( float f = 0.0f ; f <= 1.0f ; f += 0.125f ) {
   2121 		qglScissor( w * f - 1 , 0, 3, h );
   2122 		qglClear( GL_COLOR_BUFFER_BIT );
   2123 		qglScissor( 0, h * f - 1 , w, 3 );
   2124 		qglClear( GL_COLOR_BUFFER_BIT );
   2125 	}
   2126 	qglClearColor( 0, 1, 0, 1 );
   2127 	float f = 0.5f;
   2128 	qglScissor( w * f - 1 , 0, 3, h );
   2129 	qglClear( GL_COLOR_BUFFER_BIT );
   2130 	qglScissor( 0, h * f - 1 , w, 3 );
   2131 	qglClear( GL_COLOR_BUFFER_BIT );
   2132 
   2133 	qglScissor( 0, 0, w, h );
   2134 }
   2135 
   2136 /*
   2137 ================
   2138 RB_ShowLines
   2139 
   2140 Draw exact pixel lines to check pixel center sampling
   2141 ================
   2142 */
   2143 void RB_ShowLines() {
   2144 	if ( !r_showLines.GetBool() ) {
   2145 		return;
   2146 	}
   2147 
   2148 	glEnable( GL_SCISSOR_TEST );
   2149 	if ( backEnd.viewDef->renderView.viewEyeBuffer == 0 ) {
   2150 		glClearColor( 1, 0, 0, 1 );
   2151 	} else if ( backEnd.viewDef->renderView.viewEyeBuffer == 1 ) {
   2152 		glClearColor( 0, 1, 0, 1 );
   2153 	} else {
   2154 		glClearColor( 0, 0, 1, 1 );
   2155 	}
   2156 
   2157 	const int start = ( r_showLines.GetInteger() > 2 );	// 1,3 = horizontal, 2,4 = vertical
   2158 	if ( r_showLines.GetInteger() == 1 || r_showLines.GetInteger() == 3 ) {
   2159 		for ( int i = start ; i < tr.GetHeight() ; i+=2 ) {
   2160 			glScissor( 0, i, tr.GetWidth(), 1 );
   2161 			glClear( GL_COLOR_BUFFER_BIT );
   2162 		}
   2163 	} else {
   2164 		for ( int i = start ; i < tr.GetWidth() ; i+=2 ) {
   2165 			glScissor( i, 0, 1, tr.GetHeight() );
   2166 			glClear( GL_COLOR_BUFFER_BIT );
   2167 		}
   2168 	}
   2169 }
   2170 
   2171 
   2172 /*
   2173 ================
   2174 RB_TestGamma
   2175 ================
   2176 */
   2177 #define	G_WIDTH		512
   2178 #define	G_HEIGHT	512
   2179 #define	BAR_HEIGHT	64
   2180 
   2181 void RB_TestGamma() {
   2182 	byte	image[G_HEIGHT][G_WIDTH][4];
   2183 	int		i, j;
   2184 	int		c, comp;
   2185 	int		v, dither;
   2186 	int		mask, y;
   2187 
   2188 	if ( r_testGamma.GetInteger() <= 0 ) {
   2189 		return;
   2190 	}
   2191 
   2192 	v = r_testGamma.GetInteger();
   2193 	if ( v <= 1 || v >= 196 ) {
   2194 		v = 128;
   2195 	}
   2196 
   2197 	memset( image, 0, sizeof( image ) );
   2198 
   2199 	for ( mask = 0; mask < 8; mask++ ) {
   2200 		y = mask * BAR_HEIGHT;
   2201 		for ( c = 0; c < 4; c++ ) {
   2202 			v = c * 64 + 32;
   2203 			// solid color
   2204 			for ( i = 0; i < BAR_HEIGHT/2; i++ ) {
   2205 				for ( j = 0; j < G_WIDTH/4; j++ ) {
   2206 					for ( comp = 0; comp < 3; comp++ ) {
   2207 						if ( mask & ( 1 << comp ) ) {
   2208 							image[y+i][c*G_WIDTH/4+j][comp] = v;
   2209 						}
   2210 					}
   2211 				}
   2212 				// dithered color
   2213 				for ( j = 0; j < G_WIDTH/4; j++ ) {
   2214 					if ( ( i ^ j ) & 1 ) {
   2215 						dither = c * 64;
   2216 					} else {
   2217 						dither = c * 64 + 63;
   2218 					}
   2219 					for ( comp = 0; comp < 3; comp++ ) {
   2220 						if ( mask & ( 1 << comp ) ) {
   2221 							image[y+BAR_HEIGHT/2+i][c*G_WIDTH/4+j][comp] = dither;
   2222 						}
   2223 					}
   2224 				}
   2225 			}
   2226 		}
   2227 	}
   2228 
   2229 	// draw geometrically increasing steps in the bottom row
   2230 	y = 0 * BAR_HEIGHT;
   2231 	float	scale = 1;
   2232 	for ( c = 0; c < 4; c++ ) {
   2233 		v = (int)(64 * scale);
   2234 		if ( v < 0 ) {
   2235 			v = 0;
   2236 		} else if ( v > 255 ) {
   2237 			v = 255;
   2238 		}
   2239 		scale = scale * 1.5;
   2240 		for ( i = 0; i < BAR_HEIGHT; i++ ) {
   2241 			for ( j = 0; j < G_WIDTH/4; j++ ) {
   2242 				image[y+i][c*G_WIDTH/4+j][0] = v;
   2243 				image[y+i][c*G_WIDTH/4+j][1] = v;
   2244 				image[y+i][c*G_WIDTH/4+j][2] = v;
   2245 			}
   2246 		}
   2247 	}
   2248 
   2249 	qglLoadIdentity();
   2250 
   2251 	qglMatrixMode( GL_PROJECTION );
   2252 	GL_State( GLS_DEPTHFUNC_ALWAYS );
   2253 	GL_Color( 1, 1, 1 );
   2254 	qglPushMatrix();
   2255 	qglLoadIdentity(); 
   2256 	qglDisable( GL_TEXTURE_2D );
   2257     qglOrtho( 0, 1, 0, 1, -1, 1 );
   2258 	qglRasterPos2f( 0.01f, 0.01f );
   2259 	qglDrawPixels( G_WIDTH, G_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, image );
   2260 	qglPopMatrix();
   2261 	qglEnable( GL_TEXTURE_2D );
   2262 	qglMatrixMode( GL_MODELVIEW );
   2263 }
   2264 
   2265 
   2266 /*
   2267 ==================
   2268 RB_TestGammaBias
   2269 ==================
   2270 */
   2271 static void RB_TestGammaBias() {
   2272 	byte	image[G_HEIGHT][G_WIDTH][4];
   2273 
   2274 	if ( r_testGammaBias.GetInteger() <= 0 ) {
   2275 		return;
   2276 	}
   2277 
   2278 	int y = 0;
   2279 	for ( int bias = -40; bias < 40; bias+=10, y += BAR_HEIGHT ) {
   2280 		float	scale = 1;
   2281 		for ( int c = 0; c < 4; c++ ) {
   2282 			int v = (int)(64 * scale + bias);
   2283 			scale = scale * 1.5;
   2284 			if ( v < 0 ) {
   2285 				v = 0;
   2286 			} else if ( v > 255 ) {
   2287 				v = 255;
   2288 			}
   2289 			for ( int i = 0; i < BAR_HEIGHT; i++ ) {
   2290 				for ( int j = 0; j < G_WIDTH/4; j++ ) {
   2291 					image[y+i][c*G_WIDTH/4+j][0] = v;
   2292 					image[y+i][c*G_WIDTH/4+j][1] = v;
   2293 					image[y+i][c*G_WIDTH/4+j][2] = v;
   2294 				}
   2295 			}
   2296 		}
   2297 	}
   2298 
   2299 	qglLoadIdentity();
   2300 	qglMatrixMode( GL_PROJECTION );
   2301 	GL_State( GLS_DEPTHFUNC_ALWAYS );
   2302 	GL_Color( 1, 1, 1 );
   2303 	qglPushMatrix();
   2304 	qglLoadIdentity(); 
   2305 	qglDisable( GL_TEXTURE_2D );
   2306     qglOrtho( 0, 1, 0, 1, -1, 1 );
   2307 	qglRasterPos2f( 0.01f, 0.01f );
   2308 	qglDrawPixels( G_WIDTH, G_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, image );
   2309 	qglPopMatrix();
   2310 	qglEnable( GL_TEXTURE_2D );
   2311 	qglMatrixMode( GL_MODELVIEW );
   2312 }
   2313 
   2314 /*
   2315 ================
   2316 RB_TestImage
   2317 
   2318 Display a single image over most of the screen
   2319 ================
   2320 */
   2321 void RB_TestImage() {
   2322 	idImage	*image = NULL;
   2323 	idImage *imageCr = NULL;
   2324 	idImage *imageCb = NULL;
   2325 	int		max;
   2326 	float	w, h;
   2327 
   2328 	image = tr.testImage;
   2329 	if ( !image ) {
   2330 		return;
   2331 	}
   2332 
   2333 	if ( tr.testVideo ) {
   2334 		cinData_t	cin;
   2335 
   2336 		cin = tr.testVideo->ImageForTime( backEnd.viewDef->renderView.time[1] - tr.testVideoStartTime );
   2337 		if ( cin.imageY != NULL ) {
   2338 			image = cin.imageY;
   2339 			imageCr = cin.imageCr;
   2340 			imageCb = cin.imageCb;
   2341 		} else {
   2342 			tr.testImage = NULL;
   2343 			return;
   2344 		}
   2345 		w = 0.25;
   2346 		h = 0.25;
   2347 	} else {
   2348 		max = image->GetUploadWidth() > image->GetUploadHeight() ? image->GetUploadWidth() : image->GetUploadHeight();
   2349 
   2350 		w = 0.25 * image->GetUploadWidth() / max;
   2351 		h = 0.25 * image->GetUploadHeight() / max;
   2352 
   2353 		w *= (float)renderSystem->GetHeight() / renderSystem->GetWidth();
   2354 	}
   2355 
   2356 	// Set State
   2357 	GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
   2358 
   2359 	// Set Parms
   2360 	float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
   2361 	float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
   2362 	renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_S, texS );
   2363 	renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_T, texT );
   2364 
   2365 	float texGenEnabled[4] = { 0, 0, 0, 0 };
   2366 	renderProgManager.SetRenderParm( RENDERPARM_TEXGEN_0_ENABLED, texGenEnabled );
   2367 
   2368 	// not really necessary but just for clarity
   2369 	const float screenWidth = 1.0f;
   2370 	const float screenHeight = 1.0f;
   2371 	const float halfScreenWidth = screenWidth * 0.5f;
   2372 	const float halfScreenHeight = screenHeight * 0.5f;
   2373 
   2374 	float scale[16] = { 0 };
   2375 	scale[0] = w; // scale
   2376 	scale[5] = h; // scale
   2377 	scale[12] = halfScreenWidth - ( halfScreenWidth * w ); // translate
   2378 	scale[13] = halfScreenHeight - ( halfScreenHeight * h ); // translate
   2379 	scale[10] = 1.0f;
   2380 	scale[15] = 1.0f;
   2381 
   2382 	float ortho[16] = { 0 };
   2383 	ortho[0] = 2.0f / screenWidth;
   2384 	ortho[5] = -2.0f / screenHeight;
   2385 	ortho[10] = -2.0f;
   2386 	ortho[12] = -1.0f;
   2387 	ortho[13] = 1.0f;
   2388 	ortho[14] = -1.0f;
   2389 	ortho[15] = 1.0f;
   2390 
   2391 	float finalOrtho[16];
   2392 	R_MatrixMultiply( scale, ortho, finalOrtho );
   2393 
   2394 	float projMatrixTranspose[16];
   2395 	R_MatrixTranspose( finalOrtho, projMatrixTranspose );
   2396 	renderProgManager.SetRenderParms( RENDERPARM_MVPMATRIX_X, projMatrixTranspose, 4 );
   2397 	qglMatrixMode( GL_PROJECTION );
   2398 	qglLoadMatrixf( finalOrtho );
   2399 	qglMatrixMode( GL_MODELVIEW );
   2400 	qglLoadIdentity();
   2401 
   2402 	// Set Color
   2403 	GL_Color( 1, 1, 1, 1 );
   2404 
   2405 	// Bind the Texture
   2406 	if ( ( imageCr != NULL ) && ( imageCb != NULL ) ) {
   2407 		GL_SelectTexture( 0 );
   2408 		image->Bind();
   2409 		GL_SelectTexture( 1 );
   2410 		imageCr->Bind();
   2411 		GL_SelectTexture( 2 );
   2412 		imageCb->Bind();
   2413 		renderProgManager.BindShader_Bink();
   2414 	} else {
   2415 		GL_SelectTexture( 0 );
   2416 		image->Bind();
   2417 		// Set Shader
   2418 		renderProgManager.BindShader_Texture();
   2419 	}
   2420 	
   2421 	// Draw!
   2422 	RB_DrawElementsWithCounters( &backEnd.testImageSurface );
   2423 }
   2424 
   2425 /*
   2426 =================
   2427 RB_DrawExpandedTriangles
   2428 =================
   2429 */
   2430 void RB_DrawExpandedTriangles( const srfTriangles_t *tri, const float radius, const idVec3 &vieworg ) {
   2431 	int i, j, k;
   2432 	idVec3 dir[6], normal, point;
   2433 
   2434 	for ( i = 0; i < tri->numIndexes; i += 3 ) {
   2435 
   2436 		idVec3 p[3] = { tri->verts[ tri->indexes[ i + 0 ] ].xyz, tri->verts[ tri->indexes[ i + 1 ] ].xyz, tri->verts[ tri->indexes[ i + 2 ] ].xyz };
   2437 
   2438 		dir[0] = p[0] - p[1];
   2439 		dir[1] = p[1] - p[2];
   2440 		dir[2] = p[2] - p[0];
   2441 
   2442 		normal = dir[0].Cross( dir[1] );
   2443 
   2444 		if ( normal * p[0] < normal * vieworg ) {
   2445 			continue;
   2446 		}
   2447 
   2448 		dir[0] = normal.Cross( dir[0] );
   2449 		dir[1] = normal.Cross( dir[1] );
   2450 		dir[2] = normal.Cross( dir[2] );
   2451 
   2452 		dir[0].Normalize();
   2453 		dir[1].Normalize();
   2454 		dir[2].Normalize();
   2455 
   2456 		qglBegin( GL_LINE_LOOP );
   2457 
   2458 		for ( j = 0; j < 3; j++ ) {
   2459 			k = ( j + 1 ) % 3;
   2460 
   2461 			dir[4] = ( dir[j] + dir[k] ) * 0.5f;
   2462 			dir[4].Normalize();
   2463 
   2464 			dir[3] = ( dir[j] + dir[4] ) * 0.5f;
   2465 			dir[3].Normalize();
   2466 
   2467 			dir[5] = ( dir[4] + dir[k] ) * 0.5f;
   2468 			dir[5].Normalize();
   2469 
   2470 			point = p[k] + dir[j] * radius;
   2471 			qglVertex3f( point[0], point[1], point[2] );
   2472 
   2473 			point = p[k] + dir[3] * radius;
   2474 			qglVertex3f( point[0], point[1], point[2] );
   2475 
   2476 			point = p[k] + dir[4] * radius;
   2477 			qglVertex3f( point[0], point[1], point[2] );
   2478 
   2479 			point = p[k] + dir[5] * radius;
   2480 			qglVertex3f( point[0], point[1], point[2] );
   2481 
   2482 			point = p[k] + dir[k] * radius;
   2483 			qglVertex3f( point[0], point[1], point[2] );
   2484 		}
   2485 
   2486 		qglEnd();
   2487 	}
   2488 }
   2489 
   2490 /*
   2491 ================
   2492 RB_ShowTrace
   2493 
   2494 Debug visualization
   2495 
   2496 FIXME: not thread safe!
   2497 ================
   2498 */
   2499 void RB_ShowTrace( drawSurf_t **drawSurfs, int numDrawSurfs ) {
   2500 	int						i;
   2501 	const srfTriangles_t	*tri;
   2502 	const drawSurf_t		*surf;
   2503 	idVec3					start, end;
   2504 	idVec3					localStart, localEnd;
   2505 	localTrace_t			hit;
   2506 	float					radius;
   2507 
   2508 	if ( r_showTrace.GetInteger() == 0 ) {
   2509 		return;
   2510 	}
   2511 
   2512 	if ( r_showTrace.GetInteger() == 2 ) {
   2513 		radius = 5.0f;
   2514 	} else {
   2515 		radius = 0.0f;
   2516 	}
   2517 
   2518 	// determine the points of the trace
   2519 	start = backEnd.viewDef->renderView.vieworg;
   2520 	end = start + 4000 * backEnd.viewDef->renderView.viewaxis[0];
   2521 
   2522 	// check and draw the surfaces
   2523 	globalImages->whiteImage->Bind();
   2524 
   2525 	// find how many are ambient
   2526 	for ( i = 0; i < numDrawSurfs; i++ ) {
   2527 		surf = drawSurfs[i];
   2528 		tri = surf->frontEndGeo;
   2529 
   2530 		if ( tri == NULL || tri->verts == NULL ) {
   2531 			continue;
   2532 		}
   2533 
   2534 		// transform the points into local space
   2535 		R_GlobalPointToLocal( surf->space->modelMatrix, start, localStart );
   2536 		R_GlobalPointToLocal( surf->space->modelMatrix, end, localEnd );
   2537 
   2538 		// check the bounding box
   2539 		if ( !tri->bounds.Expand( radius ).LineIntersection( localStart, localEnd ) ) {
   2540 			continue;
   2541 		}
   2542 
   2543 		qglLoadMatrixf( surf->space->modelViewMatrix );
   2544 
   2545 		// highlight the surface
   2546 		GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
   2547 
   2548 		GL_Color( 1, 0, 0, 0.25 );
   2549 		RB_DrawElementsWithCounters( surf );
   2550 
   2551 		// draw the bounding box
   2552 		GL_State( GLS_DEPTHFUNC_ALWAYS );
   2553 
   2554 		GL_Color( 1, 1, 1, 1 );
   2555 		RB_DrawBounds( tri->bounds );
   2556 
   2557 		if ( radius != 0.0f ) {
   2558 			// draw the expanded triangles
   2559 			GL_Color( 0.5f, 0.5f, 1.0f, 1.0f );
   2560 			RB_DrawExpandedTriangles( tri, radius, localStart );
   2561 		}
   2562 
   2563 		// check the exact surfaces
   2564 		hit = R_LocalTrace( localStart, localEnd, radius, tri );
   2565 		if ( hit.fraction < 1.0 ) {
   2566 			GL_Color( 1, 1, 1, 1 );
   2567 			RB_DrawBounds( idBounds( hit.point ).Expand( 1 ) );
   2568 		}
   2569 	}
   2570 }
   2571 
   2572 /*
   2573 =================
   2574 RB_RenderDebugTools
   2575 =================
   2576 */
   2577 void RB_RenderDebugTools( drawSurf_t **drawSurfs, int numDrawSurfs ) {
   2578 	// don't do much if this was a 2D rendering
   2579 	if ( !backEnd.viewDef->viewEntitys ) {
   2580 		RB_TestImage();
   2581 		RB_ShowLines();
   2582 		return;
   2583 	}
   2584 
   2585 	renderLog.OpenMainBlock( MRB_DRAW_DEBUG_TOOLS );
   2586 	RENDERLOG_PRINTF( "---------- RB_RenderDebugTools ----------\n" );
   2587 
   2588 	GL_State( GLS_DEFAULT );
   2589 
   2590 	GL_Scissor( backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1,
   2591 				backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1,
   2592 				backEnd.viewDef->scissor.x2 + 1 - backEnd.viewDef->scissor.x1,
   2593 				backEnd.viewDef->scissor.y2 + 1 - backEnd.viewDef->scissor.y1 );
   2594 	backEnd.currentScissor = backEnd.viewDef->scissor;
   2595 
   2596 	RB_ShowLightCount();
   2597 	RB_ShowTexturePolarity( drawSurfs, numDrawSurfs );
   2598 	RB_ShowTangentSpace( drawSurfs, numDrawSurfs );
   2599 	RB_ShowVertexColor( drawSurfs, numDrawSurfs );
   2600 	RB_ShowTris( drawSurfs, numDrawSurfs );
   2601 	RB_ShowUnsmoothedTangents( drawSurfs, numDrawSurfs );
   2602 	RB_ShowSurfaceInfo( drawSurfs, numDrawSurfs );
   2603 	RB_ShowEdges( drawSurfs, numDrawSurfs );
   2604 	RB_ShowNormals( drawSurfs, numDrawSurfs );
   2605 	RB_ShowViewEntitys( backEnd.viewDef->viewEntitys );
   2606 	RB_ShowLights();
   2607 	RB_ShowTextureVectors( drawSurfs, numDrawSurfs );
   2608 	RB_ShowDominantTris( drawSurfs, numDrawSurfs );
   2609 	if ( r_testGamma.GetInteger() > 0 ) {	// test here so stack check isn't so damn slow on debug builds
   2610 		RB_TestGamma();
   2611 	}
   2612 	if ( r_testGammaBias.GetInteger() > 0 ) {
   2613 		RB_TestGammaBias();
   2614 	}
   2615 	RB_TestImage();
   2616 	RB_ShowPortals();
   2617 	RB_ShowSilhouette();
   2618 	RB_ShowDepthBuffer();
   2619 	RB_ShowIntensity();
   2620 	RB_ShowCenterOfProjection();
   2621 	RB_ShowLines();
   2622 	RB_ShowDebugLines();
   2623 	RB_ShowDebugText();
   2624 	RB_ShowDebugPolygons();
   2625 	RB_ShowTrace( drawSurfs, numDrawSurfs );
   2626 
   2627 	renderLog.CloseMainBlock();
   2628 }
   2629 
   2630 /*
   2631 =================
   2632 RB_ShutdownDebugTools
   2633 =================
   2634 */
   2635 void RB_ShutdownDebugTools() {
   2636 	for ( int i = 0; i < MAX_DEBUG_POLYGONS; i++ ) {
   2637 		rb_debugPolygons[i].winding.Clear();
   2638 	}
   2639 }