Ejemplo n.º 1
0
/*
* SCR_GetNextColumnLayout
*/
static const char *SCR_GetNextColumnLayout( const char **ptrlay, const char **ptrtitle, char *type, int *width, struct qfontface_s *font )
{
	static const char *empty = "";
	const char *token;

	assert( ptrlay && *ptrlay );

	// get the token type from the layout
	token = COM_ParseExt( ptrlay, true );
	if( !token[0] )
		return NULL;

	if( token[0] != '%' )
		CG_Error( "SCR_GetNextColumnLayout: Invalid player tab layout (expecting token type. found '%s')\n", token );

	if( type )
		*type = token[1];

	// get the column width from the layout
	token = COM_ParseExt( ptrlay, true );
	if( !token[0] || token[0] == '%' )
		CG_Error( "SCR_GetNextColumnLayout: Invalid player tab layout (expecting token width. found '%s')\n", token );

	if( width )
	{
		float widthScale = cg_scoreboardWidthScale->value;
		bool relative = true;
		if( token[0] == 'l' ) // line heights
		{
			widthScale *= trap_SCR_FontHeight( font );
			relative = false;
			token++;
		}
		*width = (int)( atof( token ) * widthScale );
		if( relative )
			*width = *width * cgs.vidHeight / 600;

		if( *width < 0 )
			*width = 0;
	}

	if( ptrtitle && *ptrtitle )
	{
		// get the column title token from the layout
		token = COM_ParseExt( ptrtitle, true );
		if( !token[0] )
			CG_Error( "SCR_GetNextColumnLayout: Invalid player tab layout (expecting token tittle. found '%s')\n", token );
	}
	else
	{
		token = empty;
	}

	return token;
}
Ejemplo n.º 2
0
/*
* SCR_DrawChallengers
*/
static int SCR_DrawChallengers( const char **ptrptr, int x, int y, int panelWidth, struct qfontface_s *font, int pass )
{
	const char *token;
	char string[MAX_STRING_CHARS];
	int yoffset = 0, xoffset = 0;
	int playerNum, ping;
	int height;

	assert( ptrptr && *ptrptr );

	height = trap_SCR_FontHeight( font );

	// draw title
	yoffset = height;
	if( pass ) {
		trap_SCR_DrawString( x + xoffset, y + yoffset, ALIGN_CENTER_TOP,
			CG_TranslateString( "Challengers" ), font, colorCyan );
	}
	yoffset += height;

	// draw challengers
	while( *ptrptr )
	{
		if( !SCR_ParseToken( ptrptr, &token ) )
			break;

		// first token is played id
		playerNum = atoi( token );
		if( playerNum < 0 || playerNum >= gs.maxclients )
			break;

		// get a second token
		if( !SCR_ParseToken( ptrptr, &token ) )
			break;

		// second token is ping
		ping = atoi( token );

		// draw the challenger
		if( ping < 0 )
			Q_snprintfz( string, sizeof( string ), "%s%s ...", cgs.clientInfo[playerNum].name, S_COLOR_WHITE );
		else
			Q_snprintfz( string, sizeof( string ), "%s%s %i", cgs.clientInfo[playerNum].name, S_COLOR_WHITE, ping );

		if( pass ) {
			trap_SCR_DrawString( x + xoffset, y + yoffset, ALIGN_CENTER_TOP, string, font, colorWhite );
		}
		yoffset += height;
	}

	yoffset += height;
	return yoffset;
}
Ejemplo n.º 3
0
/*
* SCR_DrawPlayerIcons
*/
static void SCR_DrawPlayerIcons( struct qfontface_s *font )
{
	if( !scr_numplayericons )
		return;

	qsort( scr_playericons, scr_numplayericons, sizeof( scr_playericons[0] ),
		( int (*)( const void *, const void * ) )SCR_ComparePlayerIcons );

	int height = trap_SCR_FontHeight( font );
	vec4_t color;
	Vector4Copy( colorWhite, color );

	for( unsigned i = 0; i < scr_numplayericons; i++ )
	{
		scr_playericon_t &icon = scr_playericons[i];
		color[3] = icon.alpha;
		trap_R_DrawStretchPic( icon.x, icon.y, height, height, 0, 0, 1, 1, color, icon.image );
	}

	scr_numplayericons = 0;
}
Ejemplo n.º 4
0
/*
* CG_DrawScoreboard
*/
void CG_DrawScoreboard( void )
{
	int pass;
	const char *ptr, *token, *layout;
	char title[MAX_CONFIGSTRING_CHARS], type;
	int team = TEAM_PLAYERS;
	int xpos;
	int ypos, yoffset, maxyoffset;
	struct qfontface_s *font;
	struct qfontface_s *monofont;
	struct qfontface_s *titlefont;
	int width, panelWidth;
	vec4_t whiteTransparent = { 1.0f, 1.0f, 1.0f, 0.5f };

	// no layout defined
	if( !cgs.configStrings[CS_SCB_PLAYERTAB_LAYOUT][0] )
		return;

	if( scoreboardString[0] != '&' ) // nothing to draw
		return;

	font = CG_ScoreboardFont( cg_scoreboardFontFamily, cg_scoreboardFontSize );
	monofont = CG_ScoreboardFont( cg_scoreboardMonoFontFamily, cg_scoreboardFontSize );
	titlefont = CG_ScoreboardFont( cg_scoreboardTitleFontFamily, cg_scoreboardTitleFontSize );

	xpos = (int)( cgs.vidWidth * 0.5 );
	ypos = (int)( cgs.vidHeight * 0.2 ) - 24 * cgs.vidHeight / 600;

	// draw title
	Q_strncpyz( title, cgs.configStrings[CS_GAMETYPETITLE], sizeof( title ) );
	if( !title[0] )
		Q_strncpyz( title, gs.gametypeName, sizeof( title ) );
	Q_strupr( title );

	trap_SCR_DrawString( xpos, ypos, ALIGN_CENTER_TOP, title, titlefont, whiteTransparent );
	ypos += trap_SCR_FontHeight( titlefont );
	trap_SCR_DrawStringWidth( xpos, ypos, ALIGN_CENTER_TOP, cgs.configStrings[CS_HOSTNAME], cgs.vidWidth*0.75, font, whiteTransparent );
	ypos += trap_SCR_FontHeight( font );

	// calculate the panel width from the layout
	panelWidth = 0;
	layout = cgs.configStrings[CS_SCB_PLAYERTAB_LAYOUT];
	while( SCR_GetNextColumnLayout( &layout, NULL, &type, &width, font ) != NULL )
	{
		if( !SCR_SkipColumn( type ) )
			panelWidth += width;
	}

	// parse and draw the scoreboard message
	for ( pass = 0; pass < 2; pass++ )
	{
		yoffset = 0;
		maxyoffset = 0;
		scr_numplayericons = 0;
		ptr = scoreboardString;
		while ( ptr )
		{
			token = COM_ParseExt( &ptr, true );
			if ( token[0] != '&' )
				break;

			if ( !Q_stricmp( token, "&t" ) ) // team tab
			{
				yoffset = 0;
				yoffset += SCR_DrawTeamTab( &ptr, &team, xpos, ypos + yoffset, panelWidth, font, titlefont, pass );
			}
			else if ( !Q_stricmp( token, "&p" ) ) // player tab
			{
				yoffset += SCR_DrawPlayerTab( &ptr, team, xpos, ypos + yoffset, panelWidth, font, pass );
			}
			else if ( !Q_stricmp( token, "&w" ) ) // list of challengers
			{
				if ( yoffset < maxyoffset )
					yoffset = maxyoffset;

				maxyoffset += SCR_DrawChallengers( &ptr, xpos, ypos + yoffset, panelWidth, font, pass );
			}
			else if ( !Q_stricmp( token, "&s" ) ) // list of spectators
			{
				if ( yoffset < maxyoffset )
					yoffset = maxyoffset;

				maxyoffset += SCR_DrawSpectators( &ptr, xpos, ypos + yoffset, panelWidth, font, true, "Spectators", colorYellow, pass );
			}
			else if( !Q_stricmp( token, "&y" ) ) // list of chasers
			{
				if( yoffset < maxyoffset )
					yoffset = maxyoffset;

				if( cg_showChasers->integer )
					maxyoffset += SCR_DrawSpectators( &ptr, xpos, ypos + yoffset, panelWidth, font, false, "Chasers", colorOrange, pass );
				else
					SCR_IgnoreSpectators( &ptr, false );
			}

			if ( yoffset > maxyoffset )
				maxyoffset = yoffset;
		}
		if( !pass )
			SCR_DrawPlayerIcons( font );
	}

	// add the player stats
	yoffset = maxyoffset + trap_SCR_FontHeight( font );
	yoffset += SCB_DrawPlayerStats( xpos, ypos + yoffset, monofont );
}
Ejemplo n.º 5
0
/*
* SCR_DrawPlayerTab
*/
static int SCR_DrawPlayerTab( const char **ptrptr, int team, int x, int y, int panelWidth, struct qfontface_s *font, int pass )
{
	int dir, align, i, columncount;
	char type, string[MAX_STRING_CHARS];
	const char *token, *layout;
	int height, width, xoffset, yoffset;
	vec4_t teamcolor = { 0.0f, 0.0f, 0.0f, 1.0f }, color;
	int iconnum;
	struct shader_s *icon;
	bool highlight = false, trans = false;

	if( GS_TeamBasedGametype() )
	{
		dir = ( team == TEAM_ALPHA ) ? -1 : 1;
		align = ( team == TEAM_ALPHA ) ? ALIGN_RIGHT_TOP : ALIGN_LEFT_TOP;
	}
	else
	{
		dir = 0;
		align = ALIGN_CENTER_TOP;
	}

	xoffset = 0;
	yoffset = 0;

	height = trap_SCR_FontHeight( font );

	// start from the center again
	xoffset = CG_HorizontalAlignForWidth( 0, align, panelWidth );
	xoffset += ( SCB_CENTERMARGIN * dir );

	// draw the background
	columncount = 0;
	if( ( team == TEAM_ALPHA ) || ( team == TEAM_BETA ) )
		CG_TeamColor( team, teamcolor );

	// draw the player tab column titles
	layout = cgs.configStrings[CS_SCB_PLAYERTAB_LAYOUT];

	while( SCR_GetNextColumnLayout( &layout, NULL, &type, &width, font ) != NULL )
	{
		// grab the actual scoreboard data
		if( !SCR_ParseToken( ptrptr, &token ) )
			break;

		if( SCR_SkipColumn( type ) )
			continue;

		Vector4Copy( colorWhite, color ); // reset to white after each column
		icon = NULL;
		string[0] = 0;

		// interpret the data based on the type defined in the layout
		switch( type )
		{
		default:
			CG_Error( "SCR_DrawPlayerTab: Invalid player tab layout\n" );
			break;

		case 's': // is a string
			{
				char l10n[MAX_STRING_CHARS];
				Q_strncpyz( string, CG_TranslateColoredString( token, l10n, sizeof( l10n ) ), sizeof( string ) );
			}
			break;

		case 'n': // is a player name indicated by player number
			i = atoi( token );

			if( i < 0 ) // negative numbers toggle transparency on
			{
				trans = true;
				i = -1 - i;
			}

			if( i < 0 || i >= gs.maxclients )
				Q_strncpyz( string, "invalid", sizeof( string ) );
			else
				Q_strncpyz( string, cgs.clientInfo[i].name, sizeof( string ) );

			if( ISVIEWERENTITY( i + 1 ) ) // highlight if it's our own player
				highlight = true;

			break;
		case 'i': // is a integer (negatives are colored in red)
			i = atoi( token );
			Q_snprintfz( string, sizeof( string ), "%i", i );
			VectorCopy( i >= 0 ? colorWhite : colorRed, color );
			break;

		case 'f': // is a float
			Q_snprintfz( string, sizeof( string ), "%.2f", atof( token ) );
			break;

		case 'l': // p is an integer colored in latency style
			i = atoi( token );
			Q_snprintfz( string, sizeof( string ), "%i", i );
			CG_PingColor( i, color );
			break;

		case 'b': // is a Y/N boolean
			i = atoi( token );
			Q_snprintfz( string, sizeof( string ), "%s", CG_TranslateString( ( i != 0 ) ? "Yes" : "No" ) );
			VectorCopy( i ? colorGreen : colorRed, color );
			break;

		case 'p': // is a picture. It uses height for width to get a square
			iconnum = atoi( token );
			if( ( iconnum > 0 ) && ( iconnum < MAX_IMAGES ) )
				icon = cgs.imagePrecache[iconnum];
			break;

		case 't': // is a race time. Convert time into MM:SS:mm
			{
				unsigned int milli, min, sec;

				milli = (unsigned int)( atoi( token ) );
				if( !milli )
					Q_snprintfz( string, sizeof( string ), CG_TranslateString( "no time" ) );
				else
				{
					min = milli / 60000;
					milli -= min * 60000;
					sec = milli / 1000;
					milli -= sec * 1000;
					Q_snprintfz( string, sizeof( string ), va( "%02i:%02i.%03i", min, sec, milli ) );
				}
			}
			break;

		case 'r': // is a ready state tick that is hidden when not in warmup
			if( atoi( token ) )
				icon = CG_MediaShader( cgs.media.shaderVSayIcon[VSAY_YES] );
			break;
		}

		if( !width )
			continue;

		// draw the column background
		teamcolor[3] = SCB_BACKGROUND_ALPHA;
		if( columncount & 1 )
			teamcolor[3] -= 0.15;

		if( highlight )
			teamcolor[3] += 0.3;

		if( trans )
			color[3] = 0.3;

		if( !pass ) {
			trap_R_DrawStretchPic( x + xoffset, y + yoffset, width, height, 0, 0, 1, 1, teamcolor, cgs.shaderWhite );

			if( icon )
				SCR_AddPlayerIcon( icon, x + xoffset, y + yoffset, color[3], font );
		}

		// draw the column value
		if( pass && string[0] )
		{
			trap_SCR_DrawClampString( x + xoffset, y + yoffset, string,
				x + xoffset, y + yoffset,
				x + xoffset + width, y + yoffset + height, font, color );
		}

		columncount++;

		xoffset += width;
	}

	yoffset += height;
	return yoffset;
}
Ejemplo n.º 6
0
/*
* SCR_DrawTeamTab
*/
static int SCR_DrawTeamTab( const char **ptrptr, int *curteam, int x, int y, int panelWidth, struct qfontface_s *font, struct qfontface_s *titleFont, int pass )
{
	const char *token;
	const char *layout, *titles;
	char type;
	int team, team_score, team_ping;
	int yoffset = 0, xoffset = 0;
	int dir = 0, align, width, height;
	vec4_t teamcolor = { 0.0f, 0.0f, 0.0f, 1.0f }, pingcolor;

	// team tab is always the same. Sets the current team and draws its score

	if( !(*ptrptr) || !(*ptrptr[0]) || *ptrptr[0] == '&' )
		return yoffset;

	team = CG_ParseValue( ptrptr );
	if( team < TEAM_PLAYERS || team > TEAM_BETA )
		CG_Error( "SCR_ParseTeamTab: Invalid team value\n" );

	*curteam = team;

	if( *ptrptr[0] == '&' )
		return yoffset;

	team_score = CG_ParseValue( ptrptr );

	if( *ptrptr[0] == '&' )
		return yoffset;

	team_ping = CG_ParseValue( ptrptr );

	if( ( team == TEAM_ALPHA ) || ( team == TEAM_BETA ) )
		CG_TeamColor( team, teamcolor );
	teamcolor[3] = SCB_BACKGROUND_ALPHA; // make transparent

	if( GS_TeamBasedGametype() ) // we only draw the team tabs in team based gametypes
	{
		dir = ( team == TEAM_ALPHA ) ? -1 : 1;
		align = ( team == TEAM_ALPHA ) ? ALIGN_RIGHT_TOP : ALIGN_LEFT_TOP;

		// draw the tab

		xoffset = ( SCB_CENTERMARGIN * dir );

		width = ( cgs.vidWidth * 0.5 ) - SCB_CENTERMARGIN;
		height = trap_SCR_FontHeight( titleFont ) + 2;

		if( !pass ) {
			CG_DrawAlignPic( x + xoffset, y + yoffset + SCB_SCORENUMBER_SIZE - height,
				width, height, align, teamcolor, cgs.shaderWhite );
		}

		if( pass ) {
			xoffset += ( ( 16 * cgs.vidHeight / 600 ) * dir );

			CG_DrawHUDNumeric( x + xoffset, y + yoffset, align, colorWhite,
				SCB_SCORENUMBER_SIZE, SCB_SCORENUMBER_SIZE, team_score );

			xoffset += ( ( SCB_SCORENUMBER_SIZE * strlen(va("%i", team_score)) + ( 16 * cgs.vidHeight / 600 ) ) * dir );
			trap_SCR_DrawStringWidth( x + xoffset + ( ( SCB_TINYFIELD_PIXELWIDTH + ( 16 * cgs.vidHeight / 600 ) ) * dir ),
				y + yoffset + SCB_SCORENUMBER_SIZE - (trap_SCR_FontHeight( titleFont ) + 1),
				align, GS_TeamName( team ), SCB_TEAMNAME_PIXELWIDTH, titleFont, colorWhite );

			CG_PingColor( team_ping, pingcolor );
			trap_SCR_DrawStringWidth( x + xoffset,
				y + yoffset + SCB_SCORENUMBER_SIZE - (trap_SCR_FontHeight( font ) + 1),
				align, va( "%i", team_ping ), SCB_TINYFIELD_PIXELWIDTH, font, pingcolor );
		}

		yoffset += SCB_SCORENUMBER_SIZE;
	}
	else
	{
		dir = 0;
		align = ALIGN_CENTER_TOP;
	}

	// draw the player tab column titles
	layout = cgs.configStrings[CS_SCB_PLAYERTAB_LAYOUT];
	titles = cgs.configStrings[CS_SCB_PLAYERTAB_TITLES];

	height = trap_SCR_FontHeight( font );

	// start from the center again
	xoffset = CG_HorizontalAlignForWidth( 0, align, panelWidth );
	xoffset += ( SCB_CENTERMARGIN * dir );

	while( ( token = SCR_GetNextColumnLayout( &layout, &titles, &type, &width, font ) ) != NULL )
	{
		if( SCR_SkipColumn( type ) )
			continue;

		if( width )
		{
			if( pass ) {
				trap_SCR_DrawClampString( x + xoffset, y + yoffset, CG_TranslateString( token ),
					x + xoffset, y + yoffset, x + xoffset + width, y + yoffset + height, font, colorWhite );
			}
			xoffset += width;
		}
	}

	yoffset += trap_SCR_FontHeight( font );

	return yoffset;
}
Ejemplo n.º 7
0
/*
* SCR_DrawSpectators
*/
static int SCR_DrawSpectators( const char **ptrptr, int x, int y, int panelWidth, struct qfontface_s *font, bool havePing, const char *title, vec4_t titleColor, int pass )
{
	const char *token;
	char string[MAX_STRING_CHARS];
	int yoffset = 0, xoffset = 0;
	int playerNum, ping;
	int aligns[3], offsets[3];
	int colwidth, fullwidth, count = 0, height;
	bool titleDrawn = false;

	fullwidth = panelWidth * 1.5;
	if( fullwidth > cgs.vidWidth * 0.7 )
		fullwidth = cgs.vidWidth * 0.7;
	colwidth = fullwidth / 3;

	aligns[0] = ALIGN_CENTER_TOP;
	aligns[1] = ALIGN_LEFT_TOP;
	aligns[2] = ALIGN_RIGHT_TOP;

	offsets[0] = 0;
	offsets[1] = -fullwidth * 0.5;
	offsets[2] = fullwidth * 0.5;

	assert( ptrptr && *ptrptr );

	height = trap_SCR_FontHeight( font );
	yoffset = height;

	// draw spectators
	while( *ptrptr )
	{
		if( !SCR_ParseToken( ptrptr, &token ) )
			break;

		// first token is played id
		playerNum = atoi( token );
		if( playerNum < 0 || playerNum >= gs.maxclients )
			break;

		if( havePing )
		{
			// get a second token
			if( !SCR_ParseToken( ptrptr, &token ) )
				break;

			// second token is ping
			ping = atoi( token );

			// draw the spectator
			if( ping < 0 )
				Q_snprintfz( string, sizeof( string ), "%s%s ...", cgs.clientInfo[playerNum].name, S_COLOR_WHITE );
			else
				Q_snprintfz( string, sizeof( string ), "%s%s %i", cgs.clientInfo[playerNum].name, S_COLOR_WHITE, ping );
		}
		else
		{
			Q_snprintfz( string, sizeof( string ), "%s%s", cgs.clientInfo[playerNum].name, S_COLOR_WHITE );
		}

		// draw title if there are any spectators
		if( !titleDrawn )
		{
			titleDrawn = true;
			if( pass ) {
				trap_SCR_DrawString( x, y + yoffset, ALIGN_CENTER_TOP,
					CG_TranslateString( title ), font, titleColor );
			}
			yoffset += height;
		}

		xoffset = offsets[count] + CG_HorizontalAlignForWidth( 0, aligns[count], trap_SCR_strWidth( string, font, 0 ) );

		if ( pass ) {
			// fixme: the boxes aren't actually correctly aligned
			trap_SCR_DrawClampString( x + xoffset, y + yoffset, string, x + xoffset, y + yoffset, x + xoffset + colwidth, y + yoffset + height, font, colorWhite );
		}

		count++;
		if( count > 2 )
		{
			count = 0;
			yoffset += height;
		}
	}

	if( count )
		yoffset += height;
	return yoffset;
}
Ejemplo n.º 8
0
/*
* SCB_DrawPlayerStats
*/
static int SCB_DrawPlayerStats( int x, int y, struct qfontface_s *font )
{
	int xoffset, yoffset, lines;
	int i, j, num_weapons, weap, xpos, width, done;
	gsitem_t *it;
	char string[MAX_STRING_CHARS];
	vec4_t color = { 0.5, 0.5, 0.5, 0.5f };

	// don't display stats
	if( !cg_scoreboardStats->integer )
		return 0;

	// total number of weapon
	num_weapons = WEAP_TOTAL-WEAP_GUNBLADE;

	width = ( SCB_TINYFIELD_PIXELWIDTH + 2 * SCB_SMALLFIELD_PIXELWIDTH ) * 2 + SCB_SMALLFIELD_PIXELWIDTH;

	xpos = -width / 2;

	// Center the box
	xoffset = xpos;
	yoffset = trap_SCR_FontHeight( font );

	// Room for header, it's actually written later if we have at least one stat
	yoffset += trap_SCR_FontHeight( font );

	lines = 0;
	for( i = 0; i < num_weapons; )
	{
		xoffset = xpos;

		// two weapons per line
		for( j = 0, done = 0; done < 2 && i + j < num_weapons; j++ )
		{
			weap = WEAP_GUNBLADE + i + j;

			if( scb_player_stats[2*( i+j )] == -1 && scb_player_stats[2*( i+j )+1] == -1 )
				continue;

			it = GS_FindItemByTag( weap );

			// short name
			Q_snprintfz( string, sizeof( string ), "%s%2s", it->color, it->shortname );
			trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, string, SCB_TINYFIELD_PIXELWIDTH, font, colorWhite );

			Q_snprintfz( string, sizeof( string ), "%2d%c", scb_player_stats[2*( i+j )+1], '%' );
			trap_SCR_DrawStringWidth( x + xoffset + 2 * SCB_TINYFIELD_PIXELWIDTH, y + yoffset, ALIGN_CENTER_TOP, string, 2*SCB_SMALLFIELD_PIXELWIDTH, font, colorWhite );

			// separator
			xoffset = 0;
			done++;
		}

		// next line
		if( done > 0 )
		{
			lines++;
			yoffset += trap_SCR_FontHeight( font );
		}

		i += j;
	}

	if( lines )
	{
		// if we drew anything, draw header and box too
		xoffset = xpos;
		yoffset = trap_SCR_FontHeight( font );

		// header
		trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, 
			CG_TranslateString( "Weapon stats" ), width, font, colorMdGrey );
		yoffset += trap_SCR_FontHeight( font );

		// box
		trap_R_DrawStretchPic( x + xoffset - SCB_TINYFIELD_PIXELWIDTH/2, y + yoffset, width + SCB_TINYFIELD_PIXELWIDTH,
			lines * trap_SCR_FontHeight( font ), 0, 0, 1, 1, color, cgs.shaderWhite );

		return ( trap_SCR_FontHeight( font ) * ( 2+lines ) );
	}

	return 0;
}
Ejemplo n.º 9
0
/*
** CG_DrawChat
*/
void CG_DrawChat( cg_gamechat_t *chat, int x, int y, char *fontName, struct qfontface_s *font, int fontSize,
				  int width, int height, int padding_x, int padding_y, vec4_t backColor, struct shader_s *backShader ) {
	int i, j;
	int s, e, w;
	int utf_len;
	int l, total_lines, lines;
	int x_offset, y_offset;
	int font_height;
	int pass;
	int lastcolor;
	int message_mode;
	int wait_time, fade_time;
	const cg_gamemessage_t *msg;
	const char *text;
	char tstr[GAMECHAT_STRING_SIZE];
	vec4_t fontColor;
	bool chat_active = false;
	bool background_drawn = false;
	int corner_radius = 12 * cgs.vidHeight / 600;
	int background_y;
	int first_candidate;

	font_height = trap_SCR_FontHeight( font );
	message_mode = (int)trap_Cvar_Value( "con_messageMode" );
	chat_active = ( chat->lastMsgTime + GAMECHAT_WAIT_IN_TIME + GAMECHAT_FADE_IN_TIME > cg.realTime || message_mode );
	lines = 0;
	total_lines = /*!message_mode ? 0 : */ 1;

	if( chat_active ) {
		wait_time = GAMECHAT_WAIT_IN_TIME;
		fade_time = GAMECHAT_FADE_IN_TIME;
	} else {
		wait_time = GAMECHAT_WAIT_OUT_TIME;
		fade_time = GAMECHAT_FADE_OUT_TIME;
	}

	if( chat_active != chat->lastActive ) {
		// smooth fade ins and fade outs
		chat->lastActiveChangeTime = cg.realTime - ( 1.0 - chat->activeFrac ) * ( wait_time + fade_time );
	}

	if( cg.realTime >= chat->lastActiveChangeTime + wait_time ) {
		int time_diff, time_interval;

		time_diff = cg.realTime - ( chat->lastActiveChangeTime + wait_time );
		time_interval = fade_time;

		if( time_diff <= time_interval ) {
			chat->activeFrac = (float)time_diff / time_interval;
		} else {
			chat->activeFrac = 1;
		}
	} else {
		chat->activeFrac = 0;
	}

	if( chat_active ) {
		backColor[3] *= chat->activeFrac;
	} else {
		backColor[3] *= ( 1.0 - chat->activeFrac );
	}

	for( i = 0; i < GAMECHAT_STACK_SIZE; i++ ) {
		bool old_msg;

		l = chat->nextMsg - 1 - i;
		if( l < 0 ) {
			l = GAMECHAT_STACK_SIZE + l;
		}

		msg = &chat->messages[l];
		text = msg->text;
		old_msg = !message_mode && ( cg.realTime > msg->time + GAMECHAT_NOTIFY_TIME );

		if( !background_drawn && backColor[3] ) {
			if( old_msg ) {
				// keep the box being drawn for a while to prevent it from flickering
				// upon arrival of the possibly entered chat message
				if( !( !chat_active && cg.realTime <= chat->lastActiveChangeTime + 200 ) ) {
					break;
				}
			}

			background_y = y;
			trap_R_DrawStretchPic( x, background_y, width, height - corner_radius,
								   0.0f, 0.0f, 1.0f, 0.5f, backColor, backShader );
			background_y += height - corner_radius;

			if( trap_IN_IME_GetCandidates( NULL, 0, 10, NULL, &first_candidate ) ) {
				int candidates_height = ( first_candidate ? 3 : 5 ) * font_height;
				trap_R_DrawStretchPic( x, background_y, width, candidates_height,
									   0.0f, 0.5f, 1.0f, 0.5f, backColor, backShader );
				background_y += candidates_height;
			}

			trap_R_DrawStretchPic( x, background_y, corner_radius, corner_radius,
								   0.0f, 0.5f, 0.5f, 1.0f, backColor, backShader );
			trap_R_DrawStretchPic( x + corner_radius, background_y, width - corner_radius * 2, corner_radius,
								   0.5f, 0.5f, 0.5f, 1.0f, backColor, backShader );
			trap_R_DrawStretchPic( x + width - corner_radius, background_y, corner_radius, corner_radius,
								   0.5f, 0.5f, 1.0f, 1.0f, backColor, backShader );

			background_drawn = true;
		}

		// unless user is typing something, only display recent messages
		if( old_msg ) {
			break;
		}

		pass = 0;
		lines = 0;
		lastcolor = ColorIndex( COLOR_WHITE );

parse_string:
		l = 1;
		s = e = 0;
		while( 1 ) {
			int len;

			memset( tstr, 0, sizeof( tstr ) );

			// skip whitespaces at start
			for( ; text[s] == '\n' || Q_IsBreakingSpace( text + s ); s = Q_Utf8SyncPos( text, s + 1, UTF8SYNC_RIGHT ) ) ;

			// empty string
			if( !text[s] ) {
				break;
			}

			w = -1;
			len = trap_SCR_StrlenForWidth( text + s, font, width - padding_x * 2 );
			clamp_low( len, 1 );

			for( j = s; ( j < ( s + len ) ) && text[j] != '\0'; j += utf_len ) {
				utf_len = Q_Utf8SyncPos( text + j, 1, UTF8SYNC_RIGHT );
				memcpy( tstr + j - s, text + j, utf_len );

				if( text[j] == '\n' || Q_IsBreakingSpace( text + j ) ) {
					w = j; // last whitespace
				}
				if( text[j] == '\n' ) {
					break;
				}
			}
			e = j; // end

			// try to word avoid splitting words, unless no other options
			if( text[j] != '\0' && w > 0 ) {
				// stop at the last encountered whitespace
				j = w;
			}

			tstr[j - s] = '\0';

			Vector4Copy( color_table[lastcolor], fontColor );
			fontColor[3] = chat_active ? chat->activeFrac : 1.0 - chat->activeFrac;

			if( pass ) {
				// now actually render the line
				x_offset = padding_x;
				y_offset = height - padding_y - font_height - ( total_lines + lines - l ) * ( font_height + 2 );
				if( y_offset < padding_y ) {
					break;
				}

				trap_SCR_DrawClampString( x + x_offset, y + y_offset, tstr,
										  x + padding_x, y + padding_y, x - padding_x + width, y - padding_y + height, font, fontColor );

				l++;
			} else {
				// increase the lines counter
				lines++;
			}

			if( !text[j] ) {
				// fast path: we don't need two passes in case of one-liners..
				if( lines == 1 ) {
					x_offset = padding_x;
					y_offset = height - font_height - total_lines * ( font_height + 2 );
					if( y_offset < padding_y ) {
						break;
					}

					trap_SCR_DrawClampString( x + x_offset, y + y_offset, tstr,
											  x + padding_x, y + padding_y, x - padding_x + width, y - padding_y + height, font, fontColor );

					total_lines++;
					pass++;
				}
				break;
			}

			if( pass ) {
				// grab the last color token to carry it over to the next line
				lastcolor = Q_ColorStrLastColor( lastcolor, tstr, j - s );
			}

			s = j;
		}

		if( !pass ) {
			pass++;
			goto parse_string;
		} else {
			total_lines += lines;
		}
	}

	// let the engine know where the input line should be drawn
	trap_SCR_DrawChat( x + padding_x, y + height - padding_y - font_height, width - padding_x, font );

	chat->lastActive = chat_active;
}
Ejemplo n.º 10
0
/*
* CG_DrawDemocam2D
*/
void CG_DrawDemocam2D( void ) {
	int xpos, ypos;
	const char *cam_type_name;
	int64_t cam_timestamp;
	char sfov[8], strack[8];
	cg_subtitle_t *sub;

	if( !cgs.demoPlaying ) {
		return;
	}

	if( ( sub = CG_Democam_FindCurrentSubtitle() ) != NULL ) {
		if( sub->text && sub->text[0] ) {
			int y;

			if( sub->highprint ) {
				y = cgs.vidHeight * 0.30f;
			} else {
				y = cgs.vidHeight - ( cgs.vidHeight * 0.30f );
			}

			CG_Democam_DrawCenterSubtitle( y, cgs.vidWidth * 0.75, cgs.fontSystemBig, sub->text );
		}
	}

	if( democam_editing_mode ) {
		// draw the numbers of every entity in the view
		CG_DrawEntityNumbers();

		// draw the cams info
		xpos = 8 * cgs.vidHeight / 600;
		ypos = 100 * cgs.vidHeight / 600;

		if( *cgs.demoName ) {
			trap_SCR_DrawString( xpos, ypos, ALIGN_LEFT_TOP, va( "Demo: %s", cgs.demoName ), cgs.fontSystemSmall, colorWhite );
			ypos += trap_SCR_FontHeight( cgs.fontSystemSmall );
		}

		trap_SCR_DrawString( xpos, ypos, ALIGN_LEFT_TOP, va( "Play mode: %s%s%s", S_COLOR_ORANGE, CamIsFree ? "Free Fly" : "Preview", S_COLOR_WHITE ), cgs.fontSystemSmall, colorWhite );
		ypos += trap_SCR_FontHeight( cgs.fontSystemSmall );

		trap_SCR_DrawString( xpos, ypos, ALIGN_LEFT_TOP, va( "Time: %" PRIi64, demo_time ), cgs.fontSystemSmall, colorWhite );
		ypos += trap_SCR_FontHeight( cgs.fontSystemSmall );

		cam_type_name = "none";
		cam_timestamp = 0;

		if( currentcam ) {
			cam_type_name = cam_TypeNames[currentcam->type];
			cam_timestamp = currentcam->timeStamp;
			Q_snprintfz( strack, sizeof( strack ), "%i", currentcam->trackEnt );
			Q_snprintfz( sfov, sizeof( sfov ), "%i", currentcam->fov );
		} else {
			Q_strncpyz( strack, "NO", sizeof( strack ) );
			Q_strncpyz( sfov, "NO", sizeof( sfov ) );
		}

		trap_SCR_DrawString( xpos, ypos, ALIGN_LEFT_TOP, 
			va( "Current cam: " S_COLOR_ORANGE "%s" S_COLOR_WHITE " Fov " S_COLOR_ORANGE "%s" S_COLOR_WHITE " Start %" PRIi64 " Tracking " S_COLOR_ORANGE "%s" S_COLOR_WHITE,
															 cam_type_name, sfov, cam_timestamp, strack ),
							 cgs.fontSystemSmall, colorWhite );
		ypos += trap_SCR_FontHeight( cgs.fontSystemSmall );

		if( currentcam ) {
			trap_SCR_DrawString( xpos, ypos, ALIGN_LEFT_TOP, 
				va( "Pitch: " S_COLOR_ORANGE "%.2f" S_COLOR_WHITE " Yaw: " S_COLOR_ORANGE "%.2f" S_COLOR_WHITE " Roll: " S_COLOR_ORANGE "%.2f" S_COLOR_WHITE,
																 currentcam->angles[PITCH], currentcam->angles[YAW], currentcam->angles[ROLL] ),
								 cgs.fontSystemSmall, colorWhite );
		}
		ypos += trap_SCR_FontHeight( cgs.fontSystemSmall );

		cam_type_name = "none";
		cam_timestamp = 0;
		Q_strncpyz( sfov, "NO", sizeof( sfov ) );
		if( nextcam ) {
			cam_type_name = cam_TypeNames[nextcam->type];
			cam_timestamp = nextcam->timeStamp;
			Q_snprintfz( strack, sizeof( strack ), "%i", nextcam->trackEnt );
			Q_snprintfz( sfov, sizeof( sfov ), "%i", nextcam->fov );
		} else {
			Q_strncpyz( strack, "NO", sizeof( strack ) );
			Q_strncpyz( sfov, "NO", sizeof( sfov ) );
		}

		trap_SCR_DrawString( xpos, ypos, ALIGN_LEFT_TOP, 
			va( "Next cam: " S_COLOR_ORANGE "%s" S_COLOR_WHITE " Fov " S_COLOR_ORANGE "%s" S_COLOR_WHITE " Start %" PRIi64 " Tracking " S_COLOR_ORANGE "%s" S_COLOR_WHITE,
															 cam_type_name, sfov, cam_timestamp, strack ),
							 cgs.fontSystemSmall, colorWhite );
		ypos += trap_SCR_FontHeight( cgs.fontSystemSmall );

		if( nextcam ) {
			trap_SCR_DrawString( xpos, ypos, ALIGN_LEFT_TOP, 
				va( "Pitch: " S_COLOR_ORANGE "%.2f" S_COLOR_WHITE " Yaw: " S_COLOR_ORANGE "%.2f" S_COLOR_WHITE " Roll: " S_COLOR_ORANGE "%.2f" S_COLOR_WHITE,
																 nextcam->angles[PITCH], nextcam->angles[YAW], nextcam->angles[ROLL] ),
								 cgs.fontSystemSmall, colorWhite );
		}
		ypos += trap_SCR_FontHeight( cgs.fontSystemSmall );
	}
}
Ejemplo n.º 11
0
void CG_Democam_DrawCenterSubtitle( int y, unsigned int maxwidth, struct qfontface_s *font, char *text ) {
	char *ptr, *s, *t, c, d;
	int x = cgs.vidWidth / 2;

	if( !text || !text[0] ) {
		return;
	}

	int shadowOffset = 2 * cgs.vidHeight / 600;
	if( !shadowOffset ) {
		shadowOffset = 1;
	}

	if( !maxwidth || trap_SCR_strWidth( text, font, 0 ) <= maxwidth ) {
		trap_SCR_DrawStringWidth( x + shadowOffset, y + shadowOffset, ALIGN_CENTER_TOP, COM_RemoveColorTokens( text ), maxwidth, font, colorBlack );
		trap_SCR_DrawStringWidth( x, y, ALIGN_CENTER_TOP, text, maxwidth, font, colorWhite );
		return;
	}

	t = s = ptr = text;
	while( *s ) {
		while( *s && *s != ' ' && *s != '\n' )
			s++;

		if( ( !*s || *s == '\n' ) && trap_SCR_strWidth( ptr, font, 0 ) < maxwidth ) { // new line or end of text, in both cases force write
			c = *s;
			*s = 0;
			trap_SCR_DrawStringWidth( x + shadowOffset, y + shadowOffset, ALIGN_CENTER_TOP, COM_RemoveColorTokens( ptr ), maxwidth, font, colorBlack );
			trap_SCR_DrawStringWidth( x, y, ALIGN_CENTER_TOP, ptr, maxwidth, font, colorWhite );
			*s = c;

			if( !*s ) {
				break;
			}

			t = s;
			s++;
			ptr = s;
		} else {
			c = *s;
			*s = 0;

			if( trap_SCR_strWidth( ptr, font, 0 ) < maxwidth ) {
				*s = c;
				t = s;
				s++;
				continue;
			}

			*s = c;
			d = *t;
			*t = 0;
			trap_SCR_DrawStringWidth( x + shadowOffset, y + shadowOffset, ALIGN_CENTER_TOP, COM_RemoveColorTokens( ptr ), maxwidth, font, colorBlack );
			trap_SCR_DrawStringWidth( x, y, ALIGN_CENTER_TOP, ptr, maxwidth, font, colorWhite );
			*t = d;
			s = t;
			s++;
			ptr = s;
		}

		y += trap_SCR_FontHeight( font );
	}
}
Ejemplo n.º 12
0
/*
* SCR_DrawChallengers
*/
static int SCR_DrawChallengers( const char **ptrptr, int x, int y, int panelWidth, struct qfontface_s *font, int pass )
{
	char *token;
	const char *oldptr;
	char string[MAX_STRING_CHARS];
	int yoffset = 0, xoffset = 0;
	int playerNum, ping;
	int height;

	assert( ptrptr && *ptrptr );

	height = trap_SCR_FontHeight( font );

	// draw title
	yoffset = height;
	if( pass ) {
		trap_SCR_DrawString( x + xoffset, y + yoffset, ALIGN_CENTER_TOP,
			CG_TranslateString( "Spectating you" ), font, colorCyan ); // racesow
	}
	yoffset += height;

	// draw challengers
	while( *ptrptr )
	{
		oldptr = *ptrptr;
		token = COM_ParseExt( ptrptr, true );
		if( !token[0] )
			break;

		if( token[0] == '&' ) // it's a different command than 'challengers', so step back and return
		{
			*ptrptr = oldptr;
			break;
		}

		// first token is played id
		playerNum = atoi( token );
		if( playerNum < 0 || playerNum >= gs.maxclients )
			break;

		// get a second token
		oldptr = *ptrptr;
		token = COM_ParseExt( ptrptr, true );
		if( !token[0] )
			break;

		if( token[0] == '&' ) // it's a different command than 'challengers', so step back and return
		{
			*ptrptr = oldptr;
			break;
		}

		// second token is ping
		ping = atoi( token );

		// draw the challenger
		if( ping < 0 )
			Q_snprintfz( string, sizeof( string ), "%s%s ...", cgs.clientInfo[playerNum].name, S_COLOR_WHITE );
		else
			Q_snprintfz( string, sizeof( string ), "%s%s %i", cgs.clientInfo[playerNum].name, S_COLOR_WHITE, ping );

		if( pass ) {
			trap_SCR_DrawString( x + xoffset, y + yoffset, ALIGN_CENTER_TOP, string, font, colorWhite );
		}
		yoffset += height;
	}

	yoffset += height;
	return yoffset;
}