X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=gl_draw.c;h=da5935015d4332cd57e79aa22fa947cc681845b6;hb=ab9c17fbb62210574e50347558b6a1cbce9c390e;hp=a891e89e35fc9e86c56dd174b93f9c082f4093ca;hpb=5b46069b0ac5931cfad920d61d828a3adbbc4a76;p=xonotic%2Fdarkplaces.git diff --git a/gl_draw.c b/gl_draw.c index a891e89e..da593501 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -289,7 +289,7 @@ static rtexture_t *draw_generatepic(const char *name, qboolean quiet) if (!strcmp(name, "gfx/colorcontrol/ditherpattern")) return draw_generateditherpattern(); if (!quiet) - Con_Printf("Draw_CachePic: failed to load %s\n", name); + Con_DPrintf("Draw_CachePic: failed to load %s\n", name); return r_texture_notexture; } @@ -532,6 +532,7 @@ void Draw_FreePic(const char *picname) } } +static float snap_to_pixel_x(float x, float roundUpAt); extern int con_linewidth; // to force rewrapping static void LoadFont(qboolean override, const char *name, dp_font_t *fnt) { @@ -558,14 +559,27 @@ static void LoadFont(qboolean override, const char *name, dp_font_t *fnt) if(fnt->req_face != -1) { if(!Font_LoadFont(fnt->texpath, fnt)) - Con_Printf("Failed to load font-file for '%s', it will not support as many characters.\n", fnt->texpath); + Con_DPrintf("Failed to load font-file for '%s', it will not support as many characters.\n", fnt->texpath); } fnt->tex = Draw_CachePic_Flags(fnt->texpath, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex; if(fnt->tex == r_texture_notexture) { - fnt->tex = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION)->tex; - strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile)); + for (i = 0; i < MAX_FONT_FALLBACKS; ++i) + { + if (!fnt->fallbacks[i][0]) + break; + fnt->tex = Draw_CachePic_Flags(fnt->fallbacks[i], CACHEPICFLAG_QUIET | CACHEPICFLAG_NOCOMPRESSION)->tex; + if(fnt->tex != r_texture_notexture) + break; + } + if(fnt->tex == r_texture_notexture) + { + fnt->tex = Draw_CachePic_Flags("gfx/conchars", CACHEPICFLAG_NOCOMPRESSION)->tex; + strlcpy(widthfile, "gfx/conchars.width", sizeof(widthfile)); + } + else + dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->fallbacks[i]); } else dpsnprintf(widthfile, sizeof(widthfile), "%s.width", fnt->texpath); @@ -602,7 +616,19 @@ static void LoadFont(qboolean override, const char *name, dp_font_t *fnt) case '+': case '-': case '.': - fnt->width_of[ch++] = atof(com_token) + extraspacing; + fnt->width_of[ch] = atof(com_token) + extraspacing; + if (fnt->ft2) + { + for (i = 0; i < MAX_FONT_SIZES; ++i) + { + //Font_MapForIndex(fnt->ft2, i)->width_of[ch] = snap_to_pixel_x(fnt->width_of[ch] * fnt->req_sizes[i], 0.4); + ft2_font_map_t *map = Font_MapForIndex(fnt->ft2, i); + if (!map) + break; + map->width_of[ch] = Font_SnapTo(fnt->width_of[ch], 1/map->size); + } + } + ch++; break; default: if(!strcmp(com_token, "extraspacing")) @@ -681,9 +707,9 @@ static float snap_to_pixel_y(float y, float roundUpAt) static void LoadFont_f(void) { dp_font_t *f; - int i, si; - float sz, sn; + int i; const char *filelist, *c, *cm; + float sz; char mainfont[MAX_QPATH]; if(Cmd_Argc() < 2) @@ -769,28 +795,12 @@ static void LoadFont_f(void) for(i = 1; i < MAX_FONT_SIZES; ++i) f->req_sizes[i] = -1; - // for some reason this argc is 3 even when using 2 arguments here, maybe nexuiz screws up if(Cmd_Argc() >= 3) { for(i = 0; i < Cmd_Argc()-3; ++i) { sz = atof(Cmd_Argv(i+3)); - if (IS_NAN(sz)) // do not use crap sizes - continue; - // now try to scale to our actual size: - if (vid.width > 0) - sn = snap_to_pixel_y(sz, 0.5); - else - { - sn = sz * vid_height.value / vid_conheight.value; - si = (int)sn; - if ( sn - (float)si >= 0.5 ) - ++si; - sn = si * vid_conheight.value / vid_height.value; - } - if (!IS_NAN(sn)) - f->req_sizes[i] = sn; - else + if (sz > 0.001f && sz < 1000.0f) // do not use crap sizes f->req_sizes[i] = sz; } } @@ -855,7 +865,6 @@ void GL_Draw_Init (void) for(i = 0, j = 0; i < MAX_USERFONTS; ++i) if(!FONT_USER[i].title[0]) dpsnprintf(FONT_USER[i].title, sizeof(FONT_USER[i].title), "user%d", j++); - Font_Init(); } void _DrawQ_Setup(void) @@ -1073,7 +1082,8 @@ static void DrawQ_GetTextColor(float color[4], int colorindex, float r, float g, } } -float DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(const char *text, float w, float h, size_t *maxlen, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth) +// NOTE: this function always draws exactly one character if maxwidth <= 0 +float DrawQ_TextWidth_UntilWidth_TrackColors_Scale(const char *text, size_t *maxlen, float w, float h, float sw, float sh, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth) { const char *text_start = text; int colorindex = STRING_COLOR_DEFAULT; @@ -1091,6 +1101,9 @@ float DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(const char *text, float w ft2_font_t *ft2 = fnt->ft2; // float ftbase_x; qboolean snap = true; + qboolean least_one = false; + float dw, dh; // display w/h + const float *width_of; if (!h) h = w; if (!h) { @@ -1111,6 +1124,9 @@ float DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(const char *text, float w fontmap = Font_MapForIndex(ft2, map_index); } + dw = w * sw; + dh = h * sh; + if (*maxlen < 1) *maxlen = 1<<30; @@ -1121,26 +1137,42 @@ float DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(const char *text, float w // maxwidth /= fnt->scale; // w and h are multiplied by it already // ftbase_x = snap_to_pixel_x(0); + + if(maxwidth <= 0) + { + least_one = true; + maxwidth = -maxwidth; + } + + //if (snap) + // x = snap_to_pixel_x(x, 0.4); // haha, it's 0 anyway + + if (fontmap) + width_of = fontmap->width_of; + else + width_of = fnt->width_of; for (i = 0;((bytes_left = *maxlen - (text - text_start)) > 0) && *text;) { + size_t i0 = i; nextch = ch = u8_getnchar(text, &text, bytes_left); - //i = text - text_start; + i = text - text_start; if (!ch) break; - if (snap) - x = snap_to_pixel_x(x, 0.4); if (ch == ' ' && !fontmap) { - if(x + fnt->width_of[(int) ' '] * w > maxwidth) + if(!least_one || i0) // never skip the first character + if(x + width_of[(int) ' '] * dw > maxwidth) + { + i = i0; break; // oops, can't draw this - x += fnt->width_of[(int) ' '] * w; - ++i; + } + x += width_of[(int) ' '] * dw; continue; } - if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i + 1 < *maxlen) + // i points to the char after ^ + if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < *maxlen) { - ++i; ch = *text; // colors are ascii, so no u8_ needed if (ch <= '9' && ch >= '0') // ^[0-9] found { @@ -1149,6 +1181,9 @@ float DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(const char *text, float w ++i; continue; } + // i points to the char after ^... + // i+3 points to 3 in ^x123 + // i+3 == *maxlen would mean that char is missing else if (ch == STRING_COLOR_RGB_TAG_CHAR && i + 3 < *maxlen ) // ^x found { // building colorindex... @@ -1188,7 +1223,6 @@ float DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(const char *text, float w i--; } ch = nextch; - ++i; if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF)) { @@ -1199,9 +1233,13 @@ float DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(const char *text, float w if (fontmap) map = ft2_oldstyle_map; prevch = 0; - if(x + fnt->width_of[ch] * w > maxwidth) + if(!least_one || i0) // never skip the first character + if(x + width_of[ch] * dw > maxwidth) + { + i = i0; break; // oops, can't draw this - x += fnt->width_of[ch] * w; + } + x += width_of[ch] * dw; } else { if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch) { @@ -1216,8 +1254,8 @@ float DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(const char *text, float w } mapch = ch - map->start; if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, NULL)) - x += kx * w; - x += map->glyphs[mapch].advance_x * w; + x += kx * dw; + x += map->glyphs[mapch].advance_x * dw; prevmap = map; prevch = ch; } @@ -1231,7 +1269,7 @@ float DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(const char *text, float w return x; } -float DrawQ_String_Font(float startx, float starty, const char *text, size_t maxlen, float w, float h, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt) +float DrawQ_String_Scale(float startx, float starty, const char *text, size_t maxlen, float w, float h, float sw, float sh, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt) { int shadow, colorindex = STRING_COLOR_DEFAULT; size_t i; @@ -1256,6 +1294,8 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max qboolean snap = true; float pix_x, pix_y; size_t bytes_left; + float dw, dh; + const float *width_of; int tw, th; tw = R_TextureWidth(fnt->tex); @@ -1280,9 +1320,12 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max fontmap = Font_MapForIndex(ft2, map_index); } + dw = w * sw; + dh = h * sh; + // draw the font at its baseline when using freetype //ftbase_x = 0; - ftbase_y = h * (4.5/6.0); + ftbase_y = dh * (4.5/6.0); if (maxlen < 1) maxlen = 1<<30; @@ -1292,7 +1335,7 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max R_Mesh_ColorPointer(color4f, 0, 0); R_Mesh_ResetTextureState(); if (!fontmap) - R_Mesh_TexBind(0, R_GetTexture(fnt->tex)); + R_Mesh_TexBind(0, fnt->tex); R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0); R_Mesh_VertexPointer(vertex3f, 0, 0); R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1); @@ -1303,12 +1346,24 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max batchcount = 0; //ftbase_x = snap_to_pixel_x(ftbase_x); - ftbase_y = snap_to_pixel_y(ftbase_y, 0.3); + if(snap) + { + startx = snap_to_pixel_x(startx, 0.4); + starty = snap_to_pixel_y(starty, 0.4); + ftbase_y = snap_to_pixel_y(ftbase_y, 0.3); + } pix_x = vid.width / vid_conwidth.value; pix_y = vid.height / vid_conheight.value; + + if (fontmap) + width_of = fontmap->width_of; + else + width_of = fnt->width_of; + for (shadow = r_textshadow.value != 0 && basealpha > 0;shadow >= 0;shadow--) { + prevch = 0; text = text_start; if (!outcolor || *outcolor == -1) @@ -1330,23 +1385,16 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max for (i = 0;((bytes_left = maxlen - (text - text_start)) > 0) && *text;) { nextch = ch = u8_getnchar(text, &text, bytes_left); - //i = text - text_start; + i = text - text_start; if (!ch) break; - if (snap) - { - x = snap_to_pixel_x(x, 0.4); - y = snap_to_pixel_y(y, 0.4); - } if (ch == ' ' && !fontmap) { - x += fnt->width_of[(int) ' '] * w; - ++i; + x += width_of[(int) ' '] * dw; continue; } - if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i + 1 < maxlen) + if (ch == STRING_COLOR_TAG && !ignorecolorcodes && i < maxlen) { - ++i; ch = *text; // colors are ascii, so no u8_ needed if (ch <= '9' && ch >= '0') // ^[0-9] found { @@ -1398,14 +1446,13 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max } // get the backup ch = nextch; - ++i; // using a value of -1 for the oldstyle map because NULL means uninitialized... // this way we don't need to rebind fnt->tex for every old-style character // E000..E0FF: emulate old-font characters (to still have smileys and such available) if (shadow) { - x += pix_x * r_textshadow.value; - y += pix_y * r_textshadow.value; + x += 1.0/pix_x * r_textshadow.value; + y += 1.0/pix_y * r_textshadow.value; } if (!fontmap || (ch <= 0xFF && fontmap->glyphs[ch].image) || (ch >= 0xE000 && ch <= 0xE0FF)) { @@ -1420,9 +1467,7 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max if (batchcount) { // switching from freetype to non-freetype rendering - GL_LockArrays(0, batchcount * 4); R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0); - GL_LockArrays(0, 0); batchcount = 0; ac = color4f; at = texcoord2f; @@ -1450,24 +1495,22 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max at[ 4] = s+u ; at[ 5] = t+v ; at[ 6] = s ; at[ 7] = t+v ; av[ 0] = x ; av[ 1] = y ; av[ 2] = 10; - av[ 3] = x+w*thisw ; av[ 4] = y ; av[ 5] = 10; - av[ 6] = x+w*thisw ; av[ 7] = y+h ; av[ 8] = 10; - av[ 9] = x ; av[10] = y+h ; av[11] = 10; + av[ 3] = x+dw*thisw ; av[ 4] = y ; av[ 5] = 10; + av[ 6] = x+dw*thisw ; av[ 7] = y+dh ; av[ 8] = 10; + av[ 9] = x ; av[10] = y+dh ; av[11] = 10; ac += 16; at += 8; av += 12; batchcount++; if (batchcount >= QUADELEMENTS_MAXQUADS) { - GL_LockArrays(0, batchcount * 4); R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0); - GL_LockArrays(0, 0); batchcount = 0; ac = color4f; at = texcoord2f; av = vertex3f; } - x += thisw * w; + x += width_of[ch] * dw; } else { if (!map || map == ft2_oldstyle_map || map->start < ch || map->start + FONT_CHARS_PER_MAP >= ch) { @@ -1475,9 +1518,7 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max if (batchcount) { // we need a different character map, render what we currently have: - GL_LockArrays(0, batchcount * 4); R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0); - GL_LockArrays(0, 0); batchcount = 0; ac = color4f; at = texcoord2f; @@ -1509,8 +1550,8 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max y += ftbase_y; if (prevch && Font_GetKerningForMap(ft2, map_index, w, h, prevch, ch, &kx, &ky)) { - x += kx * w; - y += ky * h; + x += kx * dw; + y += ky * dh; } else kx = ky = 0; @@ -1522,23 +1563,21 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max at[2] = map->glyphs[mapch].txmax; at[3] = map->glyphs[mapch].tymin; at[4] = map->glyphs[mapch].txmax; at[5] = map->glyphs[mapch].tymax; at[6] = map->glyphs[mapch].txmin; at[7] = map->glyphs[mapch].tymax; - av[ 0] = x + w * map->glyphs[mapch].vxmin; av[ 1] = y + h * map->glyphs[mapch].vymin; av[ 2] = 10; - av[ 3] = x + w * map->glyphs[mapch].vxmax; av[ 4] = y + h * map->glyphs[mapch].vymin; av[ 5] = 10; - av[ 6] = x + w * map->glyphs[mapch].vxmax; av[ 7] = y + h * map->glyphs[mapch].vymax; av[ 8] = 10; - av[ 9] = x + w * map->glyphs[mapch].vxmin; av[10] = y + h * map->glyphs[mapch].vymax; av[11] = 10; + av[ 0] = x + dw * map->glyphs[mapch].vxmin; av[ 1] = y + dh * map->glyphs[mapch].vymin; av[ 2] = 10; + av[ 3] = x + dw * map->glyphs[mapch].vxmax; av[ 4] = y + dh * map->glyphs[mapch].vymin; av[ 5] = 10; + av[ 6] = x + dw * map->glyphs[mapch].vxmax; av[ 7] = y + dh * map->glyphs[mapch].vymax; av[ 8] = 10; + av[ 9] = x + dw * map->glyphs[mapch].vxmin; av[10] = y + dh * map->glyphs[mapch].vymax; av[11] = 10; //x -= ftbase_x; y -= ftbase_y; - x += thisw * w; + x += thisw * dw; ac += 16; at += 8; av += 12; batchcount++; if (batchcount >= QUADELEMENTS_MAXQUADS) { - GL_LockArrays(0, batchcount * 4); R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0); - GL_LockArrays(0, 0); batchcount = 0; ac = color4f; at = texcoord2f; @@ -1550,17 +1589,13 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max } if (shadow) { - x -= pix_x * r_textshadow.value; - y -= pix_y * r_textshadow.value; + x -= 1.0/pix_x * r_textshadow.value; + y -= 1.0/pix_y * r_textshadow.value; } } } if (batchcount > 0) - { - GL_LockArrays(0, batchcount * 4); R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0); - GL_LockArrays(0, 0); - } if (outcolor) *outcolor = colorindex; @@ -1569,34 +1604,24 @@ float DrawQ_String_Font(float startx, float starty, const char *text, size_t max return x; } -float DrawQ_String(float startx, float starty, const char *text, size_t maxlen, float w, float h, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes) -{ - return DrawQ_String_Font(startx, starty, text, maxlen, w, h, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, &dp_fonts[0]); -} - -float DrawQ_TextWidth_Font(const char *text, size_t maxlen, qboolean ignorecolorcodes, const dp_font_t *fnt) -{ - return DrawQ_TextWidth_Font_UntilWidth(text, &maxlen, ignorecolorcodes, fnt, 1000000000); -} - -float DrawQ_TextWidth_Font_Size(const char *text, float w, float h, size_t maxlen, qboolean ignorecolorcodes, const dp_font_t *fnt) +float DrawQ_String(float startx, float starty, const char *text, size_t maxlen, float w, float h, float basered, float basegreen, float baseblue, float basealpha, int flags, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt) { - return DrawQ_TextWidth_Font_UntilWidth_Size(text, w, h, &maxlen, ignorecolorcodes, fnt, 1000000000); + return DrawQ_String_Scale(startx, starty, text, maxlen, w, h, 1, 1, basered, basegreen, baseblue, basealpha, flags, outcolor, ignorecolorcodes, fnt); } -float DrawQ_TextWidth_Font_UntilWidth(const char *text, size_t *maxlen, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth) +float DrawQ_TextWidth_UntilWidth_TrackColors(const char *text, size_t *maxlen, float w, float h, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth) { - return DrawQ_TextWidth_Font_UntilWidth_TrackColors(text, maxlen, NULL, ignorecolorcodes, fnt, maxWidth); + return DrawQ_TextWidth_UntilWidth_TrackColors_Scale(text, maxlen, w, h, 1, 1, outcolor, ignorecolorcodes, fnt, maxwidth); } -float DrawQ_TextWidth_Font_UntilWidth_Size(const char *text, float w, float h, size_t *maxlen, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth) +float DrawQ_TextWidth(const char *text, size_t maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt) { - return DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(text, w, h, maxlen, NULL, ignorecolorcodes, fnt, maxWidth); + return DrawQ_TextWidth_UntilWidth(text, &maxlen, w, h, ignorecolorcodes, fnt, 1000000000); } -float DrawQ_TextWidth_Font_UntilWidth_TrackColors(const char *text, size_t *maxlen, int *outcolor, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxwidth) +float DrawQ_TextWidth_UntilWidth(const char *text, size_t *maxlen, float w, float h, qboolean ignorecolorcodes, const dp_font_t *fnt, float maxWidth) { - return DrawQ_TextWidth_Font_UntilWidth_TrackColors_Size(text, 0, 0, maxlen, outcolor, ignorecolorcodes, fnt, maxwidth); + return DrawQ_TextWidth_UntilWidth_TrackColors(text, maxlen, w, h, NULL, ignorecolorcodes, fnt, maxWidth); } #if 0 @@ -1687,9 +1712,7 @@ void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags) R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0); R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1); - GL_LockArrays(0, mesh->num_vertices); R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, mesh->data_element3s, 0, 0); - GL_LockArrays(0, 0); } void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags)