font (StaticFont) from image?

I have an image like this which i want to use as font.
persistent.info/files/canvas-text/font.png
(though not ASCII)

However, I don’t have a ttf file, so the panda program for generating an egg+png from ttf won’t be useful.

Are there any methods in Panda3d to use an image as font file by setting some options, or maybe an easy way to generate a font egg from a png? Or am I out of luck and will have to make an egg fle by hand? (some info on that)

There are no tools to generate a font from a file such as this, but the good news is that it will be fairly easy to do it yourself.

Examine an existing egg font file, and you’ll see that it consists of a series of entries, each of which is given a name that is the ASCII (or Unicode) number of the character it defines. Each contains a single that draws the character in question, and a whose only purpose is to mark the X coordinate of the next character to be placed following this one (thus defining the width of this character and the space between successive characters).

For a fixed-width font like this, you just need to divide your texture space into a grid, and create a polygon for each one. The vertex will be the same for all of them because they’re all the same width.

I suggest writing a simple Python program to generate the egg file. You can either write the egg syntax directly, or you can use the EggData interface.

David

OK, sounds simple. But I’m afraid the actual font I’m using is not in ASCII or UNICODE, but in SJIS…

SJIS isn’t a character set; it’s an encoding system used to represent 16-bit Unicode numbers in an 8-bit stream.

I’m not sure what would mean to have a SJIS png file, but maybe you mean you have a table along with the png file that gives the SJIS encoding for each character? If that’s the case, then you only need to decode the SJIS to get the Unicode number.

David

yeah I have a list of codes for each character.
I wonder what Python modules I should have a look at, never done this before.

You won’t need to use any special modules; it’s just raw Python code (especially if you’re generating the egg text directly). You just need to compute the UV’s for each character as a number in the range 0…1 to represent the portion of the png file that each character uses. You’ll also need the 3-D vertex positions, of course, but these will all be the same if all of your glyphs are the same size.

You can Google “SJIS to Unicode” to get the mapping table for your codes.

David

OK, sounds simple enough.
I know I can find this out myself by searching the existing egg font files, but I thought I could also ask this here: can you have a single plane for all the “glyphs”, or do you need to make overlapping, extra 2 triangles for every character?

Also, do font images have to be power of two? I’m kinda hoping the Panda3d font class will be smart to scale it automatically.

I’m sorry, this question baffles me. Typically a font will define a rectilinear quad in the Y=0 plane for each glyph. There’s no need for extra triangles.

Font images, like any other textures, should generally be a power of two for optimum performance and quality. If they are not, however, then like any other texture, Panda will automatically scale it down to the nearest smaller power of two. You can also configure Panda to scale it up to the nearest larger power of two, to maintain quality; or to keep it unscaled and hope your hardware can render it anyway (many do).

David

Well yeah, quad is 2 triangles right? I dont think egg supports quad primitives.
I thought Panda worked like this: I could have a single quad for all the characters and Panda would copy (instance) the quad for each textNode character and modify it’s UV offset.

But what if I only want to scale up the font texture(s)? From what you said you can’t even set the GUI textures to scale up but not the textures of 3d models.

If I “keep it unscaled and hope my hardware can render it anyway”, is there a “fallback” code in Panda to switch to “nearest smaller power of two” if my hardware doesn’t support it, or will the game simply crash?

Egg supports arbitrary polygons of any complexity. They are converted into triangles automatically when the egg file is loaded, but you don’t need to think about that.

No. The font loader assumes you have defined the UV coordinate properly for each character. It has no idea how the characters are arranged in the png file, so it wouldn’t be able to modify the UV offset for you. (The standard fonts, for instance, with non-proportional characters, don’t even lay things out in a regular grid.)

So, you can define a different quad for each character. When it is laying out text, Panda will make a copy of the the appropriate quad each time a particular character appears. It will change the position of the quad, but not the UV coordinates.

If you need this level of control, I suggest simply pre-scaling the font textures to the appropriate size. Actually, I suggest doing this for all of your textures anyway. The automatic scaling is intended primarily for the convenience of development.

You can put this in your Config.prc file:

textures-power-2 down
textures-auto-power-2 1

The second line asks Panda to query the graphics driver and disable auto scaling if it claims to support non-power-2 textures. (Note that many low-end graphics cards claim to support non-power-2 textures even though they don’t really. The graphics driver is simply doing the scaling. Panda has no way to detect if this is the case.)

