diff options
author | Tony J. White <tjw@tjw.org> | 2009-10-03 11:45:20 +0000 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2013-01-03 00:15:18 +0000 |
commit | 412d3c9c3479012d687139f891d14cfe18b6e6ee (patch) | |
tree | c8ca701ac8e4ef8cac3a35fbe8460b058e25bbda | |
parent | a60e24850d73f8d807bab40f256a3e017219f17e (diff) |
* UI_Text_* emoticon drawing support (e.g. [dretch] draws
/emoticons/dretch.tga inline with text)
* emoticons are square .tga images placed in the /emoticons dir of fs_game
* emoticons should probably be 64x64 to look nice
* g_emoticonsAllowedInNames (default ON) is an optional server setting to
prevent players from using them in names
* emoticons can be escaped by prefixing with an additional [
* cvars ui_emoticons and cg_emoticons can be set to 0 to disable drawing
of emoticons in ui or cgame contexts respectively
* fix color code continuation on wrapped lines
* prefix all wrapped lines with a space to prevent chat shenanigans
-rw-r--r-- | src/cgame/cg_local.h | 2 | ||||
-rw-r--r-- | src/cgame/cg_main.c | 19 | ||||
-rw-r--r-- | src/game/bg_misc.c | 61 | ||||
-rw-r--r-- | src/game/bg_public.h | 1 | ||||
-rw-r--r-- | src/game/g_client.c | 57 | ||||
-rw-r--r-- | src/game/g_local.h | 5 | ||||
-rw-r--r-- | src/game/g_main.c | 6 | ||||
-rw-r--r-- | src/qcommon/q_shared.h | 3 | ||||
-rw-r--r-- | src/ui/ui_main.c | 16 | ||||
-rw-r--r-- | src/ui/ui_shared.c | 353 | ||||
-rw-r--r-- | src/ui/ui_shared.h | 4 |
11 files changed, 412 insertions, 115 deletions
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index f090e928..9bdcb3b9 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -1533,6 +1533,8 @@ extern vmCvar_t cg_projectileNudge; extern vmCvar_t cg_voice; +extern vmCvar_t cg_emoticons; + // // cg_main.c // diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c index b239236d..9a40a5c3 100644 --- a/src/cgame/cg_main.c +++ b/src/cgame/cg_main.c @@ -214,6 +214,8 @@ vmCvar_t cg_projectileNudge; vmCvar_t cg_voice; +vmCvar_t cg_emoticons; + typedef struct { @@ -336,7 +338,9 @@ static cvarTable_t cvarTable[ ] = { &pmove_msec, "pmove_msec", "8", 0}, { &cg_noTaunt, "cg_noTaunt", "0", CVAR_ARCHIVE}, - { &cg_voice, "voice", "default", CVAR_USERINFO|CVAR_ARCHIVE} + { &cg_voice, "voice", "default", CVAR_USERINFO|CVAR_ARCHIVE}, + + { &cg_emoticons, "cg_emoticons", "1", CVAR_LATCH|CVAR_ARCHIVE} }; static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] ); @@ -1663,6 +1667,8 @@ void CG_LoadHudMenu( void ) void CG_AssetCache( void ) { + int i; + cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR ); cgDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR ); cgDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN ); @@ -1672,6 +1678,17 @@ void CG_AssetCache( void ) cgDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB ); cgDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR ); cgDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB ); + + if( cg_emoticons.integer ) + cgDC.Assets.emoticonCount = BG_LoadEmoticons( cgDC.Assets.emoticons ); + else + cgDC.Assets.emoticonCount = 0; + + for( i = 0; i < cgDC.Assets.emoticonCount; i++ ) + { + cgDC.Assets.emoticonShaders[ i ] = trap_R_RegisterShaderNoMip( + va( "emoticons/%s.tga", cgDC.Assets.emoticons[ i ] ) ); + } } /* diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c index 9f8ce9e4..244ee482 100644 --- a/src/game/bg_misc.c +++ b/src/game/bg_misc.c @@ -31,6 +31,7 @@ void trap_FS_Read( void *buffer, int len, fileHandle_t f ); void trap_FS_Write( const void *buffer, int len, fileHandle_t f ); void trap_FS_FCloseFile( fileHandle_t f ); void trap_FS_Seek( fileHandle_t f, long offset, fsOrigin_t origin ); // fsOrigin_t +int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ); static const buildableAttributes_t bg_buildableList[ ] = { @@ -3855,3 +3856,63 @@ weapon_t BG_PrimaryWeapon( int stats[ ] ) return WP_NONE; } +/* +============ +BG_LoadEmoticons +============ +*/ +int BG_LoadEmoticons( char names[ ][ MAX_EMOTICON_NAME_LEN ] ) +{ + int numFiles; + char fileList[ MAX_EMOTICONS * ( MAX_EMOTICON_NAME_LEN + 5 ) ] = {""}; + int i; + char *filePtr; + int fileLen; + char emoticon[ MAX_EMOTICON_NAME_LEN + 5 ] = {""}; + int loaded = 0; + int count; + + numFiles = trap_FS_GetFileList( "emoticons", ".tga", fileList, + sizeof( fileList ) ); + + if( numFiles < 1 ) + return 0; + + filePtr = fileList; + fileLen = 0; + count = 0; + for( i = 0; i < numFiles; i++, filePtr += fileLen + 1 ) + { + if( count >= MAX_EMOTICONS ) + { + count++; + continue; + } + + fileLen = strlen( filePtr ); + if( fileLen > MAX_EMOTICON_NAME_LEN + 5 ) + { + Com_Printf( S_COLOR_YELLOW "WARNING: MAX_EMOTICON_NAME_LEN is %d. " + "skipping \"%s\", filename too long", MAX_EMOTICON_NAME_LEN, filePtr ); + continue; + } + if( !trap_FS_FOpenFile( va( "emoticons/%s", filePtr ), NULL, FS_READ ) ) + { + Com_Printf( S_COLOR_YELLOW "WARNING: BG_LoadEmoticons(): detected " + " an unreadable .tga file name \"emoticons/%s\" in emoticon detection", + filePtr ); + break; + } + Q_strncpyz( emoticon, filePtr, sizeof( emoticon ) ); + emoticon[ fileLen - 4 ] = '\0'; + + Q_strncpyz( names[ count ], emoticon, sizeof( names[ count ] ) ); + count++; + loaded = count; + } + + Com_Printf( "Loaded %d of %d emoticons (MAX_EMOTICONS is %d)\n", + loaded, count, MAX_EMOTICONS ); + return loaded; +} + diff --git a/src/game/bg_public.h b/src/game/bg_public.h index 1e1c98ac..2a6f1874 100644 --- a/src/game/bg_public.h +++ b/src/game/bg_public.h @@ -1298,3 +1298,4 @@ voiceTrack_t *BG_VoiceTrackFind( voiceTrack_t *head, team_t team, class_t class, weapon_t weapon, int enthusiasm, int *trackNum ); +int BG_LoadEmoticons( char names[ ][ MAX_EMOTICON_NAME_LEN ] ); diff --git a/src/game/g_client.c b/src/game/g_client.c index 0e8051b8..4d674905 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -764,16 +764,54 @@ void respawn( gentity_t *ent ) } } +static qboolean G_IsEmoticon( const char *s, qboolean *escaped ) +{ + int i, j; + const char *p = s; + char emoticon[ MAX_EMOTICON_NAME_LEN ] = {""}; + qboolean escape = qfalse; + + if( *p != '[' ) + return qfalse; + p++; + if( *p == '[' ) + { + escape = qtrue; + p++; + } + i = 0; + while( *p && i < ( MAX_EMOTICON_NAME_LEN - 1 ) ) + { + if( *p == ']' ) + { + for( j = 0; j < level.emoticonCount; j++ ) + { + if( !Q_stricmp( emoticon, level.emoticons[ j ] ) ) + { + *escaped = escape; + return qtrue; + } + } + return qfalse; + } + emoticon[ i++ ] = *p; + emoticon[ i ] = '\0'; + p++; + } + return qfalse; +} + /* =========== -ClientCleanName +G_ClientCleanName ============ */ -static void ClientCleanName( const char *in, char *out, int outSize ) +static void G_ClientCleanName( const char *in, char *out, int outSize ) { int len, colorlessLen; char *p; int spaces; + qboolean escaped; //save room for trailing null byte outSize--; @@ -808,6 +846,19 @@ static void ClientCleanName( const char *in, char *out, int outSize ) len += 2; continue; } + else if( !g_emoticonsAllowedInNames.integer && G_IsEmoticon( in, &escaped ) ) + { + // make sure room in dest for both chars + if( len > outSize - 2 ) + break; + + *out++ = '['; + *out++ = '['; + len += 2; + if( escaped ) + in++; + continue; + } // don't allow too many consecutive spaces if( *in == ' ' ) @@ -942,7 +993,7 @@ void ClientUserinfoChanged( int clientNum ) // set name Q_strncpyz( oldname, client->pers.netname, sizeof( oldname ) ); s = Info_ValueForKey( userinfo, "name" ); - ClientCleanName( s, newname, sizeof( newname ) ); + G_ClientCleanName( s, newname, sizeof( newname ) ); if( strcmp( oldname, newname ) ) { diff --git a/src/game/g_local.h b/src/game/g_local.h index db15d208..05f1fe21 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -619,6 +619,9 @@ typedef struct team_t surrenderTeam; voice_t *voices; + + char emoticons[ MAX_EMOTICONS ][ MAX_EMOTICON_NAME_LEN ]; + int emoticonCount; } level_locals_t; #define CMD_CHEAT 0x01 @@ -1142,6 +1145,8 @@ extern vmCvar_t g_mapConfigs; extern vmCvar_t g_layouts; extern vmCvar_t g_layoutAuto; +extern vmCvar_t g_emoticonsAllowedInNames; + extern vmCvar_t g_admin; extern vmCvar_t g_adminLog; extern vmCvar_t g_adminParseSay; diff --git a/src/game/g_main.c b/src/game/g_main.c index 34793cb2..e3db3c23 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -124,6 +124,8 @@ vmCvar_t g_chatTeamPrefix; vmCvar_t g_layouts; vmCvar_t g_layoutAuto; +vmCvar_t g_emoticonsAllowedInNames; + vmCvar_t g_admin; vmCvar_t g_adminLog; vmCvar_t g_adminParseSay; @@ -244,6 +246,8 @@ static cvarTable_t gameCvarTable[ ] = { &g_layouts, "g_layouts", "", CVAR_LATCH, 0, qfalse }, { &g_layoutAuto, "g_layoutAuto", "1", CVAR_ARCHIVE, 0, qfalse }, + + { &g_emoticonsAllowedInNames, "g_emoticonsAllowedInNames", "1", CVAR_LATCH|CVAR_ARCHIVE, 0, qfalse }, { &g_admin, "g_admin", "admin.dat", CVAR_ARCHIVE, 0, qfalse }, { &g_adminLog, "g_adminLog", "admin.log", CVAR_ARCHIVE, 0, qfalse }, @@ -603,6 +607,8 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ), &level.clients[ 0 ].ps, sizeof( level.clients[ 0 ] ) ); + level.emoticonCount = BG_LoadEmoticons( level.emoticons ); + trap_SetConfigstring( CS_INTERMISSION, "0" ); // test to see if a custom buildable layout will be loaded diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h index 232982f5..84e2c2b4 100644 --- a/src/qcommon/q_shared.h +++ b/src/qcommon/q_shared.h @@ -1326,4 +1326,7 @@ typedef enum { #define SAY_TEAM 1 #define SAY_TELL 2 +#define MAX_EMOTICON_NAME_LEN 16 +#define MAX_EMOTICONS 64 + #endif // __Q_SHARED_H diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c index d8389c66..8d18372d 100644 --- a/src/ui/ui_main.c +++ b/src/ui/ui_main.c @@ -98,6 +98,8 @@ vmCvar_t ui_developer; vmCvar_t ui_winner; +vmCvar_t ui_emoticons; + static cvarTable_t cvarTable[ ] = { { &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE }, @@ -120,6 +122,7 @@ static cvarTable_t cvarTable[ ] = { &ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE}, { &ui_textWrapCache, "ui_textWrapCache", "1", CVAR_ARCHIVE }, { &ui_developer, "ui_developer", "0", CVAR_ARCHIVE | CVAR_CHEAT }, + { &ui_emoticons, "ui_emoticons", "1", CVAR_LATCH | CVAR_ARCHIVE }, }; static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] ); @@ -190,6 +193,8 @@ intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, void AssetCache( void ) { + int i; + uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR ); uiInfo.uiDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR ); uiInfo.uiDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN ); @@ -199,6 +204,17 @@ void AssetCache( void ) uiInfo.uiDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB ); uiInfo.uiDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR ); uiInfo.uiDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB ); + + if( ui_emoticons.integer ) + uiInfo.uiDC.Assets.emoticonCount = BG_LoadEmoticons( uiInfo.uiDC.Assets.emoticons ); + else + uiInfo.uiDC.Assets.emoticonCount = 0; + + for( i = 0; i < uiInfo.uiDC.Assets.emoticonCount; i++ ) + { + uiInfo.uiDC.Assets.emoticonShaders[ i ] = trap_R_RegisterShaderNoMip( + va( "emoticons/%s.tga", uiInfo.uiDC.Assets.emoticons[ i ] ) ); + } } void UI_DrawSides( float x, float y, float w, float h, float size ) diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index 84c31e4e..f2fe9b28 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -1834,6 +1834,53 @@ void Script_playLooped( itemDef_t *item, char **args ) } } +static qboolean UI_Text_Emoticon( const char *s, qboolean *escaped, int *length, qhandle_t *h ) +{ + char name[ MAX_EMOTICON_NAME_LEN ] = {""}; + const char *p = s; + int i = 0; + int j = 0; + + if( *p != '[' ) + return qfalse; + p++; + + *escaped = qfalse; + if( *p == '[' ) + { + *escaped = qtrue; + p++; + } + + while( *p && i < ( MAX_EMOTICON_NAME_LEN - 1 ) ) + { + if( *p == ']' ) + { + for( j = 0; j < DC->Assets.emoticonCount; j++ ) + { + if( !Q_stricmp( DC->Assets.emoticons[ j ], name ) ) + { + if( *escaped ) + { + *length = 1; + return qtrue; + } + if( h ) + *h = DC->Assets.emoticonShaders[ j ]; + *length = i + 2; + return qtrue; + } + } + return qfalse; + } + name[ i++ ] = *p; + name[ i ] = '\0'; + p++; + } + return qfalse; +} + + float UI_Text_Width( const char *text, float scale, int limit ) { int count, len; @@ -1842,6 +1889,10 @@ float UI_Text_Width( const char *text, float scale, int limit ) float useScale; const char *s = text; fontInfo_t *font = &DC->Assets.textFont; + int emoticonLen; + qboolean emoticonEscaped; + float emoticonWidth; + int emoticons = 0; if( scale <= DC->getCVarValue( "ui_smallFont" ) ) font = &DC->Assets.smallFont; @@ -1849,6 +1900,7 @@ float UI_Text_Width( const char *text, float scale, int limit ) font = &DC->Assets.bigFont; useScale = scale * font->glyphScale; + emoticonWidth = UI_Text_Height( "[", scale, 0 ) * DC->aspectScale; out = 0; if( text ) @@ -1862,22 +1914,33 @@ float UI_Text_Width( const char *text, float scale, int limit ) while( s && *s && count < len ) { + glyph = &font->glyphs[( int )*s]; + if( Q_IsColorString( s ) ) { s += 2; continue; } - else + else if ( UI_Text_Emoticon( s, &emoticonEscaped, &emoticonLen, NULL ) ) { - glyph = &font->glyphs[( int )*s]; - out += ( glyph->xSkip * DC->aspectScale ); - s++; - count++; + if( emoticonEscaped ) + { + s++; + } + else + { + s += emoticonLen; + emoticons++; + continue; + } } + out += ( glyph->xSkip * DC->aspectScale ); + s++; + count++; } } - return out * useScale; + return ( out * useScale ) + ( emoticons * emoticonWidth ); } float UI_Text_Height( const char *text, float scale, int limit ) @@ -1971,6 +2034,13 @@ void UI_Text_Paint_Limit( float *maxX, float x, float y, float scale, int len, count; vec4_t newColor; glyphInfo_t *glyph; + int emoticonLen = 0; + qhandle_t emoticonHandle = 0; + float emoticonH, emoticonW; + qboolean emoticonEscaped; + + emoticonH = UI_Text_Height( "[", scale, 0 ); + emoticonW = emoticonH * DC->aspectScale; if( text ) { @@ -1979,6 +2049,8 @@ void UI_Text_Paint_Limit( float *maxX, float x, float y, float scale, float useScale; fontInfo_t *font = &DC->Assets.textFont; + memcpy( &newColor[0], &color[0], sizeof( vec4_t ) ); + if( scale <= DC->getCVarValue( "ui_smallFont" ) ) font = &DC->Assets.smallFont; else if( scale > DC->getCVarValue( "ui_bigFont" ) ) @@ -1997,11 +2069,13 @@ void UI_Text_Paint_Limit( float *maxX, float x, float y, float scale, while( s && *s && count < len ) { - float width, height, skip; + float width, height, skip, yadj; + glyph = &font->glyphs[ ( int )*s ]; width = glyph->imageWidth * DC->aspectScale; height = glyph->imageHeight; skip = glyph->xSkip * DC->aspectScale; + yadj = useScale * glyph->top; if( Q_IsColorString( s ) ) { @@ -2011,30 +2085,42 @@ void UI_Text_Paint_Limit( float *maxX, float x, float y, float scale, s += 2; continue; } - else + else if( UI_Text_Emoticon( s, &emoticonEscaped, &emoticonLen, &emoticonHandle ) ) { - float yadj = useScale * glyph->top; - - if( UI_Text_Width( s, useScale, 1 ) + x > max ) + if( emoticonEscaped ) { - *maxX = 0; - break; + s++; } + else + { + s += emoticonLen; + DC->setColor( NULL ); + DC->drawHandlePic( x, y - yadj, emoticonW, emoticonH, emoticonHandle ); + DC->setColor( newColor ); + x += emoticonW; + continue; + } + } - UI_Text_PaintChar( x, y - yadj, - width, - height, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph ); - x += ( skip * useScale ) + adjust; - *maxX = x; - count++; - s++; + if( UI_Text_Width( s, useScale, 1 ) + x > max ) + { + *maxX = 0; + break; } + + UI_Text_PaintChar( x, y - yadj, + width, + height, + useScale, + glyph->s, + glyph->t, + glyph->s2, + glyph->t2, + glyph->glyph ); + x += ( skip * useScale ) + adjust; + *maxX = x; + count++; + s++; } DC->setColor( NULL ); @@ -2049,12 +2135,18 @@ void UI_Text_Paint( float x, float y, float scale, vec4_t color, const char *tex glyphInfo_t *glyph; float useScale; fontInfo_t *font = &DC->Assets.textFont; + int emoticonLen = 0; + qhandle_t emoticonHandle = 0; + float emoticonH, emoticonW; + qboolean emoticonEscaped; if( scale <= DC->getCVarValue( "ui_smallFont" ) ) font = &DC->Assets.smallFont; else if( scale >= DC->getCVarValue( "ui_bigFont" ) ) font = &DC->Assets.bigFont; + emoticonH = UI_Text_Height( "[", scale, 0 ); + emoticonW = emoticonH * DC->aspectScale; useScale = scale * font->glyphScale; if( text ) @@ -2071,11 +2163,13 @@ void UI_Text_Paint( float x, float y, float scale, vec4_t color, const char *tex while( s && *s && count < len ) { - float width, height, skip; + float width, height, skip, yadj; + glyph = &font->glyphs[( int )*s]; width = glyph->imageWidth * DC->aspectScale; height = glyph->imageHeight; skip = glyph->xSkip * DC->aspectScale; + yadj = useScale * glyph->top; if( Q_IsColorString( s ) ) { @@ -2085,85 +2179,29 @@ void UI_Text_Paint( float x, float y, float scale, vec4_t color, const char *tex s += 2; continue; } - else + else if( UI_Text_Emoticon( s, &emoticonEscaped, &emoticonLen, &emoticonHandle ) ) { - float yadj = useScale * glyph->top; - - if( style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE ) + if( emoticonEscaped ) { - int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2; - colorBlack[3] = newColor[3]; - DC->setColor( colorBlack ); - UI_Text_PaintChar( x + ofs, y - yadj + ofs, - width, - height, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph ); - DC->setColor( newColor ); - colorBlack[3] = 1.0; + s++; } - else if( style == ITEM_TEXTSTYLE_NEON ) + else { - vec4_t glow, outer, inner, white; - - glow[ 0 ] = newColor[ 0 ] * 0.5; - glow[ 1 ] = newColor[ 1 ] * 0.5; - glow[ 2 ] = newColor[ 2 ] * 0.5; - glow[ 3 ] = newColor[ 3 ] * 0.2; - - outer[ 0 ] = newColor[ 0 ]; - outer[ 1 ] = newColor[ 1 ]; - outer[ 2 ] = newColor[ 2 ]; - outer[ 3 ] = newColor[ 3 ]; - - inner[ 0 ] = newColor[ 0 ] * 1.5 > 1.0f ? 1.0f : newColor[ 0 ] * 1.5; - inner[ 1 ] = newColor[ 1 ] * 1.5 > 1.0f ? 1.0f : newColor[ 1 ] * 1.5; - inner[ 2 ] = newColor[ 2 ] * 1.5 > 1.0f ? 1.0f : newColor[ 2 ] * 1.5; - inner[ 3 ] = newColor[ 3 ]; - - white[ 0 ] = white[ 1 ] = white[ 2 ] = white[ 3 ] = 1.0f; - - DC->setColor( glow ); - UI_Text_PaintChar( x - 1.5, y - yadj - 1.5, - width + 3, - height + 3, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph ); - - DC->setColor( outer ); - UI_Text_PaintChar( x - 1, y - yadj - 1, - width + 2, - height + 2, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph ); - - DC->setColor( inner ); - UI_Text_PaintChar( x - 0.5, y - yadj - 0.5, - width + 1, - height + 1, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph ); - - DC->setColor( white ); + DC->setColor( NULL ); + DC->drawHandlePic( x, y - yadj, emoticonW, emoticonH, emoticonHandle ); + DC->setColor( newColor ); + x += emoticonW; + s += emoticonLen; + continue; } + } - UI_Text_PaintChar( x, y - yadj, + if( style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE ) + { + int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2; + colorBlack[3] = newColor[3]; + DC->setColor( colorBlack ); + UI_Text_PaintChar( x + ofs, y - yadj + ofs, width, height, useScale, @@ -2172,13 +2210,80 @@ void UI_Text_Paint( float x, float y, float scale, vec4_t color, const char *tex glyph->s2, glyph->t2, glyph->glyph ); + DC->setColor( newColor ); + colorBlack[3] = 1.0; + } + else if( style == ITEM_TEXTSTYLE_NEON ) + { + vec4_t glow, outer, inner, white; - x += ( skip * useScale ) + adjust; - s++; - count++; + glow[ 0 ] = newColor[ 0 ] * 0.5; + glow[ 1 ] = newColor[ 1 ] * 0.5; + glow[ 2 ] = newColor[ 2 ] * 0.5; + glow[ 3 ] = newColor[ 3 ] * 0.2; + + outer[ 0 ] = newColor[ 0 ]; + outer[ 1 ] = newColor[ 1 ]; + outer[ 2 ] = newColor[ 2 ]; + outer[ 3 ] = newColor[ 3 ]; + + inner[ 0 ] = newColor[ 0 ] * 1.5 > 1.0f ? 1.0f : newColor[ 0 ] * 1.5; + inner[ 1 ] = newColor[ 1 ] * 1.5 > 1.0f ? 1.0f : newColor[ 1 ] * 1.5; + inner[ 2 ] = newColor[ 2 ] * 1.5 > 1.0f ? 1.0f : newColor[ 2 ] * 1.5; + inner[ 3 ] = newColor[ 3 ]; + + white[ 0 ] = white[ 1 ] = white[ 2 ] = white[ 3 ] = 1.0f; + + DC->setColor( glow ); + UI_Text_PaintChar( x - 1.5, y - yadj - 1.5, + width + 3, + height + 3, + useScale, + glyph->s, + glyph->t, + glyph->s2, + glyph->t2, + glyph->glyph ); + + DC->setColor( outer ); + UI_Text_PaintChar( x - 1, y - yadj - 1, + width + 2, + height + 2, + useScale, + glyph->s, + glyph->t, + glyph->s2, + glyph->t2, + glyph->glyph ); + + DC->setColor( inner ); + UI_Text_PaintChar( x - 0.5, y - yadj - 0.5, + width + 1, + height + 1, + useScale, + glyph->s, + glyph->t, + glyph->s2, + glyph->t2, + glyph->glyph ); + + DC->setColor( white ); } - } + UI_Text_PaintChar( x, y - yadj, + width, + height, + useScale, + glyph->s, + glyph->t, + glyph->s2, + glyph->t2, + glyph->glyph ); + + x += ( skip * useScale ) + adjust; + s++; + count++; + } DC->setColor( NULL ); } } @@ -4433,6 +4538,8 @@ static const char *Item_Text_Wrap( const char *text, float scale, float width ) const char *q = NULL, *qMinus1 = NULL; unsigned int testLength; unsigned int i; + int emoticonLen; + qboolean emoticonEscaped; if( strlen( text ) >= sizeof( out ) ) return NULL; @@ -4469,12 +4576,20 @@ static const char *Item_Text_Wrap( const char *text, float scale, float width ) q = p; while( Q_IsColorString( q ) ) + { + c[ 0 ] = q[ 0 ]; + c[ 1 ] = q[ 1 ]; q += 2; + } q++; while( Q_IsColorString( q ) ) + { + c[ 0 ] = q[ 0 ]; + c[ 1 ] = q[ 1 ]; q += 2; + } while( UI_Text_Width( p, scale, testLength ) < width ) { @@ -4490,11 +4605,18 @@ static const char *Item_Text_Wrap( const char *text, float scale, float width ) for( i = 0; i < testLength; ) { // Skip color escapes - while( Q_IsColorString( q ) ) { + c[ 0 ] = q[ 0 ]; + c[ 1 ] = q[ 1 ]; q += 2; - continue; + } + while( UI_Text_Emoticon( q, &emoticonEscaped, &emoticonLen, NULL ) ) + { + if( emoticonEscaped ) + q++; + else + q += emoticonLen; } qMinus1 = q; @@ -4504,7 +4626,18 @@ static const char *Item_Text_Wrap( const char *text, float scale, float width ) // Some color escapes might still be present while( Q_IsColorString( q ) ) + { + c[ 0 ] = q[ 0 ]; + c[ 1 ] = q[ 1 ]; q += 2; + } + while( UI_Text_Emoticon( q, &emoticonEscaped, &emoticonLen, NULL ) ) + { + if( emoticonEscaped ) + q++; + else + q += emoticonLen; + } // Manual line break if( *q == '\n' ) @@ -4523,9 +4656,6 @@ static const char *Item_Text_Wrap( const char *text, float scale, float width ) if( eol == p ) eol = q; - // Add colour code (might be empty) - Q_strcat( out, sizeof( out ), c ); - paint = out + strlen( out ); // Copy text @@ -4535,7 +4665,10 @@ static const char *Item_Text_Wrap( const char *text, float scale, float width ) // Add a \n if it's not there already if( out[ strlen( out ) - 1 ] != '\n' ) - Q_strcat( out, sizeof( out ), "\n" ); + { + Q_strcat( out, sizeof( out ), "\n " ); + Q_strcat( out, sizeof( out ), c ); + } paint = out + strlen( out ); diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h index a33d9ae6..fe9b03fe 100644 --- a/src/ui/ui_shared.h +++ b/src/ui/ui_shared.h @@ -341,7 +341,9 @@ typedef struct vec4_t shadowColor; float shadowFadeClamp; qboolean fontRegistered; - + char emoticons[ MAX_EMOTICONS ][ MAX_EMOTICON_NAME_LEN ]; + qhandle_t emoticonShaders[ MAX_EMOTICONS ]; + int emoticonCount; } cachedAssets_t; |