Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

cg_drawtools.c (17669B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 //
     23 // cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc
     24 #include "cg_local.h"
     25 
     26 /*
     27 ================
     28 CG_AdjustFrom640
     29 
     30 Adjusted for resolution and screen aspect ratio
     31 ================
     32 */
     33 void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) {
     34 #if 0
     35 	// adjust for wide screens
     36 	if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) {
     37 		*x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) );
     38 	}
     39 #endif
     40 	// scale for screen sizes
     41 	*x *= cgs.screenXScale;
     42 	*y *= cgs.screenYScale;
     43 	*w *= cgs.screenXScale;
     44 	*h *= cgs.screenYScale;
     45 }
     46 
     47 /*
     48 ================
     49 CG_FillRect
     50 
     51 Coordinates are 640*480 virtual values
     52 =================
     53 */
     54 void CG_FillRect( float x, float y, float width, float height, const float *color ) {
     55 	trap_R_SetColor( color );
     56 
     57 	CG_AdjustFrom640( &x, &y, &width, &height );
     58 	trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cgs.media.whiteShader );
     59 
     60 	trap_R_SetColor( NULL );
     61 }
     62 
     63 /*
     64 ================
     65 CG_DrawSides
     66 
     67 Coords are virtual 640x480
     68 ================
     69 */
     70 void CG_DrawSides(float x, float y, float w, float h, float size) {
     71 	CG_AdjustFrom640( &x, &y, &w, &h );
     72 	size *= cgs.screenXScale;
     73 	trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
     74 	trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
     75 }
     76 
     77 void CG_DrawTopBottom(float x, float y, float w, float h, float size) {
     78 	CG_AdjustFrom640( &x, &y, &w, &h );
     79 	size *= cgs.screenYScale;
     80 	trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
     81 	trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
     82 }
     83 /*
     84 ================
     85 UI_DrawRect
     86 
     87 Coordinates are 640*480 virtual values
     88 =================
     89 */
     90 void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
     91 	trap_R_SetColor( color );
     92 
     93   CG_DrawTopBottom(x, y, width, height, size);
     94   CG_DrawSides(x, y, width, height, size);
     95 
     96 	trap_R_SetColor( NULL );
     97 }
     98 
     99 
    100 
    101 /*
    102 ================
    103 CG_DrawPic
    104 
    105 Coordinates are 640*480 virtual values
    106 =================
    107 */
    108 void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
    109 	CG_AdjustFrom640( &x, &y, &width, &height );
    110 	trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
    111 }
    112 
    113 
    114 
    115 /*
    116 ===============
    117 CG_DrawChar
    118 
    119 Coordinates and size in 640*480 virtual screen size
    120 ===============
    121 */
    122 void CG_DrawChar( int x, int y, int width, int height, int ch ) {
    123 	int row, col;
    124 	float frow, fcol;
    125 	float size;
    126 	float	ax, ay, aw, ah;
    127 
    128 	ch &= 255;
    129 
    130 	if ( ch == ' ' ) {
    131 		return;
    132 	}
    133 
    134 	ax = x;
    135 	ay = y;
    136 	aw = width;
    137 	ah = height;
    138 	CG_AdjustFrom640( &ax, &ay, &aw, &ah );
    139 
    140 	row = ch>>4;
    141 	col = ch&15;
    142 
    143 	frow = row*0.0625;
    144 	fcol = col*0.0625;
    145 	size = 0.0625;
    146 
    147 	trap_R_DrawStretchPic( ax, ay, aw, ah,
    148 					   fcol, frow, 
    149 					   fcol + size, frow + size, 
    150 					   cgs.media.charsetShader );
    151 }
    152 
    153 
    154 /*
    155 ==================
    156 CG_DrawStringExt
    157 
    158 Draws a multi-colored string with a drop shadow, optionally forcing
    159 to a fixed color.
    160 
    161 Coordinates are at 640 by 480 virtual resolution
    162 ==================
    163 */
    164 void CG_DrawStringExt( int x, int y, const char *string, const float *setColor, 
    165 		qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars ) {
    166 	vec4_t		color;
    167 	const char	*s;
    168 	int			xx;
    169 	int			cnt;
    170 
    171 	if (maxChars <= 0)
    172 		maxChars = 32767; // do them all!
    173 
    174 	// draw the drop shadow
    175 	if (shadow) {
    176 		color[0] = color[1] = color[2] = 0;
    177 		color[3] = setColor[3];
    178 		trap_R_SetColor( color );
    179 		s = string;
    180 		xx = x;
    181 		cnt = 0;
    182 		while ( *s && cnt < maxChars) {
    183 			if ( Q_IsColorString( s ) ) {
    184 				s += 2;
    185 				continue;
    186 			}
    187 			CG_DrawChar( xx + 2, y + 2, charWidth, charHeight, *s );
    188 			cnt++;
    189 			xx += charWidth;
    190 			s++;
    191 		}
    192 	}
    193 
    194 	// draw the colored text
    195 	s = string;
    196 	xx = x;
    197 	cnt = 0;
    198 	trap_R_SetColor( setColor );
    199 	while ( *s && cnt < maxChars) {
    200 		if ( Q_IsColorString( s ) ) {
    201 			if ( !forceColor ) {
    202 				memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
    203 				color[3] = setColor[3];
    204 				trap_R_SetColor( color );
    205 			}
    206 			s += 2;
    207 			continue;
    208 		}
    209 		CG_DrawChar( xx, y, charWidth, charHeight, *s );
    210 		xx += charWidth;
    211 		cnt++;
    212 		s++;
    213 	}
    214 	trap_R_SetColor( NULL );
    215 }
    216 
    217 void CG_DrawBigString( int x, int y, const char *s, float alpha ) {
    218 	float	color[4];
    219 
    220 	color[0] = color[1] = color[2] = 1.0;
    221 	color[3] = alpha;
    222 	CG_DrawStringExt( x, y, s, color, qfalse, qtrue, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, 0 );
    223 }
    224 
    225 void CG_DrawBigStringColor( int x, int y, const char *s, vec4_t color ) {
    226 	CG_DrawStringExt( x, y, s, color, qtrue, qtrue, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, 0 );
    227 }
    228 
    229 void CG_DrawSmallString( int x, int y, const char *s, float alpha ) {
    230 	float	color[4];
    231 
    232 	color[0] = color[1] = color[2] = 1.0;
    233 	color[3] = alpha;
    234 	CG_DrawStringExt( x, y, s, color, qfalse, qfalse, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
    235 }
    236 
    237 void CG_DrawSmallStringColor( int x, int y, const char *s, vec4_t color ) {
    238 	CG_DrawStringExt( x, y, s, color, qtrue, qfalse, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 );
    239 }
    240 
    241 /*
    242 =================
    243 CG_DrawStrlen
    244 
    245 Returns character count, skiping color escape codes
    246 =================
    247 */
    248 int CG_DrawStrlen( const char *str ) {
    249 	const char *s = str;
    250 	int count = 0;
    251 
    252 	while ( *s ) {
    253 		if ( Q_IsColorString( s ) ) {
    254 			s += 2;
    255 		} else {
    256 			count++;
    257 			s++;
    258 		}
    259 	}
    260 
    261 	return count;
    262 }
    263 
    264 /*
    265 =============
    266 CG_TileClearBox
    267 
    268 This repeats a 64*64 tile graphic to fill the screen around a sized down
    269 refresh window.
    270 =============
    271 */
    272 static void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader ) {
    273 	float	s1, t1, s2, t2;
    274 
    275 	s1 = x/64.0;
    276 	t1 = y/64.0;
    277 	s2 = (x+w)/64.0;
    278 	t2 = (y+h)/64.0;
    279 	trap_R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader );
    280 }
    281 
    282 
    283 
    284 /*
    285 ==============
    286 CG_TileClear
    287 
    288 Clear around a sized down screen
    289 ==============
    290 */
    291 void CG_TileClear( void ) {
    292 	int		top, bottom, left, right;
    293 	int		w, h;
    294 
    295 	w = cgs.glconfig.vidWidth;
    296 	h = cgs.glconfig.vidHeight;
    297 
    298 	if ( cg.refdef.x == 0 && cg.refdef.y == 0 && 
    299 		cg.refdef.width == w && cg.refdef.height == h ) {
    300 		return;		// full screen rendering
    301 	}
    302 
    303 	top = cg.refdef.y;
    304 	bottom = top + cg.refdef.height-1;
    305 	left = cg.refdef.x;
    306 	right = left + cg.refdef.width-1;
    307 
    308 	// clear above view screen
    309 	CG_TileClearBox( 0, 0, w, top, cgs.media.backTileShader );
    310 
    311 	// clear below view screen
    312 	CG_TileClearBox( 0, bottom, w, h - bottom, cgs.media.backTileShader );
    313 
    314 	// clear left of view screen
    315 	CG_TileClearBox( 0, top, left, bottom - top + 1, cgs.media.backTileShader );
    316 
    317 	// clear right of view screen
    318 	CG_TileClearBox( right, top, w - right, bottom - top + 1, cgs.media.backTileShader );
    319 }
    320 
    321 
    322 
    323 /*
    324 ================
    325 CG_FadeColor
    326 ================
    327 */
    328 float *CG_FadeColor( int startMsec, int totalMsec ) {
    329 	static vec4_t		color;
    330 	int			t;
    331 
    332 	if ( startMsec == 0 ) {
    333 		return NULL;
    334 	}
    335 
    336 	t = cg.time - startMsec;
    337 
    338 	if ( t >= totalMsec ) {
    339 		return NULL;
    340 	}
    341 
    342 	// fade out
    343 	if ( totalMsec - t < FADE_TIME ) {
    344 		color[3] = ( totalMsec - t ) * 1.0/FADE_TIME;
    345 	} else {
    346 		color[3] = 1.0;
    347 	}
    348 	color[0] = color[1] = color[2] = 1;
    349 
    350 	return color;
    351 }
    352 
    353 
    354 /*
    355 ================
    356 CG_TeamColor
    357 ================
    358 */
    359 float *CG_TeamColor( int team ) {
    360 	static vec4_t	red = {1, 0.2f, 0.2f, 1};
    361 	static vec4_t	blue = {0.2f, 0.2f, 1, 1};
    362 	static vec4_t	other = {1, 1, 1, 1};
    363 	static vec4_t	spectator = {0.7f, 0.7f, 0.7f, 1};
    364 
    365 	switch ( team ) {
    366 	case TEAM_RED:
    367 		return red;
    368 	case TEAM_BLUE:
    369 		return blue;
    370 	case TEAM_SPECTATOR:
    371 		return spectator;
    372 	default:
    373 		return other;
    374 	}
    375 }
    376 
    377 
    378 
    379 /*
    380 =================
    381 CG_GetColorForHealth
    382 =================
    383 */
    384 void CG_GetColorForHealth( int health, int armor, vec4_t hcolor ) {
    385 	int		count;
    386 	int		max;
    387 
    388 	// calculate the total points of damage that can
    389 	// be sustained at the current health / armor level
    390 	if ( health <= 0 ) {
    391 		VectorClear( hcolor );	// black
    392 		hcolor[3] = 1;
    393 		return;
    394 	}
    395 	count = armor;
    396 	max = health * ARMOR_PROTECTION / ( 1.0 - ARMOR_PROTECTION );
    397 	if ( max < count ) {
    398 		count = max;
    399 	}
    400 	health += count;
    401 
    402 	// set the color based on health
    403 	hcolor[0] = 1.0;
    404 	hcolor[3] = 1.0;
    405 	if ( health >= 100 ) {
    406 		hcolor[2] = 1.0;
    407 	} else if ( health < 66 ) {
    408 		hcolor[2] = 0;
    409 	} else {
    410 		hcolor[2] = ( health - 66 ) / 33.0;
    411 	}
    412 
    413 	if ( health > 60 ) {
    414 		hcolor[1] = 1.0;
    415 	} else if ( health < 30 ) {
    416 		hcolor[1] = 0;
    417 	} else {
    418 		hcolor[1] = ( health - 30 ) / 30.0;
    419 	}
    420 }
    421 
    422 /*
    423 =================
    424 CG_ColorForHealth
    425 =================
    426 */
    427 void CG_ColorForHealth( vec4_t hcolor ) {
    428 
    429 	CG_GetColorForHealth( cg.snap->ps.stats[STAT_HEALTH], 
    430 		cg.snap->ps.stats[STAT_ARMOR], hcolor );
    431 }
    432 
    433 
    434 
    435 
    436 // bk001205 - code below duplicated in q3_ui/ui-atoms.c
    437 // bk001205 - FIXME: does this belong in ui_shared.c?
    438 // bk001205 - FIXME: HARD_LINKED flags not visible here
    439 #ifndef Q3_STATIC // bk001205 - q_shared defines not visible here 
    440 /*
    441 =================
    442 UI_DrawProportionalString2
    443 =================
    444 */
    445 static int	propMap[128][3] = {
    446 {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
    447 {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
    448 
    449 {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
    450 {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
    451 
    452 {0, 0, PROP_SPACE_WIDTH},		// SPACE
    453 {11, 122, 7},	// !
    454 {154, 181, 14},	// "
    455 {55, 122, 17},	// #
    456 {79, 122, 18},	// $
    457 {101, 122, 23},	// %
    458 {153, 122, 18},	// &
    459 {9, 93, 7},		// '
    460 {207, 122, 8},	// (
    461 {230, 122, 9},	// )
    462 {177, 122, 18},	// *
    463 {30, 152, 18},	// +
    464 {85, 181, 7},	// ,
    465 {34, 93, 11},	// -
    466 {110, 181, 6},	// .
    467 {130, 152, 14},	// /
    468 
    469 {22, 64, 17},	// 0
    470 {41, 64, 12},	// 1
    471 {58, 64, 17},	// 2
    472 {78, 64, 18},	// 3
    473 {98, 64, 19},	// 4
    474 {120, 64, 18},	// 5
    475 {141, 64, 18},	// 6
    476 {204, 64, 16},	// 7
    477 {162, 64, 17},	// 8
    478 {182, 64, 18},	// 9
    479 {59, 181, 7},	// :
    480 {35,181, 7},	// ;
    481 {203, 152, 14},	// <
    482 {56, 93, 14},	// =
    483 {228, 152, 14},	// >
    484 {177, 181, 18},	// ?
    485 
    486 {28, 122, 22},	// @
    487 {5, 4, 18},		// A
    488 {27, 4, 18},	// B
    489 {48, 4, 18},	// C
    490 {69, 4, 17},	// D
    491 {90, 4, 13},	// E
    492 {106, 4, 13},	// F
    493 {121, 4, 18},	// G
    494 {143, 4, 17},	// H
    495 {164, 4, 8},	// I
    496 {175, 4, 16},	// J
    497 {195, 4, 18},	// K
    498 {216, 4, 12},	// L
    499 {230, 4, 23},	// M
    500 {6, 34, 18},	// N
    501 {27, 34, 18},	// O
    502 
    503 {48, 34, 18},	// P
    504 {68, 34, 18},	// Q
    505 {90, 34, 17},	// R
    506 {110, 34, 18},	// S
    507 {130, 34, 14},	// T
    508 {146, 34, 18},	// U
    509 {166, 34, 19},	// V
    510 {185, 34, 29},	// W
    511 {215, 34, 18},	// X
    512 {234, 34, 18},	// Y
    513 {5, 64, 14},	// Z
    514 {60, 152, 7},	// [
    515 {106, 151, 13},	// '\'
    516 {83, 152, 7},	// ]
    517 {128, 122, 17},	// ^
    518 {4, 152, 21},	// _
    519 
    520 {134, 181, 5},	// '
    521 {5, 4, 18},		// A
    522 {27, 4, 18},	// B
    523 {48, 4, 18},	// C
    524 {69, 4, 17},	// D
    525 {90, 4, 13},	// E
    526 {106, 4, 13},	// F
    527 {121, 4, 18},	// G
    528 {143, 4, 17},	// H
    529 {164, 4, 8},	// I
    530 {175, 4, 16},	// J
    531 {195, 4, 18},	// K
    532 {216, 4, 12},	// L
    533 {230, 4, 23},	// M
    534 {6, 34, 18},	// N
    535 {27, 34, 18},	// O
    536 
    537 {48, 34, 18},	// P
    538 {68, 34, 18},	// Q
    539 {90, 34, 17},	// R
    540 {110, 34, 18},	// S
    541 {130, 34, 14},	// T
    542 {146, 34, 18},	// U
    543 {166, 34, 19},	// V
    544 {185, 34, 29},	// W
    545 {215, 34, 18},	// X
    546 {234, 34, 18},	// Y
    547 {5, 64, 14},	// Z
    548 {153, 152, 13},	// {
    549 {11, 181, 5},	// |
    550 {180, 152, 13},	// }
    551 {79, 93, 17},	// ~
    552 {0, 0, -1}		// DEL
    553 };
    554 
    555 static int propMapB[26][3] = {
    556 {11, 12, 33},
    557 {49, 12, 31},
    558 {85, 12, 31},
    559 {120, 12, 30},
    560 {156, 12, 21},
    561 {183, 12, 21},
    562 {207, 12, 32},
    563 
    564 {13, 55, 30},
    565 {49, 55, 13},
    566 {66, 55, 29},
    567 {101, 55, 31},
    568 {135, 55, 21},
    569 {158, 55, 40},
    570 {204, 55, 32},
    571 
    572 {12, 97, 31},
    573 {48, 97, 31},
    574 {82, 97, 30},
    575 {118, 97, 30},
    576 {153, 97, 30},
    577 {185, 97, 25},
    578 {213, 97, 30},
    579 
    580 {11, 139, 32},
    581 {42, 139, 51},
    582 {93, 139, 32},
    583 {126, 139, 31},
    584 {158, 139, 25},
    585 };
    586 
    587 #define PROPB_GAP_WIDTH		4
    588 #define PROPB_SPACE_WIDTH	12
    589 #define PROPB_HEIGHT		36
    590 
    591 /*
    592 =================
    593 UI_DrawBannerString
    594 =================
    595 */
    596 static void UI_DrawBannerString2( int x, int y, const char* str, vec4_t color )
    597 {
    598 	const char* s;
    599 	unsigned char	ch; // bk001204 : array subscript
    600 	float	ax;
    601 	float	ay;
    602 	float	aw;
    603 	float	ah;
    604 	float	frow;
    605 	float	fcol;
    606 	float	fwidth;
    607 	float	fheight;
    608 
    609 	// draw the colored text
    610 	trap_R_SetColor( color );
    611 	
    612 	ax = x * cgs.screenXScale + cgs.screenXBias;
    613 	ay = y * cgs.screenXScale;
    614 
    615 	s = str;
    616 	while ( *s )
    617 	{
    618 		ch = *s & 127;
    619 		if ( ch == ' ' ) {
    620 			ax += ((float)PROPB_SPACE_WIDTH + (float)PROPB_GAP_WIDTH)* cgs.screenXScale;
    621 		}
    622 		else if ( ch >= 'A' && ch <= 'Z' ) {
    623 			ch -= 'A';
    624 			fcol = (float)propMapB[ch][0] / 256.0f;
    625 			frow = (float)propMapB[ch][1] / 256.0f;
    626 			fwidth = (float)propMapB[ch][2] / 256.0f;
    627 			fheight = (float)PROPB_HEIGHT / 256.0f;
    628 			aw = (float)propMapB[ch][2] * cgs.screenXScale;
    629 			ah = (float)PROPB_HEIGHT * cgs.screenXScale;
    630 			trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, cgs.media.charsetPropB );
    631 			ax += (aw + (float)PROPB_GAP_WIDTH * cgs.screenXScale);
    632 		}
    633 		s++;
    634 	}
    635 
    636 	trap_R_SetColor( NULL );
    637 }
    638 
    639 void UI_DrawBannerString( int x, int y, const char* str, int style, vec4_t color ) {
    640 	const char *	s;
    641 	int				ch;
    642 	int				width;
    643 	vec4_t			drawcolor;
    644 
    645 	// find the width of the drawn text
    646 	s = str;
    647 	width = 0;
    648 	while ( *s ) {
    649 		ch = *s;
    650 		if ( ch == ' ' ) {
    651 			width += PROPB_SPACE_WIDTH;
    652 		}
    653 		else if ( ch >= 'A' && ch <= 'Z' ) {
    654 			width += propMapB[ch - 'A'][2] + PROPB_GAP_WIDTH;
    655 		}
    656 		s++;
    657 	}
    658 	width -= PROPB_GAP_WIDTH;
    659 
    660 	switch( style & UI_FORMATMASK ) {
    661 		case UI_CENTER:
    662 			x -= width / 2;
    663 			break;
    664 
    665 		case UI_RIGHT:
    666 			x -= width;
    667 			break;
    668 
    669 		case UI_LEFT:
    670 		default:
    671 			break;
    672 	}
    673 
    674 	if ( style & UI_DROPSHADOW ) {
    675 		drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
    676 		drawcolor[3] = color[3];
    677 		UI_DrawBannerString2( x+2, y+2, str, drawcolor );
    678 	}
    679 
    680 	UI_DrawBannerString2( x, y, str, color );
    681 }
    682 
    683 
    684 int UI_ProportionalStringWidth( const char* str ) {
    685 	const char *	s;
    686 	int				ch;
    687 	int				charWidth;
    688 	int				width;
    689 
    690 	s = str;
    691 	width = 0;
    692 	while ( *s ) {
    693 		ch = *s & 127;
    694 		charWidth = propMap[ch][2];
    695 		if ( charWidth != -1 ) {
    696 			width += charWidth;
    697 			width += PROP_GAP_WIDTH;
    698 		}
    699 		s++;
    700 	}
    701 
    702 	width -= PROP_GAP_WIDTH;
    703 	return width;
    704 }
    705 
    706 static void UI_DrawProportionalString2( int x, int y, const char* str, vec4_t color, float sizeScale, qhandle_t charset )
    707 {
    708 	const char* s;
    709 	unsigned char	ch; // bk001204 - unsigned
    710 	float	ax;
    711 	float	ay;
    712 	float	aw;
    713 	float	ah;
    714 	float	frow;
    715 	float	fcol;
    716 	float	fwidth;
    717 	float	fheight;
    718 
    719 	// draw the colored text
    720 	trap_R_SetColor( color );
    721 	
    722 	ax = x * cgs.screenXScale + cgs.screenXBias;
    723 	ay = y * cgs.screenXScale;
    724 
    725 	s = str;
    726 	while ( *s )
    727 	{
    728 		ch = *s & 127;
    729 		if ( ch == ' ' ) {
    730 			aw = (float)PROP_SPACE_WIDTH * cgs.screenXScale * sizeScale;
    731 		} else if ( propMap[ch][2] != -1 ) {
    732 			fcol = (float)propMap[ch][0] / 256.0f;
    733 			frow = (float)propMap[ch][1] / 256.0f;
    734 			fwidth = (float)propMap[ch][2] / 256.0f;
    735 			fheight = (float)PROP_HEIGHT / 256.0f;
    736 			aw = (float)propMap[ch][2] * cgs.screenXScale * sizeScale;
    737 			ah = (float)PROP_HEIGHT * cgs.screenXScale * sizeScale;
    738 			trap_R_DrawStretchPic( ax, ay, aw, ah, fcol, frow, fcol+fwidth, frow+fheight, charset );
    739 		} else {
    740 			aw = 0;
    741 		}
    742 
    743 		ax += (aw + (float)PROP_GAP_WIDTH * cgs.screenXScale * sizeScale);
    744 		s++;
    745 	}
    746 
    747 	trap_R_SetColor( NULL );
    748 }
    749 
    750 /*
    751 =================
    752 UI_ProportionalSizeScale
    753 =================
    754 */
    755 float UI_ProportionalSizeScale( int style ) {
    756 	if(  style & UI_SMALLFONT ) {
    757 		return 0.75;
    758 	}
    759 
    760 	return 1.00;
    761 }
    762 
    763 
    764 /*
    765 =================
    766 UI_DrawProportionalString
    767 =================
    768 */
    769 void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ) {
    770 	vec4_t	drawcolor;
    771 	int		width;
    772 	float	sizeScale;
    773 
    774 	sizeScale = UI_ProportionalSizeScale( style );
    775 
    776 	switch( style & UI_FORMATMASK ) {
    777 		case UI_CENTER:
    778 			width = UI_ProportionalStringWidth( str ) * sizeScale;
    779 			x -= width / 2;
    780 			break;
    781 
    782 		case UI_RIGHT:
    783 			width = UI_ProportionalStringWidth( str ) * sizeScale;
    784 			x -= width;
    785 			break;
    786 
    787 		case UI_LEFT:
    788 		default:
    789 			break;
    790 	}
    791 
    792 	if ( style & UI_DROPSHADOW ) {
    793 		drawcolor[0] = drawcolor[1] = drawcolor[2] = 0;
    794 		drawcolor[3] = color[3];
    795 		UI_DrawProportionalString2( x+2, y+2, str, drawcolor, sizeScale, cgs.media.charsetProp );
    796 	}
    797 
    798 	if ( style & UI_INVERSE ) {
    799 		drawcolor[0] = color[0] * 0.8;
    800 		drawcolor[1] = color[1] * 0.8;
    801 		drawcolor[2] = color[2] * 0.8;
    802 		drawcolor[3] = color[3];
    803 		UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, cgs.media.charsetProp );
    804 		return;
    805 	}
    806 
    807 	if ( style & UI_PULSE ) {
    808 		drawcolor[0] = color[0] * 0.8;
    809 		drawcolor[1] = color[1] * 0.8;
    810 		drawcolor[2] = color[2] * 0.8;
    811 		drawcolor[3] = color[3];
    812 		UI_DrawProportionalString2( x, y, str, color, sizeScale, cgs.media.charsetProp );
    813 
    814 		drawcolor[0] = color[0];
    815 		drawcolor[1] = color[1];
    816 		drawcolor[2] = color[2];
    817 		drawcolor[3] = 0.5 + 0.5 * sin( cg.time / PULSE_DIVISOR );
    818 		UI_DrawProportionalString2( x, y, str, drawcolor, sizeScale, cgs.media.charsetPropGlow );
    819 		return;
    820 	}
    821 
    822 	UI_DrawProportionalString2( x, y, str, color, sizeScale, cgs.media.charsetProp );
    823 }
    824 #endif // Q3STATIC