Font rendering with the FP10 drawing API

After all the vector/font rendering library is done – the HaXe sources and SWC files for ActionScript 3.0 are available on the polygonal google code project page. As a reminder – the project started as an experiment if it’s possible to render fonts using the FP10 drawing API without loading or embedding any additional assets.

For obvious reasons, I can only include free fonts. At the moment the de.polygonal.graphics.text.fonts package contains Microsoft’s TrueType core fonts hosted on sourceforge, the Bitstream Vera fonts as well as the famous bitmap04 pixel fonts.

The pros and cons

Pros

  • No font embedding required :) Import a font class and you are ready to go
  • Provides high quality font rendering; best used for extra smooth text animation
  • Seriously fast!
  • Seamless integration into the FP 10 drawing API

Cons

  • An ASCII set of printable characters adds about 20kb-30kb to the swf file – I’ll try to reduce this in a future release.
  • Not very readable at small font sizes (except pixel fonts) because it does not include any hinting information for improving the quality – text remains legible down to about 12 points (viewed at 100%)
  • You need a copy of Fontographer 4.1 to convert ttf files
  • No text field functionality yet
  • Only supports ASCII character (latin character set like ISO-8859 is planned)

Examples

Here are the ‘MS core fonts for the web’ rendered with the font library:

This also works amazingly well for pixel fonts (which I didn’t expect at all):

How it works

First a .ttf file is loaded into Fontographer and exported as a postscript file (I tried other methods but I stuck with this approach because postscript files are easy to understand). A parser reads this file and generates a HaXe class that contains the glyph data. The result is something like this: Arial.hx.

If using HaXe, the font_inline compiler flag gives you control over compilation time vs runtime performance. If omitted, compilation is fast so it’s best suited for frequent testing and debugging and the compiler-based auto-completion remains responsive. If compiled with -D font_inline, compilation is slow but results in the best performance.

The actual rendering is done by a class named de.polygonal.graphics.VectorRenderer. It uses the FP 10 drawing API in conjunction with ‘alchemy memory’ as a temporary buffer to gain some extra speed. At first all drawing commands are written into a chunk of memory, then copied into a vector and finally sent to the screen via graphics.drawGraphicsData(…). Depending on the CPU this is roughly 1.5-4x faster than using only vector. Note that this only accelerates the process of preparing the data, not the rendering itself (everything beyond drawGraphicsData())

ActionScript 3.0 usage

Grab the SWC file, add it to the library and the following code should (hopefully) compile fine:

package 
{
  import de.polygonal.ds.mem.MemoryManager;
  import de.polygonal.graphics.text.fonts.coreweb.Arial;
  import de.polygonal.graphics.VectorRenderer;
  import flash.display.MovieClip;
  import flash.Boot;
  
  public class Main extends MovieClip
  {
    public function Main():void 
    {
      new Boot(this);
      MemoryManager.allocate(4096);
     
      var vr:VectorRenderer = new VectorRenderer(512);
      vr.setLineStyle(0, 1, 0);
      
      var font:Arial = new Arial();
      font.bezierThreshold = 0.001;
      font.setPointSize(100);
      font.setRenderer(vr);
      font.write("Hello World!", 0, 100, false);
      
      vr.flush(graphics);
    }
  }
}

The source code reads like this:

  • initialize HaXe specific things
  • allocate 4 megs of alchemy memory to be on the safe side
  • create a vector renderer using a buffer size of 512kb
  • assign a line style (rgb, alpha, thickness)
  • create a font object
  • define curve smoothness, the smaller, the better (0=linear approx. using 2 segments/curve)
  • set the font size: 100 equals 72pt or one inch.
  • assign a renderer so the font can send drawing commmands to it
  • draw “Hello, World!” at the coordinates 0,100 (x,y), if the last parameter is true, the text will be centered around (x,y)
  • flush the buffer which draws everything to the screen

Glyph and text bounds

You can compute axis aligned bounding boxes for the whole text block or individual characters using the getBounds() and getIndividualBounds() methods prior to drawing the text:

Creating font classes

Converting fonts can be done using de.polygonal.gl.text.util.EPSConvert.

