/* ================= CG_DrawStrlen Returns draw width, skiping color escape codes ================= */ int CG_DrawStrlen( const char *str, int style ) { const fontInfo_t *font; int charh; if (style & UI_TINYFONT) { font = &cgs.media.tinyFont; charh = TINYCHAR_HEIGHT; } else if (style & UI_SMALLFONT) { font = &cgs.media.smallFont; charh = SMALLCHAR_HEIGHT; } else if (style & UI_GIANTFONT) { font = &cgs.media.bigFont; charh = GIANTCHAR_HEIGHT; } else { font = &cgs.media.textFont; charh = BIGCHAR_HEIGHT; } return Text_Width( str, font, charh / 48.0f, 0 ); }
/* ================= CG_DrawStrlenCommon Returns draw width, skiping color escape codes ================= */ float CG_DrawStrlenCommon( const char *str, int style, const fontInfo_t *font, int maxchars ) { int charh; charh = font->pointSize; if ( !( style & UI_NOSCALE ) && cg.cur_lc ) { if ( cg.numViewports != 1 ) { charh *= cg_splitviewTextScale.value; } else { charh *= cg_hudTextScale.value; } } return Text_Width( str, font, charh / 48.0f, maxchars ); }
/* ============== 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 ); }
void CG_DrawStringExtWithCursor( int x, int y, const char* str, int style, const vec4_t color, float scale, int maxChars, float shadowOffset, int cursorPos, int cursorChar ) { int charh; vec4_t newcolor; vec4_t lowlight; const float *drawcolor; const fontInfo_t *font; int decent; if( !str ) { return; } if ( !color ) { color = colorWhite; } if ((style & UI_BLINK) && ((cg.realTime/BLINK_DIVISOR) & 1)) return; if (style & UI_TINYFONT) { font = &cgs.media.tinyFont; charh = TINYCHAR_HEIGHT; } else if (style & UI_SMALLFONT) { font = &cgs.media.smallFont; charh = SMALLCHAR_HEIGHT; } else if (style & UI_GIANTFONT) { font = &cgs.media.bigFont; charh = GIANTCHAR_HEIGHT; } else { font = &cgs.media.textFont; charh = BIGCHAR_HEIGHT; } if ( scale <= 0 ) { scale = charh / 48.0f; } else { charh = 48 * scale; } if (style & UI_PULSE) { lowlight[0] = 0.8*color[0]; lowlight[1] = 0.8*color[1]; lowlight[2] = 0.8*color[2]; lowlight[3] = 0.8*color[3]; CG_LerpColor(color,lowlight,newcolor,0.5+0.5*sin(cg.realTime/PULSE_DIVISOR)); drawcolor = newcolor; } else drawcolor = color; switch (style & UI_FORMATMASK) { case UI_CENTER: // center justify at x x = x - Text_Width( str, font, scale, 0 ) / 2; break; case UI_RIGHT: // right justify at x x = x - Text_Width( str, font, scale, 0 ); break; default: // left justify at x break; } if ( shadowOffset == 0 && ( style & UI_DROPSHADOW ) ) { shadowOffset = 2; } // This function expects that y is top of line, text_paint expects at baseline decent = -font->glyphs[(int)'g'].top + font->glyphs[(int)'g'].height; y = y + charh - decent * scale * font->glyphScale; if ( cursorChar >= 0 ) { Text_PaintWithCursor( x, y, font, scale, drawcolor, str, cursorPos, cursorChar, 0, maxChars, shadowOffset, ( style & UI_FORCECOLOR ) ); } else { Text_Paint( x, y, font, scale, drawcolor, str, 0, maxChars, shadowOffset, ( style & UI_FORCECOLOR ) ); } }
// Note: Update UI_DrawString in q3_ui if arguments are changed. void CG_DrawStringCommon( int x, int y, const char* str, int style, const fontInfo_t *font, const vec4_t color, float scale, int maxChars, float shadowOffset, float gradient, int cursorPos, int cursorChar, float wrapX ) { int charh; vec4_t newcolor; vec4_t lowlight; const float *drawcolor; int decent; if( !str ) { return; } if ( !color ) { color = colorWhite; } if ((style & UI_BLINK) && ((cg.realTime/BLINK_DIVISOR) & 1)) return; if ( (style & UI_FONTMASK) == UI_NUMBERFONT ) { // the original number bitmaps already have a gradient if ( font->glyphs[(int)'a'].xSkip == 0 ) { style &= ~UI_GRADIENT; } } charh = font->pointSize; if ( shadowOffset == 0 && ( style & UI_DROPSHADOW ) ) { shadowOffset = 2; } if ( gradient == 0 && ( style & UI_GRADIENT ) ) { gradient = 0.4f; } if ( scale <= 0 ) { scale = charh / 48.0f; } else { charh = 48 * scale; } if ( !( style & UI_NOSCALE ) && cg.cur_lc ) { if ( cg.numViewports != 1 ) { shadowOffset *= cg_splitviewTextScale.value; scale *= cg_splitviewTextScale.value; charh *= cg_splitviewTextScale.value; } else { shadowOffset *= cg_hudTextScale.value; scale *= cg_hudTextScale.value; charh *= cg_hudTextScale.value; } } if (style & UI_PULSE) { lowlight[0] = 0.8*color[0]; lowlight[1] = 0.8*color[1]; lowlight[2] = 0.8*color[2]; lowlight[3] = 0.8*color[3]; CG_LerpColor(color,lowlight,newcolor,0.5+0.5*sin(cg.realTime/PULSE_DIVISOR)); drawcolor = newcolor; } else drawcolor = color; if ( wrapX <= 0 ) { switch (style & UI_FORMATMASK) { case UI_CENTER: // center justify at x x = x - Text_Width( str, font, scale, 0 ) / 2; break; case UI_RIGHT: // right justify at x x = x - Text_Width( str, font, scale, 0 ); break; case UI_LEFT: default: // left justify at x break; } switch (style & UI_VA_FORMATMASK) { case UI_VA_CENTER: // center justify at y y = y - charh /*Text_Height( str, font, scale, 0 )*/ / 2; break; case UI_VA_BOTTOM: // bottom justify at y y = y - charh /*Text_Height( str, font, scale, 0 )*/; break; case UI_VA_TOP: default: // top justify at y break; } } // // This function expects that y is top of line, text_paint expects at baseline // decent = -font->glyphs[(int)'g'].top + font->glyphs[(int)'g'].height; y = y + charh - decent * scale * font->glyphScale; if ( decent != 0 ) { // Make TrueType fonts line up with bigchars bitmap font which has 2 transparent pixels above glyphs at 16 point font size y += 2.0f * charh / 16.0f; } if ( cursorChar >= 0 ) { Text_PaintWithCursor( x, y, font, scale, drawcolor, str, cursorPos, cursorChar, 0, maxChars, shadowOffset, gradient, !!( style & UI_FORCECOLOR ), !!( style & UI_INMOTION ) ); } else if ( wrapX > 0 ) { // replace 'char height' in line height with our scaled charh // ZTM: TODO: This text gap handling is kind of messy. Passing scale to CG_DrawStringLineHeight might make cleaner code here. int gap = CG_DrawStringLineHeight( style | UI_NOSCALE ) - font->pointSize; if ( !( style & UI_NOSCALE ) && cg.cur_lc ) { if ( cg.numViewports != 1 ) { gap *= cg_splitviewTextScale.value; } else { gap *= cg_hudTextScale.value; } } Text_Paint_AutoWrapped( x, y, font, scale, drawcolor, str, 0, maxChars, shadowOffset, gradient, !!( style & UI_FORCECOLOR ), !!( style & UI_INMOTION ), wrapX, charh + gap, style ); } else { Text_Paint( x, y, font, scale, drawcolor, str, 0, maxChars, shadowOffset, gradient, !!( style & UI_FORCECOLOR ), !!( style & UI_INMOTION ) ); } }