void IN_DrawTime(int x, int y, int h, int m, int s, float r, float g, float b, float a) { char buf[20]; dd_snprintf(buf, 20, "%02d", s); M_DrawTextFragmentShadowed(buf, x, y, ALIGN_TOPRIGHT, 0, r, g, b, a); x -= FR_TextWidth(buf) + FR_Tracking() * 3; M_DrawTextFragmentShadowed(":", x, y, ALIGN_TOPRIGHT, 0, r, g, b, a); x -= FR_CharWidth(':') + 3; if(m || h) { dd_snprintf(buf, 20, "%02d", m); M_DrawTextFragmentShadowed(buf, x, y, ALIGN_TOPRIGHT, 0, r, g, b, a); x -= FR_TextWidth(buf) + FR_Tracking() * 3; } if(h) { dd_snprintf(buf, 20, "%02d", h); M_DrawTextFragmentShadowed(":", x, y, ALIGN_TOPRIGHT, 0, r, g, b, a); x -= FR_CharWidth(':') + FR_Tracking() * 3; M_DrawTextFragmentShadowed(buf, x, y, ALIGN_TOPRIGHT, 0, r, g, b, a); } }
static void drawTime(Vector2i origin, int hours, int minutes, int seconds, Vector4f rgba) { char buf[20]; dd_snprintf(buf, 20, "%02d", seconds); M_DrawTextFragmentShadowed(buf, origin.x, origin.y, ALIGN_TOPRIGHT, 0, rgba.x, rgba.y, rgba.z, rgba.w); origin.x -= FR_TextWidth(buf) + FR_Tracking() * 3; M_DrawTextFragmentShadowed(":", origin.x, origin.y, ALIGN_TOPRIGHT, 0, rgba.x, rgba.y, rgba.z, rgba.w); origin.x -= FR_CharWidth(':') + 3; if(minutes || hours) { dd_snprintf(buf, 20, "%02d", minutes); M_DrawTextFragmentShadowed(buf, origin.x, origin.y, ALIGN_TOPRIGHT, 0, rgba.x, rgba.y, rgba.z, rgba.w); origin.x -= FR_TextWidth(buf) + FR_Tracking() * 3; } if(hours) { dd_snprintf(buf, 20, "%02d", hours); M_DrawTextFragmentShadowed(":", origin.x, origin.y, ALIGN_TOPRIGHT, 0, rgba.x, rgba.y, rgba.z, rgba.w); origin.x -= FR_CharWidth(':') + FR_Tracking() * 3; M_DrawTextFragmentShadowed(buf, origin.x, origin.y, ALIGN_TOPRIGHT, 0, rgba.x, rgba.y, rgba.z, rgba.w); } }
static int textFragmentWidth(const char* fragment) { assert(NULL != fragment); { size_t i, len; int width = 0; const char* ch; unsigned char c; if(fr.fontNum == 0) { Con_Error("textFragmentHeight: Cannot determine height without a current font."); exit(1); } // Just add them together. len = strlen(fragment); i = 0; ch = fragment; while(i++ < len && (c = *ch++) != 0 && c != '\n') width += FR_CharWidth(c); return (int) (width + currentAttribs()->tracking * (len-1)); } }
/** * Display map completion time and par, or "sucks" message if overflow. */ static void drawTime(int x, int y, int t) { patchinfo_t info; if(t < 0) return; if(t <= 61 * 59) { int seconds = t % 60, minutes = t / 60 % 60; char buf[20]; x -= 22; FR_DrawCharXY3(':', x, y, ALIGN_TOPLEFT, DTF_NO_TYPEIN); if(minutes > 0) { dd_snprintf(buf, 20, "%d", minutes); FR_DrawTextXY3(buf, x, y, ALIGN_TOPRIGHT, DTF_NO_TYPEIN); } dd_snprintf(buf, 20, "%02d", seconds); FR_DrawTextXY3(buf, x+FR_CharWidth(':'), y, ALIGN_TOPLEFT, DTF_NO_TYPEIN); return; } // "sucks" if(!R_GetPatchInfo(pSucks, &info)) return; WI_DrawPatchXY3(pSucks, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pSucks), x - info.geometry.size.width, y, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); }
void UIChat_UpdateGeometry(uiwidget_t* obj) { const char* text = UIChat_Text(obj); assert(obj->type == GUI_CHAT); Rect_SetWidthHeight(obj->geometry, 0, 0); if(!UIChat_IsActive(obj)) return; FR_SetFont(obj->font); Rect_SetWidthHeight(obj->geometry, cfg.msgScale * (FR_TextWidth(text) + FR_CharWidth('_')), cfg.msgScale * (MAX_OF(FR_TextHeight(text), FR_CharHeight('_')))); }
void UIChat_Drawer(uiwidget_t* obj, const Point2Raw* offset) { //guidata_chat_t* chat = (guidata_chat_t*)obj->typedata; const float textAlpha = uiRendState->pageAlpha * cfg.hudColor[3]; //const float iconAlpha = uiRendState->pageAlpha * cfg.hudIconAlpha; const char* text = UIChat_Text(obj); int xOffset, textWidth, cursorWidth; assert(obj->type == GUI_CHAT); if(!UIChat_IsActive(obj)) return; DGL_MatrixMode(DGL_MODELVIEW); DGL_PushMatrix(); if(offset) DGL_Translatef(offset->x, offset->y, 0); DGL_Scalef(cfg.msgScale, cfg.msgScale, 1); FR_SetFont(obj->font); FR_SetColorAndAlpha(cfg.hudColor[CR], cfg.hudColor[CG], cfg.hudColor[CB], textAlpha); textWidth = FR_TextWidth(text); cursorWidth = FR_CharWidth('_'); if(cfg.msgAlign == 1) xOffset = -(textWidth + cursorWidth)/2; else if(cfg.msgAlign == 2) xOffset = -(textWidth + cursorWidth); else xOffset = 0; DGL_Enable(DGL_TEXTURE_2D); FR_DrawTextXY(text, xOffset, 0); if(actualMapTime & 12) { FR_DrawCharXY('_', xOffset + textWidth, 0); } DGL_Disable(DGL_TEXTURE_2D); DGL_MatrixMode(DGL_MODELVIEW); DGL_PopMatrix(); }
void LineEditWidget::updateGeometry() { FR_SetFont(mnRendState->textFonts[font()]); geometry().setSize(Vector2ui(FR_CharWidth('w') * d->maxLength - MNDATA_EDIT_BACKGROUND_OFFSET_X*2, 14)); }
static void textFragmentDrawer(const char* fragment, int x, int y, int alignFlags, short textFlags, int initialCount) { assert(fragment && fragment[0]); { font_t* font = Fonts_ToFont(fr.fontNum); fr_state_attributes_t* sat = currentAttribs(); boolean noTypein = (textFlags & DTF_NO_TYPEIN) != 0; boolean noGlitter = (sat->glitterStrength <= 0 || (textFlags & DTF_NO_GLITTER) != 0); boolean noShadow = (sat->shadowStrength <= 0 || (textFlags & DTF_NO_SHADOW) != 0 || (Font_Flags(font) & FF_SHADOWED) != 0); boolean noCharacter = (textFlags & DTF_NO_CHARACTER) != 0; float glitter = (noGlitter? 0 : sat->glitterStrength), glitterMul; float shadow = (noShadow ? 0 : sat->shadowStrength), shadowMul; float flashColor[3] = { 0, 0, 0 }; int w, h, cx, cy, count, yoff; unsigned char c; const char* ch; if(alignFlags & ALIGN_RIGHT) x -= textFragmentWidth(fragment); else if(!(alignFlags & ALIGN_LEFT)) x -= textFragmentWidth(fragment)/2; if(alignFlags & ALIGN_BOTTOM) y -= textFragmentHeight(fragment); else if(!(alignFlags & ALIGN_TOP)) y -= textFragmentHeight(fragment)/2; if(!(noTypein && noGlitter)) { flashColor[CR] = (1 + 2 * sat->rgba[CR]) / 3; flashColor[CG] = (1 + 2 * sat->rgba[CG]) / 3; flashColor[CB] = (1 + 2 * sat->rgba[CB]) / 3; } if(renderWireframe > 1) { DENG_ASSERT_IN_MAIN_THREAD(); DENG_ASSERT_GL_CONTEXT_ACTIVE(); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glDisable(GL_TEXTURE_2D); } if(Font_Type(font) == FT_BITMAP && 0 != BitmapFont_GLTextureName(font)) { GL_BindTextureUnmanaged(BitmapFont_GLTextureName(font), GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, filterUI? GL_LINEAR : GL_NEAREST); glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glScalef(1.f / BitmapFont_TextureWidth(font), 1.f / BitmapFont_TextureHeight(font), 1.f); } { int pass; for(pass = (noShadow? 1 : 0); pass < (noCharacter && noGlitter? 1 : 2); ++pass) { count = initialCount; ch = fragment; cx = x + (pass == 0? sat->shadowOffsetX : 0); cy = y + (pass == 0? sat->shadowOffsetY : 0); for(;;) { c = *ch++; yoff = 0; glitter = (noGlitter? 0 : sat->glitterStrength); glitterMul = 0; shadow = (noShadow? 0 : sat->shadowStrength); shadowMul = (noShadow? 0 : sat->rgba[CA]); // Do the type-in effect? if(!noTypein && (pass || (!noShadow && !pass))) { int maxCount = (typeInTime > 0? typeInTime * 2 : 0); if(pass) { if(!noGlitter) { if(count == maxCount) { glitterMul = 1; flashColor[CR] = sat->rgba[CR]; flashColor[CG] = sat->rgba[CG]; flashColor[CB] = sat->rgba[CB]; } else if(count + 1 == maxCount) { glitterMul = 0.88f; flashColor[CR] = (1 + sat->rgba[CR]) / 2; flashColor[CG] = (1 + sat->rgba[CG]) / 2; flashColor[CB] = (1 + sat->rgba[CB]) / 2; } else if(count + 2 == maxCount) { glitterMul = 0.75f; flashColor[CR] = sat->rgba[CR]; flashColor[CG] = sat->rgba[CG]; flashColor[CB] = sat->rgba[CB]; } else if(count + 3 == maxCount) { glitterMul = 0.5f; flashColor[CR] = sat->rgba[CR]; flashColor[CG] = sat->rgba[CG]; flashColor[CB] = sat->rgba[CB]; } else if(count > maxCount) { break; } } else if(count > maxCount) { break; } } else { if(count == maxCount) { shadowMul = 0; } else if(count + 1 == maxCount) { shadowMul *= .25f; } else if(count + 2 == maxCount) { shadowMul *= .5f; } else if(count + 3 == maxCount) { shadowMul *= .75f; } else if(count > maxCount) { break; } } } count++; if(!c || c == '\n') break; w = FR_CharWidth(c); h = FR_CharHeight(c); if(' ' != c) { // A non-white-space character we have a glyph for. if(pass) { if(!noCharacter) { // The character itself. glColor4fv(sat->rgba); drawChar(c, cx, cy + yoff, font, ALIGN_TOPLEFT, DTF_NO_EFFECTS); } if(!noGlitter && glitter > 0) { // Do something flashy. Point2Raw origin; Size2Raw size; origin.x = cx; origin.y = cy + yoff; size.width = w; size.height = h; glColor4f(flashColor[CR], flashColor[CG], flashColor[CB], glitter * glitterMul); drawFlash(&origin, &size, true); } } else if(!noShadow) { Point2Raw origin; Size2Raw size; origin.x = cx; origin.y = cy + yoff; size.width = w; size.height = h; glColor4f(1, 1, 1, shadow * shadowMul); drawFlash(&origin, &size, false); } } cx += w + sat->tracking; } }} // Restore previous GL-state. if(renderWireframe > 1) { /// @todo do not assume previous state. glEnable(GL_TEXTURE_2D); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } if(Font_Type(font) == FT_BITMAP && 0 != BitmapFont_GLTextureName(font)) { glMatrixMode(GL_TEXTURE); glPopMatrix(); } } }
int FR_TextWidth(const char* string) { int w, maxWidth = -1; boolean skipping = false, escaped = false; const char* ch; size_t i, len; errorIfNotInited("FR_TextWidth"); if(!string || !string[0]) return 0; /// @todo All visual format parsing should be done in one place. w = 0; len = strlen(string); ch = string; for(i = 0; i < len; ++i, ch++) { unsigned char c = *ch; if(c == FR_FORMAT_ESCAPE_CHAR) { escaped = true; continue; } if(!escaped && c == '{') { skipping = true; } else if(skipping && c == '}') { skipping = false; continue; } if(skipping) continue; escaped = false; if(c == '\n') { if(w > maxWidth) maxWidth = w; w = 0; continue; } w += FR_CharWidth(c); if(i != len - 1) { w += FR_Tracking(); } else if(maxWidth == -1) { maxWidth = w; } } return maxWidth; }
static void drawNetgameStats(void) { #define ORIGINX (NG_STATSX + starWidth/2 + NG_STATSX*!doFrags) int i, x, y, starWidth, pwidth; patchinfo_t info; DGL_Enable(DGL_TEXTURE_2D); DGL_Color4f(1, 1, 1, 1); FR_SetFont(FID(GF_FONTB)); FR_LoadDefaultAttrib(); FR_SetColorAndAlpha(defFontRGB2[CR], defFontRGB2[CG], defFontRGB2[CB], 1); pwidth = FR_CharWidth('%'); R_GetPatchInfo(pFaceAlive, &info); starWidth = info.geometry.size.width; // Draw stat titles (top line). R_GetPatchInfo(pKills, &info); WI_DrawPatchXY3(pKills, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pKills), ORIGINX + NG_SPACINGX, NG_STATSY, ALIGN_TOPRIGHT, 0, DTF_NO_TYPEIN); y = NG_STATSY + info.geometry.size.height; WI_DrawPatchXY3(pItems, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pItems), ORIGINX + 2 * NG_SPACINGX, NG_STATSY, ALIGN_TOPRIGHT, 0, DTF_NO_TYPEIN); WI_DrawPatchXY3(pSecret, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pSecret), ORIGINX + 3 * NG_SPACINGX, NG_STATSY, ALIGN_TOPRIGHT, 0, DTF_NO_TYPEIN); if(doFrags) { WI_DrawPatchXY3(pFrags, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pFrags), ORIGINX + 4 * NG_SPACINGX, NG_STATSY, ALIGN_TOPRIGHT, 0, DTF_NO_TYPEIN); } // Draw stats. for(i = 0; i < NUMTEAMS; ++i) { patchinfo_t info; if(0 == teamInfo[i].playerCount) continue; FR_SetFont(FID(GF_FONTA)); FR_SetColorAndAlpha(1, 1, 1, 1); x = ORIGINX; R_GetPatchInfo(pTeamBackgrounds[i], &info); WI_DrawPatchXY3(pTeamBackgrounds[i], Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pTeamBackgrounds[i]), x - info.geometry.size.width, y, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); // If more than 1 member, show the member count. if(1 != teamInfo[i].playerCount) { char tmp[40]; sprintf(tmp, "%i", teamInfo[i].playerCount); FR_DrawTextXY3(tmp, x - info.geometry.size.width + 1, y + info.geometry.size.height - 8, ALIGN_TOPLEFT, DTF_NO_TYPEIN); } FR_SetColorAndAlpha(defFontRGB2[CR], defFontRGB2[CG], defFontRGB2[CB], 1); if(i == inPlayerTeam) WI_DrawPatchXY3(pFaceAlive, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pFaceAlive), x - info.geometry.size.width, y, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); x += NG_SPACINGX; FR_SetFont(FID(GF_SMALL)); drawPercent(x - pwidth, y + 10, cntKills[i]); x += NG_SPACINGX; drawPercent(x - pwidth, y + 10, cntItems[i]); x += NG_SPACINGX; drawPercent(x - pwidth, y + 10, cntSecret[i]); x += NG_SPACINGX; if(doFrags) { char buf[20]; dd_snprintf(buf, 20, "%i", cntFrags[i]); FR_DrawTextXY3(buf, x, y + 10, ALIGN_TOPRIGHT, DTF_NO_TYPEIN); } y += WI_SPACINGY; } DGL_Disable(DGL_TEXTURE_2D); #undef ORIGINX }
static void drawDeathmatchStats(void) { int i, j, x, y, w;// lh = WI_SPACINGY; // Line height. DGL_Enable(DGL_TEXTURE_2D); DGL_Color4f(1, 1, 1, 1); FR_SetFont(FID(GF_FONTB)); FR_LoadDefaultAttrib(); FR_SetColorAndAlpha(defFontRGB2[CR], defFontRGB2[CG], defFontRGB2[CB], 1); // Draw stat titles (top line). { patchinfo_t info; if(R_GetPatchInfo(pTotal, &info)) WI_DrawPatchXY3(pTotal, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pTotal), DM_TOTALSX - info.geometry.size.width / 2, DM_MATRIXY - WI_SPACINGY + 10, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); } WI_DrawPatchXY3(pKillers, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pKillers), DM_KILLERSX, DM_KILLERSY, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); WI_DrawPatchXY3(pVictims, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pVictims), DM_VICTIMSX, DM_VICTIMSY, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); x = DM_MATRIXX + DM_SPACINGX; y = DM_MATRIXY; for(i = 0; i < NUMTEAMS; ++i) { if(teamInfo[i].playerCount > 0) { patchid_t patchId = pTeamBackgrounds[i]; const char* replacement; patchinfo_t info; FR_SetColorAndAlpha(defFontRGB2[CR], defFontRGB2[CG], defFontRGB2[CB], 1); R_GetPatchInfo(patchId, &info); replacement = Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, patchId); WI_DrawPatchXY3(patchId, replacement, x - info.geometry.size.width / 2, DM_MATRIXY - WI_SPACINGY, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); WI_DrawPatchXY3(patchId, replacement, DM_MATRIXX - info.geometry.size.width / 2, y, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); if(i == inPlayerTeam) { WI_DrawPatchXY3(pFaceDead, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pFaceDead), x - info.geometry.size.width / 2, DM_MATRIXY - WI_SPACINGY, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); WI_DrawPatchXY3(pFaceAlive, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pFaceAlive), DM_MATRIXX - info.geometry.size.width / 2, y, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); } // If more than 1 member, show the member count. if(1 > teamInfo[i].playerCount) { char tmp[20]; sprintf(tmp, "%i", teamInfo[i].playerCount); FR_SetFont(FID(GF_FONTA)); FR_DrawTextXY3(tmp, x - info.geometry.size.width / 2 + 1, DM_MATRIXY - WI_SPACINGY + info.geometry.size.height - 8, ALIGN_TOPLEFT, DTF_NO_TYPEIN); FR_DrawTextXY3(tmp, DM_MATRIXX - info.geometry.size.width / 2 + 1, y + info.geometry.size.height - 8, ALIGN_TOPLEFT, DTF_NO_TYPEIN); } } else { patchid_t patchId = pTeamIcons[i]; const char* replacement = Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, patchId); patchinfo_t info; FR_SetColorAndAlpha(defFontRGB[CR], defFontRGB[CG], defFontRGB[CB], 1); R_GetPatchInfo(patchId, &info); WI_DrawPatchXY3(patchId, replacement, x - info.geometry.size.width / 2, DM_MATRIXY - WI_SPACINGY + 10, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); WI_DrawPatchXY3(patchId, replacement, DM_MATRIXX - info.geometry.size.width / 2, y + 10, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); } x += DM_SPACINGX; y += WI_SPACINGY; } // Draw stats. y = DM_MATRIXY + 10; FR_SetFont(FID(GF_SMALL)); FR_SetColorAndAlpha(defFontRGB2[CR], defFontRGB2[CG], defFontRGB2[CB], 1); w = FR_CharWidth('0'); for(i = 0; i < NUMTEAMS; ++i) { x = DM_MATRIXX + DM_SPACINGX; if(teamInfo[i].playerCount > 0) { char buf[20]; for(j = 0; j < NUMTEAMS; ++j) { if(teamInfo[j].playerCount > 0) { dd_snprintf(buf, 20, "%i", dmFrags[i][j]); FR_DrawTextXY3(buf, x + w, y, ALIGN_TOPRIGHT, DTF_NO_TYPEIN); } x += DM_SPACINGX; } dd_snprintf(buf, 20, "%i", dmTotals[i]); FR_DrawTextXY3(buf, DM_TOTALSX + w, y, ALIGN_TOPRIGHT, DTF_NO_TYPEIN); } y += WI_SPACINGY; } DGL_Disable(DGL_TEXTURE_2D); }