Re: [SPAM: 3.000] Re: [pygame] Monospaced fonts are meant to be mono-spaced, right?

2012-06-04 Thread Greg Ewing

Weeble wrote:


To get the very best positioning of a text cursor, I think you want to
calculate the width of the string on its left, then *subtract* the
overhang of the character immediately to the left, if any.


For the *very* best results with italic fonts,
you really need a slanted cursor. :-(

--
Greg


Re: [pygame] Monospaced fonts are meant to be mono-spaced, right?

2012-06-02 Thread Weeble
I've looked into Sam's monospaced font size problems and followed up
in the Ubuntu bug. I think we've discovered unusual behaviour in
FreeType that may or may not be a bug, and hopefully someone on the
FreeType mailing list will respond to my questions over there. I'm
posting back here now to discuss how best to actually achieve the
intended cursor placement using Pygame.

Over in the bug report, Sam says:
> My solution for the labels, which works fine, is to find the rendered length 
> of the first character, then the length of the first two characters, then the 
> length of the first 3 characters and so on. Storing all these values allows 
> me to work out the correct position.

> Because there's quite a bit of repetition, this can take a little bit of CPU 
> time. My only concern with the input box, is that it needs to recalculate all 
> of this, everytime the user types something, and it is designed for use in 
> games where a fraction of a millisecond can still be important to keep the 
> game running smoothly.

In all the examples so far, you've been using
font.render("blah"...).get_size(). Do you know there's a
font.size("blah") too? That should do the calculations quickly without
actually doing the rendering. I think that should be fast enough for
your needs. (See the end of this email for a short example.)

I've done some experiments to try to understand how the font metrics
relate to the dimensions of a rendered piece of text in the general
case, not just for monospaced fonts. I thought it might be useful to
others.

Firstly, any text string rendered by a font will always have a height
of font.get_height(). It seems that this is always
1+font.get_ascent()+font.get_ascent(). It doesn't matter what text you
render, even it it's entirely whitespace, it will always be the full
height.

For the width, you need to look at the metrics of each character in
the string, as returned by font.metrics(). These are xmin, xmax, ymin,
ymax and advance, as shown in the diagram here:
http://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf.html#SEC38

The advance is the easiest to understand. It's the horizontal distance
the text cursor moves from one side of the character to the other.
xmin is the distance from the left cursor position to the leftmost
part of the outline. xmax is the distance from the left cursor
position to the rightmost part of the outline.

Most of the time, the width of a string of text is the sum of the
advance widths of the characters. But some characters can overhang,
which happens a lot in italic fonts. If the first or last characters
overhang, the width of the string will be longer. Here's a diagram:

https://lh3.googleusercontent.com/-hxXPX7kxCbs/T8q0jF08loI/DJk/72dsWzp7ATw/s877/font_rendering.png

The black bars under the letters are their advance widths. The red
highlighted areas are where characters overhang - they have parts
wider than their advance width. (The blue highlighted areas are where
the characters are narrower than their advance width - they don't
matter much.) The width of the string of text is the sum of the
advance widths *plus* the overhang of the first and last characters.

(Actually, that's not *entirely* true. I think long strings can also
vary a few pixels due to accumulated rounding and/or kerning, but
that's a much smaller effect than the overhang.)

Suppose you have rendered the word "offer" as shown in the diagram,
and you want to draw a cursor between the two "f"s. If you calculate
the cursor position based on the width of the text on the left - "of"
- you will find that the cursor is too far to the right. It will end
up right in the middle of the second "f" because the first "f"
overhangs it so much. What you actually want to do is let the font
library calculate the width of "of", then subtract the right overhang
of the last letter, "f". The right overhang is "xmax - advance".

To get the very best positioning of a text cursor, I think you want to
calculate the width of the string on its left, then *subtract* the
overhang of the character immediately to the left, if any. Here's a
demo: http://pastebin.com/PKm8ChxV

Hope this information is useful to someone!


Re: [pygame] Monospaced fonts are meant to be mono-spaced, right?

2012-05-28 Thread Sam Bull
On Mon, 2012-05-28 at 17:08 +0100, Weeble wrote:
> 1. I could reproduce the behaviour you saw on Windows but not a Ubuntu
> VM (but it is old, certainly not 12.04).

I worked out that it is only one version of the font that is causing the
problem. So, if you want to test it on Ubuntu without updating, use this
font directly:
http://ftp.gnu.org/gnu/freefont/freefont-ttf-20100919.tar.gz

For some reason, the bug only happens with that specific font. It's fine
with any of the older versions on that page, or with any of the .otf
versions.

> 3. I note that the Font object has a metrics() method that returns
> metrics for a glyph, as explained in this diagram:
> http://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf.html#SEC38

OK, I just tried to make sense of the metrics thing, and now I'm only
more confused than before... :S

The advance thing in the metrics for "Ubuntu Mono" is 8 for all
characters, and all characters rendered in this font return a width of
8, that makes sense so far...

Now, trying to do the same in the problematic "FreeMono" is peculiar.

It seems the advance is inconsistent between different characters, but
we already expected that. But, it's also inconsistent with the returned
widths.
As can be seen from this code, the advance says that 'a' and 'd' have
the same minx and maxx but different advance sizes, but it also shows
that the rendered size is different. Both characters render with a width
of 10, but the advance shows that 'd' should be 9.

print m.metrics("a")
print m.metrics("d")
print m.render("a", False, (0,0,0)).get_size()[0]
print m.render("d", False, (0,0,0)).get_size()[0]

[(1, 10, 0, 7, 10)]
[(1, 10, 0, 10, 9)]
10
10



signature.asc
Description: This is a digitally signed message part


Re: [pygame] Monospaced fonts are meant to be mono-spaced, right?

2012-05-28 Thread Weeble
On Mon, May 28, 2012 at 12:27 PM, Sam Bull  wrote:
> OK, so I registered a bug on this, and it's possible that it is a bug
> with the rendering library. Can anybody who knows anything about the
> pygame.font module, look at the bug report and see if you can add any
> information to this?
>
> https://bugs.launchpad.net/ubuntu/+source/ttf-freefont/+bug/1001033

I don't have time to investigate further, but I had a quick look:

1. I could reproduce the behaviour you saw on Windows but not a Ubuntu
VM (but it is old, certainly not 12.04).
2. I tried replacing the version of FreeType used by Pygame on Windows
with one from here http://www.gtk.org/download/win32.php and got your
expected behaviour - everything the same width.
3. I note that the Font object has a metrics() method that returns
metrics for a glyph, as explained in this diagram:
http://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf.html#SEC38
4. Based on that diagram, I'd expect "advance" to be constant for a
monospaced font, but that min and max x might vary. Metrics shows that
advance varies for the glyphs you have the problem with.
5. I also note that the description of metrics in the Pygame docs
appears to be wrong:
http://www.pygame.org/docs/ref/font.html#Font.metrics It describes the
advance as "bearing plus width", but this is not necessarily the case,
as shown in the SDL diagram.

I might have a look this evening, and if I do, I'll post a test script
and follow up on your launchpad bug. It looks like different versions
of FreeType might have subtly different behaviour, but I wouldn't like
to hazard a guess whether any of the font, FreeType, SDL or pygame
actually has a bug at this stage. I'm not in any way affiliated with
any of these projects, just curious.


Re: [pygame] Monospaced fonts are meant to be mono-spaced, right?

2012-05-28 Thread Sam Bull
OK, so I registered a bug on this, and it's possible that it is a bug
with the rendering library. Can anybody who knows anything about the
pygame.font module, look at the bug report and see if you can add any
information to this?

https://bugs.launchpad.net/ubuntu/+source/ttf-freefont/+bug/1001033

Thanks,
Sam Bull

On Tue, 2012-05-15 at 11:23 +1200, Greg Ewing wrote:
> Nicholas Seward wrote:
> > The letters may be different lengths.  However, the letters should be
> > spaced equally.  For example,"i" will be shorter than "w" but "hit"
> > and "hot" should be the same length.
> 
> No, that's not the way it should work. I just tried an experiment:
> 
>  >>> f = Font("VeraMono.ttf", 12)
>  >>> f.size("e")
> (7, 15)
>  >>> f.size("i")
> (7, 15)
> 
> I suspect that the system is not actually giving you a
> monospaced font. If it doesn't recognise the font name
> you give it, you'll probably get some default font. Have
> you tried rendering any text with the font to see what
> it looks like?
> 
> I've given up on using SysFont because the results are
> too unpredictable cross-platform. I always bundle my
> own fonts with my games and use Font to load them
> explicitly.
> 
> I like to use the Bitstream Vera fonts. They're nice,
> small and very liberally licensed.
> 
> http://ftp.gnome.org/pub/GNOME/sources/ttf-bitstream-vera/1.10/
> 





Re: [pygame] Monospaced fonts are meant to be mono-spaced, right?

2012-05-14 Thread James Paige
> I've given up on using SysFont because the results are
> too unpredictable cross-platform. I always bundle my
> own fonts with my games and use Font to load them
> explicitly.

YES! This, this, a thousand times THIS!

---
James paige


Re: [pygame] Monospaced fonts are meant to be mono-spaced, right?

2012-05-14 Thread Greg Ewing

Nicholas Seward wrote:

The letters may be different lengths.  However, the letters should be
spaced equally.  For example,"i" will be shorter than "w" but "hit"
and "hot" should be the same length.


No, that's not the way it should work. I just tried an experiment:

>>> f = Font("VeraMono.ttf", 12)
>>> f.size("e")
(7, 15)
>>> f.size("i")
(7, 15)

I suspect that the system is not actually giving you a
monospaced font. If it doesn't recognise the font name
you give it, you'll probably get some default font. Have
you tried rendering any text with the font to see what
it looks like?

I've given up on using SysFont because the results are
too unpredictable cross-platform. I always bundle my
own fonts with my games and use Font to load them
explicitly.

I like to use the Bitstream Vera fonts. They're nice,
small and very liberally licensed.

http://ftp.gnome.org/pub/GNOME/sources/ttf-bitstream-vera/1.10/

--
Greg


Re: [pygame] Monospaced fonts are meant to be mono-spaced, right?

2012-05-14 Thread Dan Uznanski
Are you accounting correctly for non-integer character width?  If it's
always the same letter /position/ that's giving you trouble, then it's
possible that the width of the character is not an integer in that
size, and your text renderer may be accounting for that in ways that
your own program is not.

On Mon, May 14, 2012 at 9:25 AM, Nicholas Seward
 wrote:
> The letters may be different lengths.  However, the letters should be
> spaced equally.  For example,"i" will be shorter than "w" but "hit"
> and "hot" should be the same length.
>
> On Mon, May 14, 2012 at 5:25 AM, Sam Bull  wrote:
>> Before I go and file a bug against Ubuntu, can somebody confirm I'm not
>> being stupid.
>>
>> For my input boxes, the cursor position depends on a monospaced font.
>> This means I check the length of a rendered letter ("e") using the font,
>> and then set the cursor position as a multiple of this length.
>>
>> This worked fine before, but in Ubuntu 12.04, it no longer seems to be
>> monospaced. Getting the length of the character "e" on my system gives
>> me 9 pixels, but it seems that some characters, such as "h", are 10
>> pixels, which starts offsetting my cursor position and messing up my
>> input box.
>>
>> The line I use to load the font is:
>>        pygame.font.SysFont("FreeMono, Monospace", 16)
>>
>> That should definitely return a monospaced font, right?
>>
>> And, the line used for getting the width is:
>>        mono_font.render("e", False, (0,0,0)).get_size()[0]
>>
>> Is this a bug, or am I doing something stupid?
>>


Re: [pygame] Monospaced fonts are meant to be mono-spaced, right?

2012-05-14 Thread Nicholas Seward
The letters may be different lengths.  However, the letters should be
spaced equally.  For example,"i" will be shorter than "w" but "hit"
and "hot" should be the same length.

On Mon, May 14, 2012 at 5:25 AM, Sam Bull  wrote:
> Before I go and file a bug against Ubuntu, can somebody confirm I'm not
> being stupid.
>
> For my input boxes, the cursor position depends on a monospaced font.
> This means I check the length of a rendered letter ("e") using the font,
> and then set the cursor position as a multiple of this length.
>
> This worked fine before, but in Ubuntu 12.04, it no longer seems to be
> monospaced. Getting the length of the character "e" on my system gives
> me 9 pixels, but it seems that some characters, such as "h", are 10
> pixels, which starts offsetting my cursor position and messing up my
> input box.
>
> The line I use to load the font is:
>        pygame.font.SysFont("FreeMono, Monospace", 16)
>
> That should definitely return a monospaced font, right?
>
> And, the line used for getting the width is:
>        mono_font.render("e", False, (0,0,0)).get_size()[0]
>
> Is this a bug, or am I doing something stupid?
>


[pygame] Monospaced fonts are meant to be mono-spaced, right?

2012-05-14 Thread Sam Bull
Before I go and file a bug against Ubuntu, can somebody confirm I'm not
being stupid.

For my input boxes, the cursor position depends on a monospaced font.
This means I check the length of a rendered letter ("e") using the font,
and then set the cursor position as a multiple of this length.

This worked fine before, but in Ubuntu 12.04, it no longer seems to be
monospaced. Getting the length of the character "e" on my system gives
me 9 pixels, but it seems that some characters, such as "h", are 10
pixels, which starts offsetting my cursor position and messing up my
input box.

The line I use to load the font is:
pygame.font.SysFont("FreeMono, Monospace", 16)

That should definitely return a monospaced font, right?

And, the line used for getting the width is:
mono_font.render("e", False, (0,0,0)).get_size()[0]

Is this a bug, or am I doing something stupid?