David

Following my previous question on loading textures from data from RAM, I’m wondering if I can do the same here: generate an egg string and load it with loadFont() without having to save it somewhere in disk.

Yes, there are several approaches. loader.loadFont() only accepts a filename, but you could take your egg string and mount it into Panda’s vfs as a virtual file, then load it with loader.loadFont(). But this is fairly complicated.

It would probably be easier to shortcut loader.loadFont() and simply create it directly from the root PandaNode of your egg file:

font = StaticTextFont(node)

and you can get the root PandaNode the usual way from your egg string, with something like:

egg = EggData()
egg.read(StringStream(myEggData))
node = loadEggData(egg)

Of course, if you are constructing this egg data on the fly, it might be easier to use the EggData syntax to construct it directly, rather that constructing literal text first and then creating an EggData structure from it with read(). But that’s up to you. :wink:

David

I’m not making a small standalone program, so if it saves me time, sure. Is there any example of using EggData, though?
I’ve written code for generating geometry from scratch when writing our 3d format loader, but not with the Egg classes…

There are examples in the forums, and the API reference is well-documented. The Egg classes follow the structure of the egg syntax almost one-to-one.

David

Sorry, but I can’t find enough documentation and the example in the forum doesn’t have much comments.

So I’ll just ask if I have it all right:
EggData is the thing which holds everything, like an actual egg file.
EggGroups are the “entries” of the egg file.
addChild() allows you to set the hierarchy of the EggGroups/entries.
EggVertexPool is the entry.
It has an addVertex() method, but I don’t see how to add the UV entries.
Are the " { 1 }" and " fps { 2 }" lines found in the egg fonts needed?
Not sure how to add the data to the EggPolygon group object too.
And couldn’t find an object for Texture entry, unless it’s just EggGroup.

Sounds right. Specifically, EggGroup corresponds to a entry. You can use EggVertex.setUv() to set the UV coordinate for a particular vertex. (You can either create a new EggVertex and pass it to EggVertexPool.addVertex(), or you can get the return value from EggVertexPool.makeNewVertex().)

The switch and scalar entries are not needed for a font; they just serve to make the characters of the font rotate through one at a time if you pview the font egg file directly. For the record, you can set these with members of EggGroup if you choose.

EggPolygon inherits from EggPrimitive, which has an addVertex() method. Add each vertex to the polygon in counterclockwise order.

Textures are added with an EggTexture object, which corresponds to the entry. Create an EggTexture and add it to the root EggData, then reference it to each polygon with EggPolygon.setTexture() (this creates a entry for the polygon).

David

Thanks.
What about the ‘PointLight’ entries?
The VertexPool, which contains the vertices, is inside a Group. After that group are Groups for each polygon (quad). So the name of those Groups are the character codes. These “Polygon” entries hold the vertices which make up the polygon and the texture. These seem enough to hold all the needed data, but inside the group, alongside the “Polygon” entry is a “PointLight” entry. I think you explained before what it was for, but I still don’t understand.

In order to lay text out, Panda has to place each letter following the other on a line. Some letters are wider than others, so the space between consecutive letters is not always the same (unless you have a fixed-width font). So Panda needs to know how far apart to place each letter.

It could do this by analyzing the width of the polygon and putting a certain fixed blank space between the right edge of one letter and the left edge of the next one, but this wouldn’t be flexible and wouldn’t really give good-looking results. So instead, we allow the font to specify precisely how much space should be allocated for each letter, and that’s the purpose of the .

The PointLight marks the point on the baseline at which the next letter will be placed following this one. Or, in other words, the X coordinate of the PointLight is the amount of space that will be reserved for this letter.

David

Hm, well I guess I don’t need that because my font format doesn’t store such info and all glyphs are the same size.
Do I need to set that info either way? If so, what egg objects corresponds to “PointLight”? Are the numbers panda units then? What number should I use if my font data is fixed-width (my glyphs are 32x32 pixels).

You still need to provide that information; it will just be the same value for each letter in your case. EggPoint is the class that corresponds to (it also inherits from EggPrimitive, same as EggPolygon).

The PointLight units are the same units you use to make the quads for the letters. For a typical Panda font, this is chosen so that 1.0 = 1 vertical line separation. If your letters should have the same horizontal separation as vertical, then you will also use an X value of 1.0 in the PointLight, but I suspect that will be too wide. You can experiment with different values to find the one that works best for your font.

David