JTalton's picture

Fonts - Yet again

Windows XP
I converted my application over from using TAO.SDL and the SDL TTF library for rendering fonts to using the OpenTK fonts.
The OpenTK fonts don't have the correct pixel precision and the look blurry. Also the bottom of the font is getting cut off.
Am I missing a setting? I did find that if I change the font size to 8.25 instead of 9.0 the bottom of the font does not get cut off.

SDL Version

OpenTK Version (Updated with fixes resulting from this thread)

Program.cs3.13 KB


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
JTalton's picture

Name = "Microsoft Sans Serif" Size=7.0
The size of the size character (32 ' ') is 0 width 0 height from MeasureText() and thus pack.Add().
The divide by zero exception comes from
GL.TexSubImage2D(TextureTarget.Texture2D, 0, rect.Left, rect.Top, rect.Width, rect.Height, OpenTK.Graphics.PixelFormat.Rgba, PixelType.UnsignedByte, (IntPtr)data_ptr);
since rect.Width and Rect.Height are 0.

Attaching my test program to the original post.

Edit - BTW Font size 10 works for me. Output and measurements look good!

JTalton's picture

The fonts are hanging down below my rectangle in the test. This is because the returned rectangle from MeasureText has a Y location of 1.998 and I am ignoring the location when drawing the gray rectangle, but the text drawing function uses this location offset.

It may be that this is the desired functionality since the 1.99 = ~2 which is how much the font in question hangs down on letters that hang (i.e. 'g' 'j'). So it is drawing the font at the location I specified but that is the baseline and not the bottom of what is drawn. If that makes sense. In a way that is a nice feature, and I can work around it in my code since I want the actual bottom of rendering by using the location offset before rendering the text.

JTalton's picture

Compiled on second machine and I am still getting this exception:


 GL.Delegates.TexSubImage2D.Invoke(target, level,xoffset, yoffset, width, height, format, type, pixels) 
 GL.TexSubImage2D(target=Texture2D, level=0, xoffset=8, yoffset=18, width=0, height=0, format=Rgba, type=UnsignedByte, pixels=)
 TextureFont.LoadGlyph(c=' ', rectangle={X=0 Y=0 Width=0 Height=0})
 TextureFont.LoadGlyphs(glyphs="Main Window")
 TextPrinter.PerformLayout(text="Main Window", font={TextureFont}, width=0, wordWarp=false, alignment=Near, rightToLeft=false, vertices={}, indices={}, num_indices=66)
 TextPrinter.Prepare(text="Main Window", font={TextureFont}, handle=null, width=0, wordWarp=false, alignment=Near, rightToLeft=false)
 TextPrinter.Prepare(text="Main Window", font={TextureFont}, handle=null)

You can see by the stack trace that the space character is trying to be loaded with a width and height of zero which causes TexSubImage2D() to throw the exception.

the Fiddler's picture