42 Comments

  1. Hey, did you know that as3swf can export font glyphs directly to drawing api code? You could generate the font .hx files directly from a swf (that has that font embedded) and skip the Fontographer/ps conversion:

    http://wiki.github.com/claus/as3swf/shape-export

    1. good to know – very cool stuff. maybe I’ll write an as3swf to HaXe bridge in the future :)

  2. I don’t understand why, but it doesn’t work with FP 10.1.51.45(prerelease version )

    1. I’m aware of that – somehow the class name FloatMemory and ByteMemory which I’m using for the memory stuff collides with 10.1 player. As soon as adobe releases a final version I’l try to fix this.

  3. John Stone

    Awesome stuff man. Look forward to playing with it.

  4. Hi I have problem why
    vectorRenderer.setFillColor(0xFF0000,1);

    or

    vectorRenderer.style.setFillColor(0xFF0000,1);

    doesn’t work ?
    How I can set fill color ?
    peter.

  5. ok it was easy I needed apply “fillStart” method.
    peter.

  6. Thank for this !!

  7. thanks, really nice!
    I have a question:
    how can i replace text? i tried this way, but it does not work:
    var vr:VectorRenderer = new VectorRenderer(512);
    vr.setLineStyle(0, 1, 0);

    var font:Arial = new Arial();
    font.bezierThreshold = 0.001;
    font.setPointSize(100);
    font.setRenderer(vr);
    font.write(“Hello World!”, 0, 100, false);
    vr.flush(graphics);
    font.write(“other text”, 0, 100, false);
    vr.flush(graphics);

    1. you can’t replace text, you have to redraw it: font.write(…) graphics.clear(); font.write(…)

  8. Downloaded polygonal_graphics_1.0.zip from repo and ….

    cant import
    de.polygonal.graphics.VectorRenderer;

    any help?
    Cheers

  9. actually I tried this as well and it didn’t work out for me. but I’ll definitely give that another shot … well, lets see if there is a happy end for my project, too. I’ll keep you posted about the result.

  10. Hi Michael,
    Yess I followed your guide. Is this might be cause I’m using FB? All libraries imported via swc. Still cant import VectorRenderer..

  11. Hi I’ve got this compiler error:

    Error: Assertation “invalid size (524288 bytes)” failed in file MemoryManager.hx, line 233, de.polygonal.ds.mem.MemoryManager::getFloatMemory
    at de.polygonal.core.util::Assert$/assert()[src/lib/de/polygonal/core/util/Assert.hx:52]
    at de.polygonal.ds.mem::MemoryManager$/getFloatMemory()[src/lib/de/polygonal/ds/mem/MemoryManager.hx:233]
    at de.polygonal.graphics::VectorRenderer()[src/lib/de/polygonal/graphics/VectorRenderer.hx:79]
    at Test()[/Users/byniutek/Documents/Flex Builder 3/polygonalTest/src/Test.as:17]

    1. You have to call MemoryManager.allocate(…). I’m working on an update to make it easier to use.

  12. Jonas Nyström

    Hi Michael!

    This is great stuff, very much longed for! Same problem as Zee, though. A working code example would be very much appreciated!

  13. Jonas Nyström

    Hi again, Michael!

    A minute after the post above, I found your brand new gl_1_01 release! Works like a charm this far! No need for MemoryManager as it seems…

    Thanx!

  14. actually I tried this as well and it didn’t work out for me. but I’ll definitely give that another shot … well, lets see if there is a happy end for my project, too. I’ll keep you posted about the result.

  15. Thanks Michael, Ihad the same problem I resolve it right now

  16. A working code example would be very much appreciated!

  17. I’m working on an update to make it easier to use.

  18. Hi, thanks for the great code. Except I’m also having trouble re-writing. It’s not clear whether you should re-use the renderer or Font object. If I try reusing it, no text is shown. I suspect it’s a memory issue, but I don’t really know. A Haxe example where you rewrite text would be really useful.

  19. The VectorRender class is not inside the package.

    Imported the SWC into Flashdevelop, using AS3 only.

    Please help !

  20. I realized that I could find the VectorRenderer inside the SVN, but in .HX format.

    Does it not exist in .AS format?

    It leaves me with a question: It this implementation possible in pure AS3 projects ? Even though HaXe is faster, the community would make great use of a pure AS3 implementation.

    I’d like to use it in my actual project, but I have no time to convert it all to HaXe…

    Finally, and this is not of your responsability, I found a few tutorials on how to use HaXe in FlashDevelop, but none of them good / simple enough to actually work here. I always get this error:

    Object reference not set to an instance of an object.

    at Duplicate.PluginMain.HandleEvent(Object sender, NotifyEvent e, HandlingPriority prority)
    at PluginCore.Managers.EventManager.DispatchEvent(Object sender, NotifyEvent e)

  21. thanks but that reply didn’t help much :P

    note: in flashdevelop, if one clicks the “+” button to collapse th contents of the SWC, it says “Object reference not set to an instance of an object.”

    1. I can’t reproduce this. Make sure you are using the latest FD version (former versions had some problems parsing swc files generated with HaXe).

  22. I am unable to see any effect from using bezierThreshold. Is there something special to do in order to specify the threshold. Does it affect the rendering speed?

    1. there is a noticeable difference for big fonts. try this:

      var font = new de.polygonal.gl.text.fonts.coreweb.Arial();
      var vr = new VectorRenderer();
      font.setRenderer(vr);
      vr.setFillColor(0, 1);
      vr.fillStart();
      font.size = 200;
      font.bezierThreshold = 0.01; //or 0.0
      font.write(‘Hello, World’, 100, 200);
      vr.fillEnd();
      vr.flush(someGraphicsObject);

      most of the time the visual difference is negligible, and setting the threshold to 0 improves performance.

  23. anyone noticed ? clicking the link above

    “converting fonts can be done using http://www.polygonal.de/doc/types/de/polygonal/graphics/text/util/EPSConvert.html

    Land on a 404 error page

    “Sehr geehrter Besucher,

    leider ist ein Fehler aufgetreten: Die gewünschte Seite wurde nicht gefunden (…)”

  24. Does this support superscript and subscript?

    1. sorry, super/subscript is not supported

  25. Anthony

    Has anyone got this working in Flash builder? I keep getting the following errors when trying to complie:

    TypeError: Error #1006: isNaN is not a function.
    at de.polygonal.gl::VectorRenderer/_getStroke()[src/lib/de/polygonal/gl/VectorRenderer.hx:1570]
    at de.polygonal.gl::VectorRenderer/applyLineStyle()[src/lib/de/polygonal/gl/VectorRenderer.hx:171]
    at de.polygonal.gl::VectorRenderer/setLineStyle()[src/lib/de/polygonal/gl/VectorRenderer.hx:185]

    1. Hi, can you try it with the swc files from SVN? (http://code.google.com/p/polygonal/source/browse/#svn%2Ftrunk%2Fswc%2Fgl) also, make sure you call haxe.init(this) before doing anything else

  26. Anthony

    Hi Michael
    Just before going to bed I tried it with the call to haxe.init(this) and it now works, so thanks for your quick reply and help on this. I will also try it with the swc files you suggest asap.

    I would really like to learn more about your font and vector rendering. Other than your API and wiki on google code do you have any more links to help get started please. For example where would I have been able to find out about the haxe call my code required. Thx and keep up the great work!

    1. about haxe call: http://code.google.com/p/polygonal/wiki/UsingActionScript3. also you can install haxe and then the polygonal library (run ‘haxelib install polygonal’ from the command line) which includes some sample files (C:Motion-Twinhaxelibpolygonal1,14sandboxgl)

  27. Hi Michael,

    I’m trying to use your libraries for some generative art machines I’m creating with AS3. http://www.kenhuxley.com/blog/

    I Got the swcs from here:

    http://code.google.com/p/polygonal/source/browse/#svn%2Ftrunk%2Fswc%2Fgl

    I followed instructions your ActionScript 3 support page.

    I can browse ds_release.swc but can’t access gl_release.swc. I’ve created the project a bunch of times, restarted FDT & rebooted etc with no luck. I’ve tried the debug and alchemy versions too. Same problem. The graphics swc are not being recognized by FDT.

    I’m using FDT MAX 4.3.1 & compiling with Flex 4.0 SDK.

    Your libraries look very powerful and I would love to get using them ASAP.

    I’d greatly appreciate any advice you could give me.

    Kind regards,

    Ken

    1. Try to rename the swc file so xxx.zip, then unzip the contents and rezip, then rename back to xxx.swc. I’ll update the gl package soon

Trackbacks/Pingbacks

  1. Social comments and analytics for this post…

    This post was mentioned on Twitter by polygonal: FP10 font rendering library released http://tiny.cc/CWizb

  2. [...] read about font rendering using the FP 10 Drawing API here in Polygonal Lab (AS3 Data structures fame). There should not be any limitation to font size because it uses the [...]

Get Adobe Flash player