/* ================== CON_ColorPrint ================== */ static void CON_ColorPrint(WINDOW *win, const char *msg, qboolean stripcodes) { static char buffer[MAXPRINTMSG]; int length = 0; CON_SetColor(win, 7); while (*msg) { if (Q_IsColorString(msg) || *msg == '\n') { // First empty the buffer if (length > 0) { buffer[length] = '\0'; wprintw(win, "%s", buffer); length = 0; } if (*msg == '\n') { // Reset the color and then print a newline CON_SetColor(win, 7); waddch(win, '\n'); msg++; } else { // Set the color CON_SetColor(win, ColorIndex(*(msg + 1))); if (stripcodes) { msg += 2; } else { if (length >= MAXPRINTMSG - 1) { break; } buffer[length] = *msg; length++; msg++; if (length >= MAXPRINTMSG - 1) { break; } buffer[length] = *msg; length++; msg++; } } } else { if (length >= MAXPRINTMSG - 1) { break; } buffer[length] = *msg; length++; msg++; } } // Empty anything still left in the buffer if (length > 0) { buffer[length] = '\0'; wprintw(win, "%s", buffer); } }
/* =========== G_ClientCleanName ============ */ 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--; len = 0; colorlessLen = 0; p = out; *p = 0; spaces = 0; for( ; *in; in++ ) { // don't allow leading spaces if( colorlessLen == 0 && *in == ' ' ) continue; // check colors if( Q_IsColorString( in ) ) { in++; // don't allow black in a name, period if( ColorIndex( *in ) == 0 ) continue; // make sure room in dest for both chars if( len > outSize - 2 ) break; *out++ = Q_COLOR_ESCAPE; *out++ = *in; 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 == ' ' ) { spaces++; if( spaces > 3 ) continue; } else spaces = 0; if( len > outSize - 1 ) break; *out++ = *in; colorlessLen++; len++; } *out = 0; // don't allow empty names if( *p == 0 || colorlessLen == 0 ) Q_strncpyz( p, "UnnamedPlayer", outSize ); }
/* ============== CG_SurfaceText Add text in 3D space. Text faces away from axis forward directory. ref entity should have origin, axis, and shaderRGBA set ============== */ void CG_SurfaceText( const refEntity_t *originEnt, const fontInfo_t *font, float scale, const char *text, float adjust, int limit, float gradient, qboolean forceColor ) { int len, count; vec4_t newColor; vec4_t gradientColor; const glyphInfo_t *glyph; const char *s; float yadj, xadj; float useScale; vec3_t baseline; refEntity_t re; polyVert_t verts[4]; float x, y, w, h; int j; if ( !text ) { return; } scale *= 0.25f; // for world scale re = *originEnt; re.reType = RT_POLY_LOCAL; VectorCopy( re.origin, re.oldorigin ); // center justify at origin VectorCopy( vec3_origin, baseline ); x = 0 - Text_Width( text, font, scale, 0 ) / 2; y = 0; useScale = scale * font->glyphScale; newColor[0] = re.shaderRGBA[0] / 255.0f; newColor[1] = re.shaderRGBA[1] / 255.0f; newColor[2] = re.shaderRGBA[2] / 255.0f; newColor[3] = re.shaderRGBA[3] / 255.0f; gradientColor[0] = Com_Clamp( 0, 1, newColor[0] - gradient ); gradientColor[1] = Com_Clamp( 0, 1, newColor[1] - gradient ); gradientColor[2] = Com_Clamp( 0, 1, newColor[2] - gradient ); gradientColor[3] = newColor[3]; len = Q_UTF8_PrintStrlen( text ); if ( limit > 0 && len > limit ) { len = limit; } s = text; count = 0; while ( s && *s && count < len ) { if ( Q_IsColorString( s ) ) { if ( !forceColor ) { VectorCopy( g_color_table[ColorIndex(*(s+1))], newColor ); gradientColor[0] = Com_Clamp( 0, 1, newColor[0] - gradient ); gradientColor[1] = Com_Clamp( 0, 1, newColor[1] - gradient ); gradientColor[2] = Com_Clamp( 0, 1, newColor[2] - gradient ); } s += 2; continue; } glyph = Text_GetGlyph( font, Q_UTF8_CodePoint( &s ) ); yadj = useScale * glyph->top; xadj = useScale * glyph->left; w = glyph->imageWidth * useScale; h = glyph->imageHeight * useScale; // 0 1 // 3 2 verts[0].xyz[0] = baseline[0] + 0; verts[0].xyz[1] = baseline[1] - ( x + xadj ); verts[0].xyz[2] = baseline[2] + y + yadj; verts[1].xyz[0] = baseline[0] + 0; verts[1].xyz[1] = baseline[1] - ( x + xadj + w ); verts[1].xyz[2] = baseline[2] + y + yadj; verts[2].xyz[0] = baseline[0] + 0; verts[2].xyz[1] = baseline[1] - ( x + xadj + w ); verts[2].xyz[2] = baseline[2] + y + yadj - h; verts[3].xyz[0] = baseline[0] + 0; verts[3].xyz[1] = baseline[1] - ( x + xadj ); verts[3].xyz[2] = baseline[2] + y + yadj - h; // standard square texture coordinates for ( j = 0; j < 4; j++ ) { verts[j].st[0] = ( j == 0 || j == 3 ) ? glyph->s : glyph->s2; verts[j].st[1] = ( j < 2 ) ? glyph->t : glyph->t2; if ( j < 2 || gradient == 0 ) { verts[j].modulate[0] = newColor[0] * 0xFF; verts[j].modulate[1] = newColor[1] * 0xFF; verts[j].modulate[2] = newColor[2] * 0xFF; verts[j].modulate[3] = newColor[3] * 0xFF; } else { verts[j].modulate[0] = gradientColor[0] * 0xFF; verts[j].modulate[1] = gradientColor[1] * 0xFF; verts[j].modulate[2] = gradientColor[2] * 0xFF; verts[j].modulate[3] = gradientColor[3] * 0xFF; } } re.customShader = glyph->glyph; re.radius = w / 2; trap_R_AddPolyRefEntityToScene( &re, 4, verts, 1 ); x += ( glyph->xSkip * useScale ) + adjust; count++; } // debug axis //re.reType = RT_MODEL; //re.hModel = 0; //trap_R_AddRefEntityToScene( &re ); }
/* =========== ClientCheckName ============ */ static void ClientCleanName( const char *in, char *out, int outSize ) { int len, colorlessLen; char ch; char *p; int spaces; //save room for trailing null byte outSize--; len = 0; colorlessLen = 0; p = out; *p = 0; spaces = 0; while( 1 ) { ch = *in++; if( !ch ) { break; } // don't allow leading spaces if( !*p && ch == ' ' ) { continue; } // check colors if( ch == Q_COLOR_ESCAPE ) { // solo trailing carat is not a color prefix if( !*in ) { break; } // don't allow black in a name, period if( ColorIndex(*in) == 0 ) { in++; continue; } // make sure room in dest for both chars if( len > outSize - 2 ) { break; } *out++ = ch; *out++ = *in++; len += 2; continue; } // don't allow too many consecutive spaces if( ch == ' ' ) { spaces++; if( spaces > 3 ) { continue; } } else { spaces = 0; } if( len > outSize - 1 ) { break; } *out++ = ch; colorlessLen++; len++; } *out = 0; // don't allow empty names if( *p == 0 || colorlessLen == 0 ) { Q_strncpyz( p, "UnnamedPlayer", outSize ); } }
/* ================= UI_DrawString ================= */ void UI_DrawString( int x, int y, int w, int h, const char *string, const int color, int forceColor, int charW, int charH, int justify, int shadow ) { int modulate, shadowModulate; char line[1024], *l; int xx, yy, ofsX, ofsY, len, ch; if( !string || !string[0] ) return; #if 0 // g-cont. disabled 29/06/2011 // this code do a bad things with prompt dialogues // vertically centered if( !strchr( string, '\n' )) y = y + (( h - charH ) / 2 ); #endif if( shadow ) { shadowModulate = PackAlpha( uiColorBlack, UnpackAlpha( color )); ofsX = charW / 8; ofsY = charH / 8; } modulate = color; yy = y; while( *string ) { // get a line of text len = 0; while( *string ) { if( *string == '\n' ) { string++; break; } line[len++] = *string++; if( len == sizeof( line ) - 1 ) break; } line[len] = 0; // align the text as appropriate if( justify == 0 ) xx = x; if( justify == 1 ) xx = x + ((w - (ColorStrlen( line ) * charW )) / 2); if( justify == 2 ) xx = x + (w - (ColorStrlen( line ) * charW )); // draw it l = line; while( *l ) { if( IsColorString( l )) { if( !forceColor ) { int colorNum = ColorIndex( *(l+1) ); modulate = PackAlpha( g_iColorTable[colorNum], UnpackAlpha( color )); } l += 2; continue; } ch = *l++; ch &= 255; // fix for letter ¸ if( ch == 0xB8 ) ch = (byte)'å'; if( ch == 0xA8 ) ch = (byte)'Å'; if( ch != ' ' ) { if( shadow ) TextMessageDrawChar( xx + ofsX, yy + ofsY, charW, charH, ch, shadowModulate, uiStatic.hFont ); TextMessageDrawChar( xx, yy, charW, charH, ch, modulate, uiStatic.hFont ); } xx += charW; } yy += charH; } }
// // DrawSelf // void TimeOfDay::DrawSelf(PaintInfo &pi) { if (texture && texture->texture) { // Radius of texture const F32 SCALE = 0.5F; const struct { F32 u, v; } UV[4] = { { -SCALE, SCALE }, { SCALE, SCALE }, { SCALE, 0.0F }, { -SCALE, 0.0F }, }; // Middle of day is 90deg rotation, Middle of night is 270deg rotation F32 angle = Environment::Light::Azimuth() * PI + PIBY2; if (!Environment::Light::IsSunUp()) { angle += PI; } // Rotate anticlockwise //angle = -angle; // Calculate UV coordinates, assumes square texture taking up entire image F32 cosAngle = F32(cos(angle)); F32 sinAngle = F32(sin(angle)); // Scale the alpha down Color color = pi.colors->bg[ColorIndex()]; if (pi.alphaScale < 1.0F) { color.a = U8(Utils::FtoL(F32(color.a) * pi.alphaScale)); } // vertices of the rectangle U16 offset; VertexTL *point = IFace::GetVerts(4, texture->texture, texture->filter, RS_TEXCLAMP, offset); IFace::SetIndex(Vid::rectIndices, 6, offset); // top left corner point[0].vv.x = (F32)pi.client.p0.x; point[0].vv.y = (F32)pi.client.p0.y; point[0].vv.z = 0.0F; point[0].rhw = 1.0F; point[0].diffuse = color; point[0].specular = 0xFF000000; point[0].u = 0.5F + UV[0].u * cosAngle - UV[0].v * sinAngle; point[0].v = 0.5F + UV[0].u * sinAngle + UV[0].v * cosAngle;; // top right corner point[1].vv.x = (F32)pi.client.p1.x; point[1].vv.y = (F32)pi.client.p0.y; point[1].vv.z = 0.0F; point[1].rhw = 1.0F; point[1].diffuse = color; point[1].specular = 0xFF000000; point[1].u = 0.5F + UV[1].u * cosAngle - UV[1].v * sinAngle; point[1].v = 0.5F + UV[1].u * sinAngle + UV[1].v * cosAngle;; // bottom right corner point[2].vv.x = (F32)pi.client.p1.x; point[2].vv.y = (F32)pi.client.p1.y; point[2].vv.z = 0.0F; point[2].rhw = 1.0F; point[2].diffuse = color; point[2].specular = 0xFF000000; point[2].u = 0.5F + UV[2].u * cosAngle - UV[2].v * sinAngle; point[2].v = 0.5F + UV[2].u * sinAngle + UV[2].v * cosAngle;; // bottom left corner point[3].vv.x = (F32)pi.client.p0.x; point[3].vv.y = (F32)pi.client.p1.y; point[3].vv.z = 0.0F; point[3].rhw = 1.0F; point[3].diffuse = color; point[3].specular = 0xFF000000; point[3].u = 0.5F + UV[3].u * cosAngle - UV[3].v * sinAngle; point[3].v = 0.5F + UV[3].u * sinAngle + UV[3].v * cosAngle;; /* // Are we after sunrise and before sunset ? if (currentTime > sunriseStartTime && currentTime < sunsetStartTime) { tempText = "Day"; tempVal = (sunsetStartTime - currentTime) * 24.0f * 60.0f; } else { tempText = "Night"; tempVal = sunriseStartTime - currentTime; if (tempVal < 0.0f) { tempVal = tempVal + 1.0f; } tempVal = tempVal * 24.0f * 60.0f; } */ } }
void CG_DrawStringExt2( int x, int y, const char *string, const float *setColor, qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars, uint uFlags) { vec4_t color, revertColor; const char *s; int xx; int cnt; /* LQ3A: We need to preserve the original Y value to support shadows on multiline strings.*/ int yy; int iOfsX, iOfsY, iLineOfs; /* LQ3A: Save the initial color so that we can revert back where necessary. */ memcpy(revertColor, setColor, sizeof(revertColor)); if (maxChars <= 0) maxChars = 32767; // do them all! /* LQ3A: Line offset depends on text size. */ iLineOfs = ((charWidth == BIGCHAR_WIDTH) && (charHeight == BIGCHAR_HEIGHT)) ? 5 : 3; // draw the drop shadow if (shadow) { color[0] = color[1] = color[2] = 0; color[3] = setColor[3]; trap_R_SetColor( color ); s = string; /* LQ3A */ xx = LQ3A_GetDrawAlignment(x, s, charWidth, uFlags); yy = y; /* LQ3A: Shadow offset depends on text size. */ iOfsX = (charWidth <= TINYCHAR_WIDTH) ? 1 : 2; iOfsY = (charHeight <= TINYCHAR_HEIGHT) ? 1 : 2; cnt = 0; while ( *s && cnt < maxChars) { if ( Q_IsColorString( s ) ) { s += 2; continue; } /* LQ3A: Support multiline strings. */ if (*s == '\n') { xx = LQ3A_GetDrawAlignment(x, ++s, charWidth, uFlags); yy += charHeight + iLineOfs; continue; } /* LQ3A */ CG_DrawChar( xx + iOfsX, yy + iOfsY, charWidth, charHeight, *s ); cnt++; xx += charWidth; s++; } } // draw the colored text s = string; /* LQ3A */ xx = LQ3A_GetDrawAlignment(x, s, charWidth, uFlags); yy = y; cnt = 0; trap_R_SetColor( setColor ); while ( *s && cnt < maxChars) { if ( Q_IsColorString( s ) ) { if ( !forceColor ) { /* LQ3A: Support S_COLOR_REVERT. */ if (s[1] == COLOR_REVERT) { memcpy(color, revertColor, sizeof(vec3_t)); } else { memcpy(color, g_color_table[ColorIndex(*(s+1))], sizeof(vec3_t)); } color[3] = setColor[3]; trap_R_SetColor( color ); } s += 2; continue; } /* LQ3A: Support multiline strings. */ if (*s == '\n') { xx = LQ3A_GetDrawAlignment(x, ++s, charWidth, uFlags); y += charHeight + iLineOfs; /* Reset the color. */ trap_R_SetColor(setColor); continue; } CG_DrawChar( xx, y, charWidth, charHeight, *s ); xx += charWidth; cnt++; s++; } trap_R_SetColor( NULL ); }
static void Con_Print2( const char *txt, qboolean notify ) { int c, l; int color; qboolean colorflag = qfalse; if( !con_initialized ) return; if( con_printText && con_printText->integer == 0 ) return; color = ColorIndex( COLOR_WHITE ); while( ( c = *txt ) ) { // count word length for( l = 0; l < con.linewidth; l++ ) if( (unsigned char)txt[l] <= ' ' ) break; // word wrap if( l != con.linewidth && ( con.x + l > con.linewidth ) ) con.x = 0; if( !con.x ) { Con_Linefeed(); // mark time for transparent overlay con.times[0] = cls.realtime; if( !notify ) con.times[0] -= con_notifytime->value*1000 + 1; if( color != ColorIndex( COLOR_WHITE ) ) { addchartostr( &con.text[0], Q_COLOR_ESCAPE ); addchartostr( &con.text[0], '0' + color ); con.x += 2; } } switch( c ) { case '\n': color = ColorIndex( COLOR_WHITE ); con.x = 0; break; case '\r': break; default: // display character and advance addchartostr( &con.text[0], c ); con.x++; if( con.x >= con.linewidth ) // haha welcome to 1995 lol con.x = 0; if( colorflag ) { if( *txt != Q_COLOR_ESCAPE ) color = ColorIndex( *txt ); colorflag = qfalse; } else if( *txt == Q_COLOR_ESCAPE ) colorflag = qtrue; // if( Q_IsColorString( txt ) ) { // color = ColorIndex( *(txt+1) ); // } break; } txt++; } }
// // TransferList::Item::DrawSelf // // DrawSelf // void TransferList::Item::DrawSelf(PaintInfo &pi) { // Fill the background DrawCtrlBackground(pi, GetTexture()); // Draw the frame DrawCtrlFrame(pi); if (!pi.font) { return; } CH buff[128]; const CH *ch; // Draw the name of the file ch = Utils::Ansi2Unicode(offer->path.str); pi.font->Draw ( pi.client.p0.x + transferList.offsetFile.x, pi.client.p0.y + transferList.offsetFile.y, ch, Utils::Strlen(ch), pi.colors->fg[ColorIndex()], &pi.client ); Network::Player *player = Network::GetPlayers().Find(offer->who); if (player) { Utils::Sprintf(buff, 128, L"%s %s", offer->from ? L"From" : L"To", Utils::Ansi2Unicode(player->GetName())); ch = buff; pi.font->Draw ( pi.client.p0.x + transferList.offsetPlayer.x, pi.client.p0.y + transferList.offsetPlayer.y, ch, Utils::Strlen(ch), pi.colors->fg[ColorIndex()], &pi.client ); } ch = Utils::Ansi2Unicode(offer->path.str); pi.font->Draw ( pi.client.p0.x + transferList.offsetFile.x, pi.client.p0.y + transferList.offsetFile.y, ch, Utils::Strlen(ch), pi.colors->fg[ColorIndex()], &pi.client ); U32 state; U32 remaining; U32 rate; offer->transfer.Progress(state, remaining, rate); switch (state) { case StyxNet::TransferState::Transferring: break; default: remaining = offer->size; rate = 0; break; } U32 transferred = offer->size - remaining; // Draw the amount transferred if (transferred < 1000) { Utils::Sprintf(buff, 128, L"%.1fB", F32(transferred)); } else if (transferred < 1000000) { Utils::Sprintf(buff, 128, L"%.1fkB", F32(transferred) / 1000.0f); } else { Utils::Sprintf(buff, 128, L"%.1fMB", F32(transferred) / 1000000.0f); } ch = buff; pi.font->Draw ( pi.client.p0.x + transferList.offsetTransferred.x, pi.client.p0.y + transferList.offsetTransferred.y, ch, Utils::Strlen(ch), pi.colors->fg[ColorIndex()], &pi.client ); // Draw the rate if (rate < 1000) { Utils::Sprintf(buff, 128, L"%.1fB/s", F32(rate)); } else if (rate < 1000000) { Utils::Sprintf(buff, 128, L"%.1fkB/s", F32(rate) / 1000.0f); } else { Utils::Sprintf(buff, 128, L"%.1fMB/s", F32(rate) / 1000000.0f); } pi.font->Draw ( pi.client.p0.x + transferList.offsetRate.x, pi.client.p0.y + transferList.offsetRate.y, ch, Utils::Strlen(ch), pi.colors->fg[ColorIndex()], &pi.client ); // Draw the ETA if (rate) { S32 eta = remaining / rate; Utils::Sprintf(buff, 128, L"%d:%02d", eta / 60, eta % 60); } else { ch = L"?:??"; } pi.font->Draw ( pi.client.p0.x + transferList.offsetETA.x, pi.client.p0.y + transferList.offsetETA.y, ch, Utils::Strlen(ch), pi.colors->fg[ColorIndex()], &pi.client ); // Draw a progress bar ClipRect c ( pi.client.p0.x + transferList.offsetProgress.x, pi.client.p0.y + transferList.offsetProgress.y, pi.client.p1.x - transferList.offsetProgress.x, pi.client.p0.y + transferList.offsetProgress.y + transferList.heightProgress ); IFace::RenderRectangle ( c, Color(0.0f, 0.0f, 0.0f, pi.alphaScale), NULL, pi.alphaScale ); IFace::RenderGradient ( ClipRect ( c.p0.x, c.p0.y, c.p1.x - (c.Width() * remaining / offer->size), c.p1.y ), Color(0.2f, 1.0f, 1.0f, pi.alphaScale), Color(0.1f, 0.5f, 0.5f, pi.alphaScale) ); }
/* ================== SCR_DrawScreenField This will be called twice if rendering in stereo mode ================== */ void SCR_DrawScreenField( stereoFrame_t stereoFrame ) { qboolean uiFullscreen; re.BeginFrame( stereoFrame ); uiFullscreen = (uivm && VM_Call( uivm, UI_IS_FULLSCREEN )); // wide aspect ratio screens need to have the sides cleared // unless they are displaying game renderings if ( uiFullscreen || (clc.state != CA_ACTIVE && clc.state != CA_CINEMATIC) ) { if ( cls.glconfig.vidWidth * 480 > cls.glconfig.vidHeight * 640 ) { re.SetColor( ColorForIndex(ColorIndex(COLOR_BLACK)) ); re.DrawStretchPic( 0, 0, cls.glconfig.vidWidth, cls.glconfig.vidHeight, 0, 0, 0, 0, cls.whiteShader ); re.SetColor( NULL ); } } // if the menu is going to cover the entire screen, we // don't need to render anything under it if ( uivm && !uiFullscreen ) { switch( clc.state ) { default: Com_Error( ERR_FATAL, "SCR_DrawScreenField: bad clc.state" ); break; case CA_CINEMATIC: SCR_DrawCinematic(); break; case CA_DISCONNECTED: // force menu up S_StopAllSounds(); VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN ); break; case CA_CONNECTING: case CA_CHALLENGING: case CA_CONNECTED: // connecting clients will only show the connection dialog // refresh to update the time VM_Call( uivm, UI_REFRESH, cls.realtime ); VM_Call( uivm, UI_DRAW_CONNECT_SCREEN, qfalse ); break; case CA_LOADING: case CA_PRIMED: // draw the game information screen and loading progress CL_CGameRendering(stereoFrame); // also draw the connection information, so it doesn't // flash away too briefly on local or lan games // refresh to update the time VM_Call( uivm, UI_REFRESH, cls.realtime ); VM_Call( uivm, UI_DRAW_CONNECT_SCREEN, qtrue ); break; case CA_ACTIVE: // always supply STEREO_CENTER as vieworg offset is now done by the engine. CL_CGameRendering(stereoFrame); SCR_DrawDemoRecording(); #ifdef USE_VOIP SCR_DrawVoipMeter(); #endif break; } } // the menu draws next if ( Key_GetCatcher( ) & KEYCATCH_UI && uivm ) { VM_Call( uivm, UI_REFRESH, cls.realtime ); } // console draws next Con_DrawConsole (); // debug graph can be drawn on top of anything if ( cl_debuggraph->integer || cl_timegraph->integer || cl_debugMove->integer ) { SCR_DrawDebugGraph (); } }
void CL_ConsolePrint( char *txt ) { int y; int c, i, l; int color; qboolean skipnotify = qfalse; // NERVE - SMF int prev; // NERVE - SMF // NERVE - SMF - work around for text that shows up in console but not in notify if ( !Q_strncmp( txt, "[skipnotify]", 12 ) ) { skipnotify = qtrue; txt += 12; } // for some demos we don't want to ever show anything on the console if ( cl_noprint && cl_noprint->integer ) { return; } if ( !con.initialized ) { con.color[ 0 ] = con.color[ 1 ] = con.color[ 2 ] = con.color[ 3 ] = 1.0f; con.linewidth = -1; Con_CheckResize(); con.initialized = qtrue; } if ( !skipnotify && !( cls.keyCatchers & KEYCATCH_CONSOLE ) && strncmp( txt, "EXCL: ", 6 ) ) { // feed the text to cgame Cmd_SaveCmdContext(); Cmd_TokenizeString( txt ); CL_GameConsoleText(); Cmd_RestoreCmdContext(); } color = ColorIndex( CONSOLE_COLOR ); while ( ( c = *txt & 0xFF ) != 0 ) { if ( Q_IsColorString( txt ) ) { color = ( txt[ 1 ] == COLOR_NULL ) ? ColorIndex( CONSOLE_COLOR ) : ColorIndex( txt[ 1 ] ); txt += 2; continue; } // count word length for ( i = l = 0; l < con.linewidth; ++l ) { if ( txt[ i ] <= ' ' && txt[ i ] >= 0 ) { break; } if ( txt[ i ] == Q_COLOR_ESCAPE && txt[ i + 1 ] == Q_COLOR_ESCAPE ) { ++i; } i += Q_UTF8Width( txt + i ); } // word wrap if ( l != con.linewidth && ( con.x + l >= con.linewidth ) ) { Con_Linefeed( skipnotify ); } switch ( c ) { case '\n': Con_Linefeed( skipnotify ); break; case '\r': con.x = 0; break; case Q_COLOR_ESCAPE: if ( txt[ 1 ] == Q_COLOR_ESCAPE ) { ++txt; } default: // display character and advance y = con.current % con.totallines; // rain - sign extension caused the character to carry over // into the color info for high ascii chars; casting c to unsigned con.text[ y * con.linewidth + con.x ].ch = Q_UTF8CodePoint( txt ); con.text[ y * con.linewidth + con.x ].ink = color; ++con.x; if ( con.x >= con.linewidth ) { Con_Linefeed( skipnotify ); con.x = 0; } break; } txt += Q_UTF8Width( txt ); } // mark time for transparent overlay if ( con.current >= 0 ) { // NERVE - SMF if ( skipnotify ) { prev = con.current % NUM_CON_TIMES - 1; if ( prev < 0 ) { prev = NUM_CON_TIMES - 1; } con.times[ prev ] = 0; } else { // -NERVE - SMF con.times[ con.current % NUM_CON_TIMES ] = cls.realtime; } } }
void CEngineSurface :: drawPrintText( const char* text, int textLen ) { static bool hasColor = 0; static int numColor = 7; if( !text || !_hCurrentFont || _drawTextColor[3] >= 255 ) return; int x = _drawTextPos[0] + _translateX; int y = _drawTextPos[1] + _translateY; int iTall = _hCurrentFont->getTall(); int j, iTotalWidth = 0; int curTextColor[4]; // HACKHACK: allow color strings in VGUI if( numColor != 7 && vgui_colorstrings->integer ) { for( j = 0; j < 3; j++ ) // grab predefined color curTextColor[j] = g_color_table[numColor][j]; } else { for( j = 0; j < 3; j++ ) // revert default color curTextColor[j] = _drawTextColor[j]; } curTextColor[3] = _drawTextColor[3]; // copy alpha if( textLen == 1 && vgui_colorstrings->integer ) { if( *text == '^' ) { hasColor = true; return; // skip '^' } else if( hasColor && isdigit( *text )) { numColor = ColorIndex( *text ); hasColor = false; // handled return; // skip colornum } else hasColor = false; } for( int i = 0; i < textLen; i++ ) { char ch = text[i]; int abcA,abcB,abcC; _hCurrentFont->getCharABCwide( ch, abcA, abcB, abcC ); iTotalWidth += abcA; int iWide = abcB; if( !iswspace( ch )) { // get the character texture from the cache int iTexId = 0; float *texCoords = NULL; if( !g_FontCache.GetTextureForChar( _hCurrentFont, ch, &iTexId, &texCoords )) continue; Assert( texCoords != NULL ); vpoint_t ul, lr; ul.point[0] = x + iTotalWidth; ul.point[1] = y; lr.point[0] = ul.point[0] + iWide; lr.point[1] = ul.point[1] + iTall; // gets at the texture coords for this character in its texture page ul.coord[0] = texCoords[0]; ul.coord[1] = texCoords[1]; lr.coord[0] = texCoords[2]; lr.coord[1] = texCoords[3]; vpoint_t clippedRect[2]; if( !ClipRect( ul, lr, &clippedRect[0], &clippedRect[1] )) continue; drawSetTexture( iTexId ); VGUI_SetupDrawingText( curTextColor ); VGUI_DrawQuad( &clippedRect[0], &clippedRect[1] ); // draw the letter } iTotalWidth += iWide + abcC; } _drawTextPos[0] += iTotalWidth; }
// Add Game name ClipRect nameClip ( pi.client.p0.x + gameList.offsetName, pi.client.p0.y, pi.client.p0.x + gameList.offsetName + gameList.widthName, pi.client.p1.y ); ch = Utils::Ansi2Unicode(session.name.str); pi.font->Draw( pi.client.p0.x + gameList.offsetName, pi.client.p0.y + yoffs, ch, Utils::Strlen(ch), pi.colors->fg[ColorIndex()], &nameClip ); // Add Game host ClipRect hostClip ( pi.client.p0.x + gameList.offsetHost, pi.client.p0.y, pi.client.p0.x + gameList.offsetHost + gameList.widthHost, pi.client.p1.y ); ch = Utils::Ansi2Unicode(host.str); pi.font->Draw( pi.client.p0.x + gameList.offsetHost,
void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) { int len, count; vec4_t newColor; glyphInfo_t *glyph; float useScale; fontInfo_t *font = &cgDC.Assets.textFont; if (scale <= cg_smallFont.value) { font = &cgDC.Assets.smallFont; } else if (scale > cg_bigFont.value) { font = &cgDC.Assets.bigFont; } useScale = scale * font->glyphScale; if (text) { // TTimo: FIXME // const unsigned char *s = text; const char *s = text; trap_R_SetColor( color ); memcpy(&newColor[0], &color[0], sizeof(vec4_t)); len = strlen(text); if (limit > 0 && len > limit) { len = limit; } count = 0; while (s && *s && count < len) { glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top; //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height); if ( Q_IsColorString( s ) ) { memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) ); newColor[3] = color[3]; trap_R_SetColor( newColor ); s += 2; continue; } else { float yadj = useScale * glyph->top; if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) { int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2; colorBlack[3] = newColor[3]; trap_R_SetColor( colorBlack ); CG_Text_PaintChar(x + ofs, y - yadj + ofs, glyph->imageWidth, glyph->imageHeight, useScale, glyph->s, glyph->t, glyph->s2, glyph->t2, glyph->glyph); colorBlack[3] = 1.0; trap_R_SetColor( newColor ); } CG_Text_PaintChar(x, y - yadj, glyph->imageWidth, glyph->imageHeight, useScale, glyph->s, glyph->t, glyph->s2, glyph->t2, glyph->glyph); // CG_DrawPic(qfalse,x, y - yadj, scale * cgDC.Assets.textFont.glyphs[text[i]].imageWidth, scale * cgDC.Assets.textFont.glyphs[text[i]].imageHeight, cgDC.Assets.textFont.glyphs[text[i]].glyph); x += (glyph->xSkip * useScale) + adjust; s++; count++; } } trap_R_SetColor( NULL ); } }
/* ================== SCR_DrawBigString[Color] Draws a multi-colored string with a drop shadow, optionally forcing to a fixed color. ================== */ void SCR_DrawStringExt(int x, int y, float w, float h, const char *string, float *setColor, qboolean forceColor, qboolean noColorEscape, qboolean dropShadow, qboolean nativeResolution) { vec4_t color; const char *s; int xx; if (dropShadow) { // draw the drop shadow Vector4Copy(colorBlack, color); color[3] = setColor[3]; re.SetColor(color); s = string; xx = x; while (*s) { if (!noColorEscape && Q_IsColorString(s)) { s += 2; continue; } SCR_DrawChar(xx + 2, y + 2, w, h, Q_UTF8_CodePoint(s), nativeResolution); xx += w; s += Q_UTF8_Width(s); } } // draw the colored text s = string; xx = x; re.SetColor(setColor); while (*s) { if (Q_IsColorString(s)) { if (!forceColor) { if (*(s + 1) == COLOR_NULL) { memcpy(color, setColor, sizeof(color)); } else { memcpy(color, g_color_table[ColorIndex(*(s + 1))], sizeof(color)); color[3] = setColor[3]; } color[3] = setColor[3]; re.SetColor(color); } if (!noColorEscape) { s += 2; continue; } } SCR_DrawChar(xx, y, w, h, Q_UTF8_CodePoint(s), nativeResolution); xx += w; s += Q_UTF8_Width(s); } re.SetColor(NULL); }
/* =========== ClientCleanName ============ */ static void ClientCleanName( const char *in, char *out, int outSize ) { int len, colorlessLen; char ch; char *p; int spaces; qboolean invalid = qfalse; //save room for trailing null byte outSize--; len = 0; colorlessLen = 0; p = out; *p = 0; spaces = 0; while( 1 ) { ch = *in++; if( !ch ) break; // don't allow leading spaces if( !*p && ch == ' ' ) continue; // don't allow nonprinting characters or (dead) console keys if( ch < ' ' || ch > '}' || ch == '`' ) continue; // check colors if( Q_IsColorString( in - 1 ) ) { // make sure room in dest for both chars if( len > outSize - 2 ) break; *out++ = ch; len += 2; // solo trailing carat is not a color prefix if( !*in ) { *out++ = COLOR_WHITE; break; } // don't allow black in a name, period if( ColorIndex( *in ) == 0 ) *out++ = COLOR_WHITE; else *out++ = *in; in++; continue; } // don't allow too many consecutive spaces if( ch == ' ' ) { spaces++; if( spaces > 3 ) continue; } else spaces = 0; if( len > outSize - 1 ) break; *out++ = ch; colorlessLen++; len++; } *out = 0; // don't allow names beginning with "[skipnotify]" because it messes up /ignore-related code if( !Q_strncmp( p, "[skipnotify]", 12 ) ) invalid = qtrue; // don't allow comment-beginning strings because it messes up various parsers if( strstr( p, "//" ) || strstr( p, "/*" ) ) invalid = qtrue; // don't allow empty names if( *p == 0 || colorlessLen == 0 ) invalid = qtrue; // if something made the name bad, put them back to UnnamedPlayer if( invalid ) Q_strncpyz( p, "UnnamedPlayer", outSize ); }
qboolean CL_InternalConsolePrint( const char *text ) { int y; int c, i, l; int color; // for some demos we don't want to ever show anything on the console if ( cl_noprint && cl_noprint->integer ) { return qtrue; } if ( !consoleState.initialized ) { consoleState.textWidthInChars = -1; consoleState.initialized = Con_CheckResize(); } //Video hasn't been initialized if ( ! cls.glconfig.vidWidth ) { return qfalse; } // NERVE - SMF - work around for text that shows up in console but not in notify if ( !Q_strncmp( text, S_SKIPNOTIFY, 12 ) ) { text += 12; } else if ( !consoleState.isOpened && strncmp( text, "EXCL: ", 6 ) ) { // feed the text to cgame Cmd_SaveCmdContext(); Cmd_TokenizeString( Cmd::Escape(text).c_str() ); CL_GameConsoleText(); Cmd_RestoreCmdContext(); } color = ColorIndex( CONSOLE_COLOR ); while ( ( c = *text & 0xFF ) != 0 ) { if ( Q_IsColorString( text ) ) { color = ( text[ 1 ] == COLOR_NULL ) ? ColorIndex( CONSOLE_COLOR ) : ColorIndex( text[ 1 ] ); text += 2; continue; } // count word length for ( i = l = 0; l < consoleState.textWidthInChars; ++l ) { if ( text[ i ] <= ' ' && text[ i ] >= 0 ) { break; } if ( text[ i ] == Q_COLOR_ESCAPE && text[ i + 1 ] == Q_COLOR_ESCAPE ) { ++i; } i += Q_UTF8_Width( text + i ); } // word wrap if ( l != consoleState.textWidthInChars && ( consoleState.horizontalCharOffset + l >= consoleState.textWidthInChars ) ) { Con_Linefeed( ); } switch ( c ) { case '\n': Con_Linefeed( ); break; case '\r': consoleState.horizontalCharOffset = 0; break; case Q_COLOR_ESCAPE: if ( text[ 1 ] == Q_COLOR_ESCAPE ) { ++text; } /* no break */ default: // display character and advance y = consoleState.currentLine % consoleState.maxScrollbackLengthInLines; // rain - sign extension caused the character to carry over // into the color info for high ascii chars; casting c to unsigned consoleState.text[ y * consoleState.textWidthInChars + consoleState.horizontalCharOffset ].ch = Q_UTF8_CodePoint( text ); consoleState.text[ y * consoleState.textWidthInChars + consoleState.horizontalCharOffset ].ink = color; ++consoleState.horizontalCharOffset; if ( consoleState.horizontalCharOffset >= consoleState.textWidthInChars ) { Con_Linefeed( ); consoleState.horizontalCharOffset = 0; } break; } text += Q_UTF8_Width( text ); } return qtrue; }
void SCR_DrawDemoRecording( void ) { char string[1024]; int pos; if ( !clc.demorecording ) { return; } if ( clc.spDemoRecording ) { return; } pos = FS_FTell( clc.demofile ); sprintf( string, "RECORDING %s: %ik", clc.demoName, pos / 1024 ); SCR_DrawStringExt( ((int)SCREEN_WIDTH/2) - (int)strlen( string ) * 4, 20, 8, string, &g_color_table[ColorIndex(COLOR_WHITE)], qtrue, qfalse ); }
void SCR_Text_Paint(float x, float y, float scale, const vec4_t color, const char *text, float adjust, int limit, int style, const fontInfo_t * font) { int len, count; vec4_t newColor; const glyphInfo_t *glyph; float useScale; useScale = scale * font->glyphScale; if(text) { // TTimo: FIXME // const unsigned char *s = text; const char *s = text; re.SetColor(color); memcpy(&newColor[0], &color[0], sizeof(vec4_t)); len = strlen(text); if(limit > 0 && len > limit) { len = limit; } count = 0; while(s && *s && count < len) { glyph = &font->glyphs[(int)*s]; if(Q_IsColorString(s)) { memcpy(newColor, (float *)g_color_table[ColorIndex(*(s + 1))], sizeof(newColor)); newColor[3] = color[3]; re.SetColor(newColor); s += 2; continue; } else { float yadj = useScale * glyph->top; if(style & UI_DROPSHADOW) // || style == ITEM_TEXTSTYLE_SHADOWEDMORE) { int ofs = 1; //style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2; colorBlack[3] = newColor[3]; re.SetColor(colorBlack); SCR_Text_PaintChar(x + ofs, y - yadj + ofs, glyph->imageWidth, glyph->imageHeight, useScale, glyph->s, glyph->t, glyph->s2, glyph->t2, glyph->glyph); colorBlack[3] = 1.0; re.SetColor(newColor); } SCR_Text_PaintChar(x, y - yadj, glyph->imageWidth, glyph->imageHeight, useScale, glyph->s, glyph->t, glyph->s2, glyph->t2, glyph->glyph); x += (glyph->xSkip * useScale) + adjust; s++; count++; } } re.SetColor(NULL); } }
void SCR_DrawVoipMeter( void ) { char buffer[16]; char string[256]; int limit, i; if (!cl_voipShowMeter->integer) return; // player doesn't want to show meter at all. else if (!cl_voipSend->integer) return; // not recording at the moment. else if (clc.state != CA_ACTIVE) return; // not connected to a server. else if (!clc.voipEnabled) return; // server doesn't support VoIP. else if (clc.demoplaying) return; // playing back a demo. else if (!cl_voip->integer) return; // client has VoIP support disabled. limit = (int) (clc.voipPower * 10.0f); if (limit > 10) limit = 10; for (i = 0; i < limit; i++) buffer[i] = '*'; while (i < 10) buffer[i++] = ' '; buffer[i] = '\0'; sprintf( string, "VoIP: [%s]", buffer ); SCR_DrawStringExt( ((int)SCREEN_WIDTH/2) - (int)strlen( string ) * 4, 10, 8, string, &g_color_table[ColorIndex(COLOR_WHITE)], qtrue, qfalse ); }
// Draws a multi-colored string with a drop shadow, optionally forcing to a fixed color. // Coordinates are at 640 by 480 virtual resolution void CG_DrawStringExt( int x, int y, const char *string, const vector4 *setColor, qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars ) { if ( trap->R_Language_IsAsian() ) { // hack-a-doodle-do (post-release quick fix code)... // vector4 color; memcpy( &color, setColor, sizeof(color) ); // de-const it Text_Paint( x, y, 1.0f, // float scale, &color, // vector4 color, string, // const char *text, 0.0f, // float adjust, 0, // int limit, shadow ? ITEM_TEXTSTYLE_SHADOWED : 0, // int style, FONT_MEDIUM, // iMenuFont qfalse ); } else { vector4 color; const char *s; int xx; // draw the drop shadow if ( shadow ) { color.r = color.g = color.b = 0; color.a = setColor->a; trap->R_SetColor( &color ); s = string; xx = x; while ( *s ) { if ( Q_IsColorString( s ) ) { s += 2; continue; } CG_DrawChar(xx + 2 * cgs.widthRatioCoef, y + 2, charWidth, charHeight, *s); xx += charWidth; s++; } } // draw the colored text s = string; xx = x; trap->R_SetColor( setColor ); while ( *s ) { if ( Q_IsColorString( s ) ) { if ( !forceColor ) { memcpy( &color, &g_color_table[ColorIndex( *(s + 1) )], sizeof(color) ); color.a = setColor->a; trap->R_SetColor( &color ); } s += 2; continue; } CG_DrawChar( xx, y, charWidth, charHeight, *s ); xx += charWidth; s++; } trap->R_SetColor( NULL ); } }
// This will be called twice if rendering in stereo mode void SCR_DrawScreenField( stereoFrame_t stereoFrame ) { qboolean uiFullscreen; re->BeginFrame( stereoFrame ); uiFullscreen = (cls.uiStarted && ui->IsFullscreen()); // wide aspect ratio screens need to have the sides cleared // unless they are displaying game renderings if ( uiFullscreen || clc.state != CA_ACTIVE ) { if ( cls.glconfig.vidWidth * SCREEN_HEIGHT > cls.glconfig.vidHeight * SCREEN_WIDTH ) { re->SetColor( &g_color_table[ColorIndex(COLOR_BLACK)] ); re->DrawStretchPic( 0, 0, (float)cls.glconfig.vidWidth, (float)cls.glconfig.vidHeight, 0, 0, 0, 0, cls.whiteShader ); re->SetColor( NULL ); } } // if the menu is going to cover the entire screen, we // don't need to render anything under it if ( cls.uiStarted && !uiFullscreen ) { switch( clc.state ) { default: Com_Error( ERR_FATAL, "SCR_DrawScreenField: bad clc.state" ); break; case CA_DISCONNECTED: // force menu up S_StopAllSounds(); ui->SetActiveMenu( UIMENU_MAIN ); break; case CA_CONNECTING: case CA_CHALLENGING: case CA_CONNECTED: // connecting clients will only show the connection dialog // refresh to update the time ui->Refresh( cls.realtime ); ui->DrawConnectScreen( qfalse ); break; case CA_LOADING: case CA_PRIMED: // draw the game information screen and loading progress CL_CGameRendering(stereoFrame); // also draw the connection information, so it doesn't // flash away too briefly on local or lan games // refresh to update the time ui->Refresh( cls.realtime ); ui->DrawConnectScreen( qtrue ); break; case CA_ACTIVE: // always supply STEREO_CENTER as vieworg offset is now done by the engine. CL_CGameRendering(stereoFrame); SCR_DrawDemoRecording(); #ifdef USE_VOIP SCR_DrawVoipMeter(); #endif break; } } // the menu draws next if ( Key_GetCatcher( ) & KEYCATCH_UI && cls.uiStarted ) { ui->Refresh( cls.realtime ); } // console draws next Con_DrawConsole(); // debug graph can be drawn on top of anything if ( cl_debuggraph->integer || cl_timegraph->integer || cl_debugMove->integer ) { SCR_DrawDebugGraph(); } }
/* ================= PlayerSettings_DrawName ================= */ static void PlayerSettings_DrawName( void *self ) { menufield_s *f; qboolean focus; int style; char *txt; char c; float *color; int n; int basex, x, y; char name[32]; f = (menufield_s*)self; basex = f->generic.x; y = f->generic.y; focus = (f->generic.parent->cursor == f->generic.menuPosition); style = UI_LEFT|UI_SMALLFONT; color = text_color_normal; if( focus ) { style |= UI_PULSE; color = text_color_highlight; } UI_DrawProportionalString( basex, y, "Name", style|UI_CURSORSHADOW, color ); // draw the actual name basex += 64; y += PROP_HEIGHT; txt = f->field.buffer; color = g_color_table[ColorIndex(COLOR_WHITE)]; x = basex; while ( (c = *txt) != 0 ) { if ( !focus && Q_IsColorString( txt ) ) { n = ColorIndex( *(txt+1) ); if( n == 0 ) { n = 7; } color = g_color_table[n]; txt += 2; continue; } UI_DrawChar( x, y, c, style, color ); txt++; x += SMALLCHAR_WIDTH; } // draw cursor if we have focus if( focus ) { if ( trap_Key_GetOverstrikeMode() ) { c = 11; } else { c = 10; } style &= ~UI_PULSE; style |= UI_BLINK; UI_DrawChar( basex + f->field.cursor * SMALLCHAR_WIDTH, y, c, style, color_white ); } // draw at bottom also using proportional font Q_strncpyz( name, f->field.buffer, sizeof(name) ); Q_CleanStr( name ); UI_DrawProportionalString( 320, 440, name, UI_CENTER|UI_BIGFONT|UI_CURSORSHADOW, text_color_normal ); }
/* =================== Field_Draw Handles horizontal scrolling and cursor blinking x, y, and width are in pixels =================== */ void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, qboolean showCursor, qboolean noColorEscape ) { int len; int drawLen; int prestep; int cursorChar; char str[MAX_STRING_CHARS], *s; int i; int curColor; drawLen = edit->widthInChars - 1; // - 1 so there is always a space for the cursor len = strlen( edit->buffer ); // guarantee that cursor will be visible if ( len <= drawLen ) { prestep = 0; } else { if ( edit->scroll + drawLen > len ) { edit->scroll = len - drawLen; if ( edit->scroll < 0 ) { edit->scroll = 0; } } prestep = edit->scroll; } if ( prestep + drawLen > len ) { drawLen = len - prestep; } // extract <drawLen> characters from the field at <prestep> if ( drawLen >= MAX_STRING_CHARS ) { Com_Error( ERR_DROP, "drawLen >= MAX_STRING_CHARS" ); } Com_Memcpy( str, edit->buffer + prestep, drawLen ); str[ drawLen ] = '\0'; // color tracking curColor = COLOR_WHITE; if ( prestep > 0 ) { // we need to track last actual color because we cut some text before s = edit->buffer; for ( i = 0; i < prestep + 1; i++, s++ ) { if ( *s == Q_COLOR_ESCAPE && *(s+1) != '\0' && *(s+1) != Q_COLOR_ESCAPE ) { curColor = *(s+1); s++; } } // scroll marker // FIXME: force white color? if ( str[0] ) { str[0] = '<'; } } // draw it if ( size == SMALLCHAR_WIDTH ) { SCR_DrawSmallStringExt( x, y, str, g_color_table[ ColorIndex( curColor ) ], qfalse, noColorEscape ); if ( len > drawLen + prestep ) { SCR_DrawSmallChar( x + ( edit->widthInChars - 1 ) * size, y, '>' ); } } else { if ( len > drawLen + prestep ) { SCR_DrawStringExt( x + ( edit->widthInChars - 1 ) * size, y, size, ">", g_color_table[ ColorIndex( COLOR_WHITE ) ], qfalse, noColorEscape ); } // draw big string with drop shadow SCR_DrawStringExt( x, y, size, str, g_color_table[ ColorIndex( curColor ) ], qfalse, noColorEscape ); } // draw the cursor if ( showCursor ) { if ( cls.realtime & 256 ) { return; // off blink } if ( key_overstrikeMode ) { cursorChar = 11; } else { cursorChar = 10; } i = drawLen - strlen( str ); if ( size == SMALLCHAR_WIDTH ) { SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar ); } else { str[0] = cursorChar; str[1] = '\0'; SCR_DrawBigString( x + ( edit->cursor - prestep - i ) * size, y, str, 1.0, qfalse ); } } }
/* ================= Sys_AnsiColorPrint Transform Q3 colour codes to ANSI escape sequences ================= */ void Sys_AnsiColorPrint( const char *msg ) { static char buffer[ MAXPRINTMSG ]; int length = 0; static int q3ToAnsi[ 8 ] = { 30, // COLOR_BLACK 31, // COLOR_RED 32, // COLOR_GREEN 33, // COLOR_YELLOW 34, // COLOR_BLUE 36, // COLOR_CYAN 35, // COLOR_MAGENTA 0 // COLOR_WHITE }; while( *msg ) { if( Q_IsColorString( msg ) || *msg == '\n' ) { // First empty the buffer if( length > 0 ) { buffer[ length ] = '\0'; fputs( buffer, stderr ); length = 0; } if( *msg == '\n' ) { // Issue a reset and then the newline fputs( "\033[0m\n", stderr ); msg++; } else { // Print the color code Com_sprintf( buffer, sizeof( buffer ), "\033[%dm", q3ToAnsi[ ColorIndex( *( msg + 1 ) ) ] ); fputs( buffer, stderr ); msg += 2; } } else { if( length >= MAXPRINTMSG - 1 ) break; buffer[ length ] = *msg; length++; msg++; } } // Empty anything still left in the buffer if( length > 0 ) { buffer[ length ] = '\0'; fputs( buffer, stderr ); } }
void CG_DrawObituary( void ) { linkedList_t *node = NULL; float x = SCREEN_WIDTH/2.0f, y = 0.0f; float lineHeight = 20.0f; float iconSize = lineHeight*2.0f; int fontHandle = MenuFontToHandle( FONT_Q3PSMALL ); float fontScale = 0.8f;//0.2175f; if ( !cg_newObituary->integer ) return; trap->R_SetColor( NULL ); if ( cg_debugHUD.boolean ) { char *attackerName = "AttackerName"; char *targetName = "TargetName"; float attackerWidth = trap->R_Font_StrLenPixels( attackerName, fontHandle, fontScale ); float iconWidth = 2.0f + iconSize + 2.0f; float victimWidth = trap->R_Font_StrLenPixels( targetName, fontHandle, fontScale ); float totalWidth = attackerWidth + iconWidth + victimWidth; float startX = x - totalWidth/2.0f; trap->R_Font_DrawString( startX, y, attackerName, g_color_table[ColorIndex(COLOR_WHITE)], fontHandle, -1, fontScale ); startX += attackerWidth; CG_DrawPic( startX, y-(iconSize/2.0f)+lineHeight/2.0f, iconSize, iconSize, cg_weapons[ weaponFromMOD[MOD_QUANTIZER] ].weaponIcon ); startX += iconWidth; trap->R_Font_DrawString( startX, y, targetName, g_color_table[ColorIndex(COLOR_WHITE)], fontHandle, -1, fontScale ); startX += victimWidth; startX = x - totalWidth/2.0f; y += lineHeight; trap->R_Font_DrawString( startX, y, attackerName, g_color_table[ColorIndex(COLOR_WHITE)], fontHandle, -1, fontScale ); startX += attackerWidth; CG_DrawPic( startX, y-(iconSize/2.0f)+lineHeight/2.0f, iconSize, iconSize, cg_weapons[ weaponFromMOD[MOD_MORTAR] ].weaponIcon ); startX += iconWidth; trap->R_Font_DrawString( startX, y, targetName, g_color_table[ColorIndex(COLOR_WHITE)], fontHandle, -1, fontScale ); startX += victimWidth; startX = x - totalWidth/2.0f; y += lineHeight; trap->R_Font_DrawString( startX, y, attackerName, g_color_table[ColorIndex(COLOR_WHITE)], fontHandle, -1, fontScale ); startX += attackerWidth; CG_DrawPic( startX, y-(iconSize/2.0f)+lineHeight/2.0f, iconSize, iconSize, cg_weapons[ weaponFromMOD[MOD_DIVERGENCE] ].weaponIcon ); startX += iconWidth; trap->R_Font_DrawString( startX, y, targetName, g_color_table[ColorIndex(COLOR_WHITE)], fontHandle, -1, fontScale ); startX += victimWidth; startX = x - totalWidth/2.0f; y += lineHeight; } else { for ( node=cg.q3p.obituaryRoot; node; node=LinkedList_Traverse( node ) ) { obituary_t *obituary = (obituary_t*)node->data; if ( obituary->deathTime < cg.time - cg_obituaryTime->integer ) {//Free this object free( obituary ); LinkedList_RemoveObject( &cg.q3p.obituaryRoot, node ); node = cg.q3p.obituaryRoot;//HACK: Return to start of list continue; } else { float attackerWidth = trap->R_Font_StrLenPixels( obituary->attackerName, fontHandle, fontScale ); float iconWidth = 2.0f + iconSize + 2.0f; float victimWidth = trap->R_Font_StrLenPixels( obituary->targetName, fontHandle, fontScale ); float totalWidth = attackerWidth + iconWidth + victimWidth; float startX = x - totalWidth/2.0f; trap->R_Font_DrawString( startX, y, obituary->attackerName, g_color_table[ColorIndex(COLOR_WHITE)], fontHandle, -1, fontScale ); startX += attackerWidth; CG_DrawPic( startX, y-(iconSize/2.0f)+lineHeight/2.0f, iconSize, iconSize, cg_weapons[ weaponFromMOD[obituary->mod] ].weaponIcon ); startX += iconWidth; trap->R_Font_DrawString( startX, y, obituary->targetName, g_color_table[ColorIndex(COLOR_WHITE)], fontHandle, -1, fontScale ); startX += victimWidth; y += lineHeight; } } } }
/*================== CG_DrawStringExt3 Draws a multi-colored string with a drop shadow, optionally forcing to a fixed color. Coordinates are at 640 by 480 virtual resolution ================== */ void CG_DrawStringExt3( int x, int y, const char *string, const float *setColor, qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars ) { vec4_t color; const char *s; int xx; int cnt; if ( maxChars <= 0 ) { maxChars = 32767; // do them all! } s = string; xx = 0; while ( *s ) { xx += charWidth; s++; } x -= xx; s = string; xx = x; // draw the drop shadow if ( shadow ) { color[0] = color[1] = color[2] = 0; color[3] = setColor[3]; trap_R_SetColor( color ); s = string; xx = x; cnt = 0; while ( *s && cnt < maxChars ) { if ( Q_IsColorString( s ) ) { s += 2; continue; } CG_DrawChar2( xx + 2, y + 2, charWidth, charHeight, *s ); cnt++; xx += charWidth; s++; } } // draw the colored text s = string; xx = x; cnt = 0; trap_R_SetColor( setColor ); while ( *s && cnt < maxChars ) { if ( Q_IsColorString( s ) ) { if ( !forceColor ) { memcpy( color, g_color_table[ColorIndex( *( s + 1 ) )], sizeof( color ) ); color[3] = setColor[3]; trap_R_SetColor( color ); } s += 2; continue; } CG_DrawChar2( xx, y, charWidth, charHeight, *s ); xx += charWidth; cnt++; s++; } trap_R_SetColor( NULL ); }
/* =========== G_ClientCleanName ============ */ static void G_ClientCleanName( const char *in, char *out, int outSize ) { int len, colorlessLen; char *p; int spaces; qboolean escaped; qboolean invalid = qfalse; //save room for trailing null byte outSize--; len = 0; colorlessLen = 0; p = out; *p = 0; spaces = 0; for( ; *in; in++ ) { // don't allow leading spaces if( colorlessLen == 0 && *in == ' ' ) continue; // don't allow nonprinting characters or (dead) console keys if( *in < ' ' || *in > '}' || *in == '`' ) continue; // check colors if( Q_IsColorString( in ) ) { in++; // make sure room in dest for both chars if( len > outSize - 2 ) break; *out++ = Q_COLOR_ESCAPE; // don't allow black in a name, period if( ColorIndex( *in ) == 0 ) *out++ = COLOR_WHITE; else *out++ = *in; 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 == ' ' ) { spaces++; if( spaces > 3 ) continue; } else spaces = 0; if( len > outSize - 1 ) break; *out++ = *in; colorlessLen++; len++; } *out = 0; // don't allow names beginning with "[skipnotify]" because it messes up /ignore-related code if( !Q_stricmpn( p, "[skipnotify]", 12 ) ) invalid = qtrue; // don't allow comment-beginning strings because it messes up various parsers if( strstr( p, "//" ) || strstr( p, "/*" ) ) invalid = qtrue; // don't allow empty names if( *p == 0 || colorlessLen == 0 ) invalid = qtrue; // if something made the name bad, put them back to UnnamedPlayer if( invalid ) Q_strncpyz( p, "UnnamedPlayer", outSize ); }
/** * $(function) */ void SCR_DrawFontText(float x, float y, float scale, vec4_t color, const char *text, int style) { if (!cls.fontFont) return; int len, count; vec4_t newColor; vec4_t black = {0.0f, 0.0f, 0.0f, 1.0f}; vec4_t grey = { 0.2f, 0.2f, 0.2f, 1.0f }; glyphInfo_t *glyph; float useScale; fontInfo_t *font = &cls.font; useScale = scale * font->glyphScale; if (text) { const char *s = text; re.SetColor( color ); memcpy(&newColor[0], &color[0], sizeof(vec4_t)); len = strlen(text); count = 0; while (s && *s && count < len) { glyph = &font->glyphs[(int)*s]; if (Q_IsColorString(s)) { memcpy( newColor, g_color_table[ColorIndex(*(s + 1))], sizeof(newColor)); newColor[3] = color[3]; re.SetColor( newColor ); s += 2; continue; } float yadj = useScale * glyph->top; if ((style == ITEM_TEXTSTYLE_SHADOWED) || (style == ITEM_TEXTSTYLE_SHADOWEDLESS)) { black[3] = newColor[3]; if (style == ITEM_TEXTSTYLE_SHADOWEDLESS) black[3] *= 0.7; if (newColor[0] == 0.0f && newColor[1] == 0.0f && newColor[2] == 0.0f) { grey[3] = black[3]; re.SetColor(grey); } else { re.SetColor(black); } SCR_DrawFontChar(x + 1, y - yadj + 1, glyph->imageWidth, glyph->imageHeight, useScale, glyph->s, glyph->t, glyph->s2, glyph->t2, glyph->glyph); colorBlack[3] = 1.0; re.SetColor(newColor); } SCR_DrawFontChar(x, y - yadj, glyph->imageWidth, glyph->imageHeight, useScale, glyph->s, glyph->t, glyph->s2, glyph->t2, glyph->glyph); x += (glyph->xSkip * useScale); s++; count++; } re.SetColor(NULL); } }
/* =========== ClientCheckName ============ */ static void ClientCleanName(const char *in, char *out, int outSize) { int len, colorlessLen; char ch; char *p; int spaces; // save room for trailing null byte outSize--; len = 0; colorlessLen = 0; p = out; *p = 0; spaces = 0; while(1) { ch = *in++; if(!ch) { break; } // don't allow leading spaces if(colorlessLen == 0 && ch == ' ') { continue; } // check colors if(ch == Q_COLOR_ESCAPE && *in && *in != Q_COLOR_ESCAPE) { // make sure there is room for both chars if((len += 2) > outSize) { break; } *out++ = ch; // don't allow black in a name, period if(ColorIndex(*in) == 0) { *out++ = COLOR_WHITE; in++; continue; } else { *out++ = *in++; } continue; } // don't allow too many consecutive spaces // don't count spaces in colorlessLen if(ch == ' ') { spaces++; if(spaces > 3) { continue; } if(++len > outSize) { break; } *out++ = ch; len++; continue; } else { spaces = 0; } if(++len > outSize) { break; } *out++ = ch; colorlessLen++; } *out = 0; // don't allow empty names if(colorlessLen == 0) { Q_strncpyz(p, "UnnamedPlayer", outSize); } }