[Hanging glyphs]
The fonts are hanging down below my rectangle in the test
I think this depends on the font, actually. Different fonts use different coordinate systems (e.g. (0,0) could be the left-most pixel of the baseline or the glyph "center") - you can verify this is the case by loading a few different fonts (e.g. Verdana and Times New Roman at 7.0em - the latter has parts of the font hanging outside the rectangle while the first doesn't).

A strange thing I just happened to observe, is that the bounding box returned by TextureFont.MeasureText correctly surrounds all overhangs - only the individual rectangles show this effect. I'm not really sure *why* this happens, as the rectangle is calculated simply from the first and last glyph sizes.

Ah, I'll have to research this a little more, I guess.

[DivideByZero exception]
I must be getting crazy, because I can't reproduce that. I've tested 10 different fonts (including MS Sans Serif) at sizes 5-10em with the "Main Window" string, and the ' ' is correctly measured.

I'm now grapsing at straws: which version of .Net are you using / building OpenTK against? If it is 2.0, do you have SP1 installed?

JTalton's picture

Windows XP - SP3
I believe .NET 2.0

GdiPlus.GetRegionBounds(regions[j], new HandleRef(gfx, GdiPlus.GetNativeGraphics(gfx)), ref rect);
The rect after this call for the space character has a width and height of zero.

I have reproduced this on two separate machines using the latest SVN code and different test code in each case.

the Fiddler's picture

Interesting. I'm still not able to reproduce the issue (Vista x64 SP1 / .Net 2.0 SP1, Windows XP SP3 / .Net 2.0 SP1, Windows 2000 / .Net 2.0). I haven't tested on Linux yet, but this problem looks rather curious. Can you test what the following returns on your machine?

Just before the failing call, place the following lines. Then put a breakpoint on the MeasureText call, and examine the output of "ranges". Does the space character still exhibit a 0 width/height?

// Somewhere before the code which crashes, place the following line:
StringFormat format = StringFormat.GenericTypographic;
format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
List<RectangleF> ranges = new List<RectangleF>();
textureFont.MeasureText(str, SizeF.Empty, format, ranges);

If yes, can you test against the sample default .Net MeasureCharacterRanges implementation? Create a new WinForms project and replace class Form1 with the following:

    public partial class Form1 : Form
        static readonly string text = "Main Window";
        static readonly Font font = new Font(new FontFamily("Microsoft Sans Serif"), 7.0f);
        public Form1()
        protected override void  OnPaint(PaintEventArgs e)
            e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
            StringFormat format = StringFormat.GenericDefault;
            CharacterRange[] ranges = new CharacterRange[text.Length];
            for (int i = 0; i < ranges.Length; i++)
                ranges[i] = new CharacterRange(i, 1);
            Region[] regions = e.Graphics.MeasureCharacterRanges(text, font, new RectangleF(0, 0, 1000.0f, 1000.0f), format);
            Rectangle measure_string_size = new Rectangle(
                new Point((int)regions[0].GetBounds(e.Graphics).Left,
                new Size((int)Math.Ceiling(regions[regions.Length - 1].GetBounds(e.Graphics).Right),
                         (int)Math.Ceiling(regions[regions.Length - 1].GetBounds(e.Graphics).Bottom)));
            e.Graphics.FillRectangle(Brushes.White, measure_string_size);
            for (int i = 0; i < regions.Length; i++)
                Region region = regions[i];
                e.Graphics.DrawString(text[i].ToString(), font, Brushes.Black,
                    new Point((int)region.GetBounds(e.Graphics).Left,
            //SizeF temp_size = e.Graphics.MeasureString(text, font);
            //Size measure_string_size = new Size((int)Math.Ceiling(temp_size.Width), (int)Math.Ceiling(temp_size.Height));
            //e.Graphics.FillRectangle(Brushes.White, new Rectangle(new Point(0, 0), measure_string_size));
            //e.Graphics.DrawString(text, font, Brushes.Black, new PointF(0, 0));

Does this code correctly display a space character on your test machine?

I'm trying to find out what's going wrong here.

On the upside, I've found a problem with italics getting cut off, which I'm now investigating. I'm also working on a new glyph packing method that will allow multiple texture sheets with glyph eviction (LRU scheme with configurable memory consumption).

JTalton's picture

Tried the same tests I have been doing on a 3rd XP SP3 machine. Works flawlessly. So something about the first two machines is off. I'll run the tests you outlined when I get a chance.

BlueMonkMN's picture

Oops, I missed out on this whole discussion. But it looks like you're stuck the same place I was: MeasureString returns a true bounding box for the text and all it's overhanging bits while MeasureCharacterRanges seems more intended to return boundaries for the main parts of the characters (for the purpose of highlighting text or something), ignoring some outlying bits, especially in the case of large italic lowercase "f" characters in Times New Roman. That's what happened when I tried to convert everything to use MeasureCharacterRanges too. But maybe you improved it somewhat by taking into account the offset of the glyph into the cell where it's drawn? I never got that far. I'll try getting and testing the new code soon and see if my results are better than before.

objarni's picture

JTalton: sorry for off topic question -- but the images on the buttons in Golem are very nice indeed. What software/tools did you use to draw them?

JTalton's picture

Inkscape Open source Linux/MacOS/Windows vector graphics program.
I highly recommend it. Exports the SVG vector icons as PNG with full transparency support.
I also try to somewhat follow the Tango icon design guidelines.
The 4 icons on the left of the bar are using the new guidelines. I still need to work the others up.