• Welcome to Dark Bit Factory & Gravity.
 

Bitmap-Font Maker

Started by hellfire, December 22, 2009

Previous topic - Next topic

0 Members and 0 Guests are viewing this topic.

hellfire

As a friend of mine asked for a simple way to create bitmaps from true-type-fonts, I dug out an old tool of mine - maybe it's useful for someone else, too.

What it does is rendering each character into a bitmap and tries to place them all into one map.
It creates a list with information about
  x-position
  y-position,
  width,
  height,
  offset from base-column (this is useful for serif-fonts where characters partially overlap),
  offset from base-line
  actual width required by the character (that's where the next character starts)

An extreme example of a single character stored in the map looks like this:


You can specify font, size, bitmap, spacing, number of colours and color-encoding.
There are some additional options like creating a set of required characters from the actual text and exporting image-data as ready to include source-code.

A simple heuristic tries to avoid worst-case scenarios when assembling the different character-bitmaps into a single map - but it's yet far from optimal or even clever.

Download here (3.1mb due to Qt).

Feature requests are welcome.

A very simple example how to use this with OpenGL is attached below.

Have fun.
Challenge Trophies Won:

rain_storm

Very useful stuff hellfire will definately be making some use of this in future

Challenge Trophies Won:

Pixel_Outlaw

These kinds of tools always fill a need. Have some karma.
Challenge Trophies Won:

zawran

Looks like a really useful tool, thanks for sharing.

Voltage

Great tool hellfire.

It has some nice features.... Generate chars list (from sentence), texture size, and the very useful char location array that goes with it.

karma++
Challenge Trophies Won:

Voltage

I was able to get this working with a simple opengl texture example.

2 things though:

1) The "Save As Array" option in fontmaker doesn't add commas to the end of each line.  I had to manually add these commas.

2) I had a little bit of trouble trying to figure out which OGL settings to use to import this data as a texture.  I used the following:


glGenTextures( 1, &texture );
glBindTexture( GL_TEXTURE_2D, texture );
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, fontdata);
Challenge Trophies Won:

hellfire

#6
I usually use

glTexImage2D(
  GL_TEXTURE_2D,
  0,
  GL_ALPHA,
  sizeX,
  sizeY,
  0,
  GL_ALPHA,
  GL_UNSIGNED_BYTE,
  data);

This way all information is inside the alpha-channel so you can use proper blending and specify the color using glcolor.

In your screenshot you need to take the "baseline" parameter into account (the 7th in each row).
Postive value means up, negative value means down.
See screenshot above.
Challenge Trophies Won:

Voltage

#7
ah that makes sense.  I did get alpha working, but I did it an ugly way.

I created a temp buffer twice the size of the texture and...


for (i=0;i<512*512;i++) {
  buffertmp[i*2]=buffer[i];
  buffertmp[i*2+1]=buffer[i];
}


Then I used GL_RGBA and GL_LUMINANCE_AND_ALPHA (or something similar).

The method shown above(yours) is obviously cleaner.  Thanks for pointing that out.
Challenge Trophies Won:

hellfire

#8
Well, the goal for the array-export is to keep the data as compact as posibble but still uncompressed (because thats what the exe-packer likes), so I thought it's enough to store a single channel.
If you like to store other formats I could add a selector for that.
I plan to support syntax for different languages, too.
Challenge Trophies Won:

combatking0

Very nice - finally a feature-rich font editor without ads/fees/viruses. K++
You are our 9001st visitor.
Challenge Trophies Won:

Voltage

ok, I got the alpha channel working as per hellfire's instructions.  And the character positions also.

thanks again hellfire. 

Challenge Trophies Won:

hellfire

The "l" in "reload" isn't properly centered between the "e" and the "o".
So either you didn't take the offset from the base-column into account or I didn't calculate the character-width correctly (haven't tried any font in italics so that's quite possible).
I'll have a look at that later.
Challenge Trophies Won:

Clyde

^^also the m.

Cool, will give this a whirl.
Still Putting The IT Into Gravy
If Only I Knew Then What I Know Now.


Challenge Trophies Won:

Voltage

I hadn't included the column adjustments.  I have now.

I'm not using italics, the letters are spinning.  See the attached exe.

The source is a dog's breakfast at the moment.  I'll clean it up a little and post it soon.
Challenge Trophies Won:

hellfire

#14
Quote from: Voltage on December 28, 2009
I'm not using italics, the letters are spinning.  See the attached exe.
Cool :)

Noticed that I didn't reserve enough spare-pixels when rendering fonts with extreme amount of serifs, so I added an option to select it manually - cut regions are marked with a white line.
Challenge Trophies Won:

energy

Great tool ,Hellfire....
:goodpost:
Possible to get output format for MASM???
coding: jwasm,masm
hobby: www.scd2003.de

hellfire

Sure. I don't use MASM, though. So please post a syntax-example.
Challenge Trophies Won:

hellfire

#17
Added a distance field rendering option for completeness (updated download link is in post #1).
More about distance field font rendering can be found here and here.
The distance is computed on a sub-pixel-level from the anti-aliased text, so the "supersampling" should be set to 1 (otherwise it takes literally ages to compute).
The interior threshold level is 128.
Challenge Trophies Won:

Raizor

Interesting stuff Hellfire. I've come across this concept before, but this is the first time it's actually made sense to me.

Would it be possible to generate the distance fields at runtime for use in 64k intros or suchlike? I'm just curious as to whether the code to generate the data would be significantly smaller than a 256x256 or 512x512 texture.
raizor

Challenge Trophies Won:

hellfire

Quote from: Raizor on April 17, 2012
Would it be possible to generate the distance fields at runtime for use in 64k intros or suchlike?
The code to generate the distance field is trivial and pretty compact.
It just does a spiraling search around each pixel to find the smallest distance to the neighbouring points.
To get some better precision I do a re-vectorization of the anti-aliased bitmap using marching squares.
Otherwise (when working with whole pixel distances only) you would need to increase the rendering size drastically (which makes the search incredibly slow).
But that's because the distance-search is just a naive add-on to the regular text-rendering function of this tool.

If you'd want to create a distance texture in a 64k-intro you'd probably store your font in some vectorized format anyway.
So you can simply test each pixels distance against the surrounding edges.
Since such vector-data is probably optimized (using as few points as possible to save space), the distance check should be pretty much faster than the pixel-based approach and certainly fits into a few hundred bytes of code.

Challenge Trophies Won: