@@ -2622,6 +2622,7 @@ void ImFont::BuildLookupTable()
2622
2622
for (int i = 0 ; i != Glyphs.Size ; i++)
2623
2623
max_codepoint = ImMax (max_codepoint, (int )Glyphs[i].Codepoint );
2624
2624
2625
+ // Build lookup table
2625
2626
IM_ASSERT (Glyphs.Size < 0xFFFF ); // -1 is reserved
2626
2627
IndexAdvanceX.clear ();
2627
2628
IndexLookup.clear ();
@@ -2638,7 +2639,7 @@ void ImFont::BuildLookupTable()
2638
2639
// FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
2639
2640
if (FindGlyph ((ImWchar)' ' ))
2640
2641
{
2641
- if (Glyphs.back ().Codepoint != ' \t ' ) // So we can call this function multiple times
2642
+ if (Glyphs.back ().Codepoint != ' \t ' ) // So we can call this function multiple times (FIXME: Flaky)
2642
2643
Glyphs.resize (Glyphs.Size + 1 );
2643
2644
ImFontGlyph& tab_glyph = Glyphs.back ();
2644
2645
tab_glyph = *FindGlyph ((ImWchar)' ' );
@@ -2648,13 +2649,24 @@ void ImFont::BuildLookupTable()
2648
2649
IndexLookup[(int )tab_glyph.Codepoint ] = (ImWchar)(Glyphs.Size -1 );
2649
2650
}
2650
2651
2652
+ // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons)
2653
+ SetGlyphVisible ((ImWchar)' ' , false );
2654
+ SetGlyphVisible ((ImWchar)' \t ' , false );
2655
+
2656
+ // Setup fall-backs
2651
2657
FallbackGlyph = FindGlyphNoFallback (FallbackChar);
2652
2658
FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0 .0f ;
2653
2659
for (int i = 0 ; i < max_codepoint + 1 ; i++)
2654
2660
if (IndexAdvanceX[i] < 0 .0f )
2655
2661
IndexAdvanceX[i] = FallbackAdvanceX;
2656
2662
}
2657
2663
2664
+ void ImFont::SetGlyphVisible (ImWchar c, bool visible)
2665
+ {
2666
+ if (ImFontGlyph* glyph = (ImFontGlyph*)(void *)FindGlyph ((ImWchar)c))
2667
+ glyph->Visible = visible ? 1 : 0 ;
2668
+ }
2669
+
2658
2670
void ImFont::SetFallbackChar (ImWchar c)
2659
2671
{
2660
2672
FallbackChar = c;
@@ -2676,7 +2688,8 @@ void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1,
2676
2688
{
2677
2689
Glyphs.resize (Glyphs.Size + 1 );
2678
2690
ImFontGlyph& glyph = Glyphs.back ();
2679
- glyph.Codepoint = (ImWchar)codepoint;
2691
+ glyph.Codepoint = (unsigned int )codepoint;
2692
+ glyph.Visible = (x0 != x1) && (y0 != y1 );
2680
2693
glyph.X0 = x0;
2681
2694
glyph.Y0 = y0 ;
2682
2695
glyph.X1 = x1;
@@ -2925,16 +2938,14 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
2925
2938
2926
2939
void ImFont::RenderChar (ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const
2927
2940
{
2928
- if (c == ' ' || c == ' \t ' || c == ' \n ' || c == ' \r ' ) // Match behavior of RenderText(), those 4 codepoints are hard-coded.
2941
+ const ImFontGlyph* glyph = FindGlyph (c);
2942
+ if (!glyph || !glyph->Visible )
2929
2943
return ;
2930
- if (const ImFontGlyph* glyph = FindGlyph (c))
2931
- {
2932
- float scale = (size >= 0 .0f ) ? (size / FontSize) : 1 .0f ;
2933
- pos.x = IM_FLOOR (pos.x + DisplayOffset.x );
2934
- pos.y = IM_FLOOR (pos.y + DisplayOffset.y );
2935
- draw_list->PrimReserve (6 , 4 );
2936
- draw_list->PrimRectUV (ImVec2 (pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2 (pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2 (glyph->U0 , glyph->V0 ), ImVec2 (glyph->U1 , glyph->V1 ), col);
2937
- }
2944
+ float scale = (size >= 0 .0f ) ? (size / FontSize) : 1 .0f ;
2945
+ pos.x = IM_FLOOR (pos.x + DisplayOffset.x );
2946
+ pos.y = IM_FLOOR (pos.y + DisplayOffset.y );
2947
+ draw_list->PrimReserve (6 , 4 );
2948
+ draw_list->PrimRectUV (ImVec2 (pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2 (pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2 (glyph->U0 , glyph->V0 ), ImVec2 (glyph->U1 , glyph->V1 ), col);
2938
2949
}
2939
2950
2940
2951
void ImFont::RenderText (ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char * text_begin, const char * text_end, float wrap_width, bool cpu_fine_clip) const
@@ -3047,73 +3058,70 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
3047
3058
continue ;
3048
3059
}
3049
3060
3050
- float char_width = 0 .0f ;
3051
- if (const ImFontGlyph* glyph = FindGlyph ((ImWchar)c))
3052
- {
3053
- char_width = glyph->AdvanceX * scale;
3061
+ const ImFontGlyph* glyph = FindGlyph ((ImWchar)c);
3062
+ if (glyph == NULL )
3063
+ continue ;
3054
3064
3055
- // Arbitrarily assume that both space and tabs are empty glyphs as an optimization
3056
- if (c != ' ' && c != ' \t ' )
3065
+ float char_width = glyph->AdvanceX * scale;
3066
+ if (glyph->Visible )
3067
+ {
3068
+ // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w
3069
+ float x1 = x + glyph->X0 * scale;
3070
+ float x2 = x + glyph->X1 * scale;
3071
+ float y1 = y + glyph->Y0 * scale;
3072
+ float y2 = y + glyph->Y1 * scale;
3073
+ if (x1 <= clip_rect.z && x2 >= clip_rect.x )
3057
3074
{
3058
- // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w
3059
- float x1 = x + glyph->X0 * scale;
3060
- float x2 = x + glyph->X1 * scale;
3061
- float y1 = y + glyph->Y0 * scale;
3062
- float y2 = y + glyph->Y1 * scale;
3063
- if (x1 <= clip_rect.z && x2 >= clip_rect.x )
3075
+ // Render a character
3076
+ float u1 = glyph->U0 ;
3077
+ float v1 = glyph->V0 ;
3078
+ float u2 = glyph->U1 ;
3079
+ float v2 = glyph->V1 ;
3080
+
3081
+ // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
3082
+ if (cpu_fine_clip)
3064
3083
{
3065
- // Render a character
3066
- float u1 = glyph->U0 ;
3067
- float v1 = glyph->V0 ;
3068
- float u2 = glyph->U1 ;
3069
- float v2 = glyph->V1 ;
3070
-
3071
- // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
3072
- if (cpu_fine_clip)
3084
+ if (x1 < clip_rect.x )
3073
3085
{
3074
- if (x1 < clip_rect.x )
3075
- {
3076
- u1 = u1 + (1 .0f - (x2 - clip_rect.x ) / (x2 - x1)) * (u2 - u1);
3077
- x1 = clip_rect.x ;
3078
- }
3079
- if (y1 < clip_rect.y )
3080
- {
3081
- v1 = v1 + (1 .0f - (y2 - clip_rect.y ) / (y2 - y1 )) * (v2 - v1);
3082
- y1 = clip_rect.y ;
3083
- }
3084
- if (x2 > clip_rect.z )
3085
- {
3086
- u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
3087
- x2 = clip_rect.z ;
3088
- }
3089
- if (y2 > clip_rect.w )
3090
- {
3091
- v2 = v1 + ((clip_rect.w - y1 ) / (y2 - y1 )) * (v2 - v1);
3092
- y2 = clip_rect.w ;
3093
- }
3094
- if (y1 >= y2)
3095
- {
3096
- x += char_width;
3097
- continue ;
3098
- }
3086
+ u1 = u1 + (1 .0f - (x2 - clip_rect.x ) / (x2 - x1)) * (u2 - u1);
3087
+ x1 = clip_rect.x ;
3099
3088
}
3100
-
3101
- // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
3089
+ if (y1 < clip_rect.y )
3090
+ {
3091
+ v1 = v1 + (1 .0f - (y2 - clip_rect.y ) / (y2 - y1 )) * (v2 - v1);
3092
+ y1 = clip_rect.y ;
3093
+ }
3094
+ if (x2 > clip_rect.z )
3102
3095
{
3103
- idx_write[0 ] = (ImDrawIdx)(vtx_current_idx); idx_write[1 ] = (ImDrawIdx)(vtx_current_idx+1 ); idx_write[2 ] = (ImDrawIdx)(vtx_current_idx+2 );
3104
- idx_write[3 ] = (ImDrawIdx)(vtx_current_idx); idx_write[4 ] = (ImDrawIdx)(vtx_current_idx+2 ); idx_write[5 ] = (ImDrawIdx)(vtx_current_idx+3 );
3105
- vtx_write[0 ].pos .x = x1; vtx_write[0 ].pos .y = y1 ; vtx_write[0 ].col = col; vtx_write[0 ].uv .x = u1; vtx_write[0 ].uv .y = v1;
3106
- vtx_write[1 ].pos .x = x2; vtx_write[1 ].pos .y = y1 ; vtx_write[1 ].col = col; vtx_write[1 ].uv .x = u2; vtx_write[1 ].uv .y = v1;
3107
- vtx_write[2 ].pos .x = x2; vtx_write[2 ].pos .y = y2; vtx_write[2 ].col = col; vtx_write[2 ].uv .x = u2; vtx_write[2 ].uv .y = v2;
3108
- vtx_write[3 ].pos .x = x1; vtx_write[3 ].pos .y = y2; vtx_write[3 ].col = col; vtx_write[3 ].uv .x = u1; vtx_write[3 ].uv .y = v2;
3109
- vtx_write += 4 ;
3110
- vtx_current_idx += 4 ;
3111
- idx_write += 6 ;
3096
+ u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
3097
+ x2 = clip_rect.z ;
3098
+ }
3099
+ if (y2 > clip_rect.w )
3100
+ {
3101
+ v2 = v1 + ((clip_rect.w - y1 ) / (y2 - y1 )) * (v2 - v1);
3102
+ y2 = clip_rect.w ;
3103
+ }
3104
+ if (y1 >= y2)
3105
+ {
3106
+ x += char_width;
3107
+ continue ;
3112
3108
}
3113
3109
}
3110
+
3111
+ // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
3112
+ {
3113
+ idx_write[0 ] = (ImDrawIdx)(vtx_current_idx); idx_write[1 ] = (ImDrawIdx)(vtx_current_idx+1 ); idx_write[2 ] = (ImDrawIdx)(vtx_current_idx+2 );
3114
+ idx_write[3 ] = (ImDrawIdx)(vtx_current_idx); idx_write[4 ] = (ImDrawIdx)(vtx_current_idx+2 ); idx_write[5 ] = (ImDrawIdx)(vtx_current_idx+3 );
3115
+ vtx_write[0 ].pos .x = x1; vtx_write[0 ].pos .y = y1 ; vtx_write[0 ].col = col; vtx_write[0 ].uv .x = u1; vtx_write[0 ].uv .y = v1;
3116
+ vtx_write[1 ].pos .x = x2; vtx_write[1 ].pos .y = y1 ; vtx_write[1 ].col = col; vtx_write[1 ].uv .x = u2; vtx_write[1 ].uv .y = v1;
3117
+ vtx_write[2 ].pos .x = x2; vtx_write[2 ].pos .y = y2; vtx_write[2 ].col = col; vtx_write[2 ].uv .x = u2; vtx_write[2 ].uv .y = v2;
3118
+ vtx_write[3 ].pos .x = x1; vtx_write[3 ].pos .y = y2; vtx_write[3 ].col = col; vtx_write[3 ].uv .x = u1; vtx_write[3 ].uv .y = v2;
3119
+ vtx_write += 4 ;
3120
+ vtx_current_idx += 4 ;
3121
+ idx_write += 6 ;
3122
+ }
3114
3123
}
3115
3124
}
3116
-
3117
3125
x += char_width;
3118
3126
}
3119
3127
0 commit comments