Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Allegro5, HTML5, TTF addon, FreeType

Credits go to Eric Johnson, LennyLen, Mark Oates, nshade, and SiegeLord for helping out!
This thread is locked; no one can reply to it. rss feed Print
Allegro5, HTML5, TTF addon, FreeType
Edgar Reynaldo
Member #8,592
May 2007
avatar

So I recently learned how to do fancy text using javascript and HTML5 with Eric Johnson's library Momo.

What I'm wondering is, does anyone here have any experience with FreeType and rendering glyphs? I know allegro stores a pre-drawn copy of the glyphs, but in HTML5, you can do some nice fancy text outlines, and I was also wondering about 3D text, taking the vectors and extruding them into space. That way I could have an awesome 3D Allegro intro screen on all my proggies.

Does Allegro 5 store the font information, or just a pre-drawn copy of the font? Ie, can I get the vectors from Allegro?

Does anyone know what I'm talking about?

LennyLen
Member #5,313
December 2004
avatar

I was actually looking last night for an Allegro 5 function to draw the outline of a font and was quite surprised to find there isn't one. It would be a good addition if you figure it out.

Eric Johnson
Member #14,841
January 2013
avatar

LennyLen said:

I was actually looking last night for an Allegro 5 function to draw the outline of a font and was quite surprised to find there isn't one.

How to create text outlines in Allegro 5:

1. Create an empty bitmap
2. Draw some text to said bitmap
3. Iterate over said bitmap's pixel data looking for where the text begins
4. Plot some black pixels at that point
5. Copy the bitmap to the screen
6. ???
7. Profit :D

More seriously, maybe try drawing a bold font first as the outline, then the non-bold version on top of that? Depending on the font, it could make for a cheap solution to outlines.

I remember this thread from a few years back, but I guess nothing came of it.

LennyLen
Member #5,313
December 2004
avatar

More seriously, maybe try drawing a bold font first as the outline, then the non-bold version on top of that? Depending on the font, it could make for a cheap solution to outlines.

I've done it this way before, and the results are mixed. also Having an Allegro function that could draw actual outlines based on the glyphs would be much better.

nshade
Member #4,372
February 2004

You draw an outline in Allegro using TTF by Drawing you text at the following coordinates relative to the place you want the text with your outline color
-1,-1
1,-1
-1,1
1,1

Then you draw your text again at 0,0 as the text color you want. It's how I've always drawn my text.

Edgar Reynaldo
Member #8,592
May 2007
avatar

SiegeLord
Member #7,827
October 2006
avatar

Added https://github.com/liballeg/allegro5/issues/891 in case someone wants to revive it. It seems like a nice feature.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Edgar Reynaldo
Member #8,592
May 2007
avatar

I don't mind looking at it, but I can't guarantee I can make sense of everything he did in that patch. I forked allegro5 so I can work on it. That patch is pretty old too, so some things might not line up right anymore.

EDIT
One thing is, is an API issue. What functions need to support the border? Do you want to cache the outline? In which case, how thick should it be? Do you want to render a glyph in real time? Do you want to render both a border and the character? Or only one or the other in a given font?

EDIT2

In the image below, the top two are HTML English Bold 48pt with a drop shadow of 2 and 1 px respectively. The bottom two are supposedly EnglishBold 48 and 36 pt text rendered with a canvas element in HTML5 using Momo.js by Eric Johnson. The outline widths are 2 and 1 px respectively.

{"name":"611316","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/7\/77aa7532ab7fb6c2332d324cdec7d959.png","w":1920,"h":1080,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/7\/77aa7532ab7fb6c2332d324cdec7d959"}611316 (Best viewed full size)

Personally, the drop shadows look better in my opinion, even yellow shadow on white text makes it clearer, especially on green.

Mark Oates
Member #1,146
March 2001
avatar

Best viewed full size

{"name":"611317","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/d\/4\/d4057afcab72095bc0e29bce5db2cd14.gif","w":360,"h":244,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/d\/4\/d4057afcab72095bc0e29bce5db2cd14"}611317

Eric Johnson
Member #14,841
January 2013
avatar

The text rendered on the canvas doesn't appear to be using the same font as in the HTML. What's your code for loading the font in Momo look like?

Momo expects the font to point to a file, not a font face name. So for example, you can't do Momo.loadFont("Arial"); you'd have to point it to a file instead like so: Momo.loadFont("arial.ttf"). It's on my to-do list to allow for using fonts that are already declared in CSS or are known by the browser (like Web safe fonts) without having to specifically load them from a file.

But currently, if the specified font file does not exist or can not be loaded, the system's default font is used instead. That would typically be a serif font (usually Times New Roman). Likewise, there's currently no elegant way to set the font's style (bold, italic, oblique). It uses the normal weight by default. Also, text is measured in pixels, not points, on a canvas.

Fonts in Momo are just object literals, so you could manipulate them directly and hack up the desired result:

#SelectExpand
1// Load the font. The font file doesn't matter; we'll overwrite it in a bit anyway. 2let font = Momo.loadFont("some_font.ttf"); 3 4// Hack the internals of the font. 5font.name = "EnglishBold"; // Match the font-face name used in CSS, for example. 6 7// .... 8 9// Draw some text. This uses "EnglishBold" instead of "some_font.ttf"; effectively using a font declared in CSS instead of directly loading it in JS. 10Momo.drawText(font, Momo.makeColor(255, 255, 255), 36, 0, 0, "left", "Hello my name is Inigo Montoya", Momo.makeColor(0, 0, 255), 2);

Edgar Reynaldo
Member #8,592
May 2007
avatar

This image is better. I drew the upper bottom image with a 1.0 px blue outline, and the lower bottom image with first a 5 px outline, then the regular text over the bottom. This looks the best in my opinion.

{"name":"611318","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/1\/b152119e3f1ddd74b60fe2db9f590a3d.png","w":1920,"h":1080,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/1\/b152119e3f1ddd74b60fe2db9f590a3d"}611318

Eric, here's a zip of everything I used :

text_gen.zip

I believe I'm loading the fonts properly. But sizes in html always seem to be off somehow.

Eric Johnson
Member #14,841
January 2013
avatar

The stretching is caused by setting the canvas' dimensions in CSS. CSS takes priority, then it gets stretched by whatever you set it to in JS.

Change this:

#SelectExpand
1canvas { 2 background: #000; 3 width: 100%; 4 height: 100%; 5}

To this:

#SelectExpand
1canvas { 2 background: #000; 3}

It's best not to set the canvas' dimensions in CSS. Just let the JS do its thing and you'll get this:

{"name":"611320","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/0\/b0a4d1c5ae48a673f5ae8b6f675be8f7.png","w":1600,"h":900,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/0\/b0a4d1c5ae48a673f5ae8b6f675be8f7"}611320

No more stretching! Now if you want it to fill the window's width, you can use window.innerWidth instead of a fixed number. That might overflow a bit, so just add overflow-x: hidden; in your CSS for the body. Now it looks like this:

{"name":"611321","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/3\/b3d00beebc94e5a3f3c2457aaa0d17b2.png","w":1600,"h":900,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/3\/b3d00beebc94e5a3f3c2457aaa0d17b2"}611321

Then to make the text in Momo bold and italic like the HTML, change this:

#SelectExpand
1font = Momo.loadFont("English.ttf");

To this:

#SelectExpand
1font = Momo.loadFont("English.ttf", "bold italic");

Now you get this:

{"name":"611322","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/d\/a\/dac26d2dcda185be5da138b79d9a2458.png","w":1600,"h":900,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/d\/a\/dac26d2dcda185be5da138b79d9a2458"}611322

Here's the source will all the changes: textgen2.zip. It includes the latest version of Momo, too (you'll need it for setting font styles like bold and italic).

There are a few other issues I noticed:

1. You're using "font-family:english;" in your CSS, but you didn't load the font using "@font-face". So you're not really using the font; you're just using the default serif font.
2. You're doing the old hack for resizing the canvas in JS. With the new version of Momo I included in the above ZIP file, you can call Momo.resizeCanvas(width, height) instead of calling Momo.setCanvas() again. You can keep using the hack though; it'll still work, but it's a hack. ;)

Hope this helps. Let me know if you have any questions. :)

Edit
Here's an edit just for fun; now they look pretty much identical:

{"name":"611324","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/e\/6e282c0f6a2289920ac1b09d00e25393.png","w":1600,"h":900,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/e\/6e282c0f6a2289920ac1b09d00e25393"}611324

Edit #2
Your fonts (English.ttf and EnglishBold.ttf) seem to be broken. My browser can't decode either of them. Where did you get them?

Edgar Reynaldo
Member #8,592
May 2007
avatar

1. You're using "font-family:english;" in your CSS, but you didn't load the font using "@font-face". So you're not really using the font; you're just using the default serif font.

That's necessary? I see all kinds of advice on changing fonts where they only change the font-family style rule, and supposedly it works. How do I use "@font-face"? I can change "english" to "Helvetica" and it shows the font change. I don't quite know what you're talking about. I've never heard of "@font-face" before...

I like the updated Momo, with bold and italic font loading.

EDIT
I got my fonts from some free font website. Momo can load them.

Eric Johnson
Member #14,841
January 2013
avatar

There are about a dozen font families that are already installed on most operating systems and are already known to the Web browser. These are called "Web safe fonts". You can use them without having to load them from a file on a server. Here is a list of Web safe fonts (note that Helvetica is one of them).

In CSS3 (the modern version of CSS), there's what's known as the "font-face rule". Basically, if you want to use a font that the browser doesn't already know about, you have to load it from a file. Here's how you do that:

#SelectExpand
1@font-face { 2 3 /* You can name the font whatever you want. */ 4 /* When using this font, you'll refer to it by the name you give it. */ 5 font-family: "Example"; 6 7 /* Specify the location of the font file. */ 8 src: url("somewebsite.com/some_font.ttf"); 9}

That defines a new font that you can now use anywhere else in your CSS. So if you wanted to use the new font in the body of your Web page, you'd do it like so:

#SelectExpand
1body { 2 3 /* Uses the same name as the new font we defined. */ 4 font-family: "Example"; 5}

You can learn more about the @font-face rule here.

Edit
Here is a new ZIP: textgen3.zip. This time it includes a new font (Roboto Slab Regular) for testing purposes. Here's what I changed:

Added a @font-face to your CSS to include the new font:

#SelectExpand
1@font-face { 2 3 font-family: "RobotoSlabReg"; 4 src: url("./RobotoSlab-Regular.ttf"); 5 }

Then changed "english" to "RobotoSlabReg" like so:

#SelectExpand
1p { 2 font-size:48px; 3 color:white; 4 text-align:left; 5 font-family:"RobotoSlabReg"; 6 font-style:italic; 7 font-weight:bold; 8 }

Now the body uses the new font. Then I updated Momo (made several commits yesterday) and changed the font loading code in your JS to this:

#SelectExpand
1font = Momo.loadFont("RobotoSlabReg", "bold italic", true);

The new Momo.loadFont() method expects a string for the font file, an optional style, and an option Boolean for whether to use a font that has been loaded by a CSS @font-face rule. So the above tells Momo to use the RobotoSlabReg font-face that was already declared in CSS, so you don't have to load the font again.

Here's the result:

{"name":"611326","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/f\/efd02a8930fee332c5e75b09451c5faa.png","w":1600,"h":900,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/f\/efd02a8930fee332c5e75b09451c5faa"}611326

Hopefully that gives you an idea about how the @font-face rule can be used.

Edgar Reynaldo
Member #8,592
May 2007
avatar

Eric,

I tried messing around with @font-face rules, and while I can get them to work in my HTML, they don't work in the Canvas with Momo.

Nevermind, I got them to work. However, I would suggest a small API change in the function signatures like so :

function loadFont(file_name , style = "normal") {/*...*/}

function loadFontFace(font_family_name , style = "normal") {/*...*/}

This at least separates the two functions, and allows you to get rid of an annoying bool variable. It caused me to make several mistakes until I read the source code closely.

Eric Johnson
Member #14,841
January 2013
avatar

That's a good idea. Here's the updated version: momo.js. There's some documentation on Momo's GitHub wiki. It's not great documentation, but it's better than nothing. Full examples would be better (it's on my to-do list).

Edit
Alternatively, you can add this to the head section of your HTML files to always load the latest version of Momo:

#SelectExpand
1<script src="https://rawgit.com/ecj2/momo/master/momo.js"></script>

Edgar Reynaldo
Member #8,592
May 2007
avatar

You can also chain them together, so loadFont returns loadFontFace after you create a new style element and append it to the head section of the document. I see your wily tricks you devil you.

(+++++)
 (^;^)
_|   |__
=\   /=\\
\()^()/ \|
 (-o-)
 /\|/\
/_/ \_\

Thanks for teaching me web speak by the way.

Catch me on #allegro

bamccaig
Member #7,536
July 2006
avatar

You can also chain them together, so loadFont returns loadFontFace after you create a new style element and append it to the head section of the document.

Please yes. It hurts my eyes to see such blatant repetition right next to each other. >:(

Eric Johnson
Member #14,841
January 2013
avatar

I'm not a fan of chaining. It becomes too messy too quickly. If everything were to be chainable, then every method would need to return "this", and it would have to save the old return values as members, and I don't want to do that...

I guess I could have loadFont() return loadFontFace() to cut down on internal repetition though. :P

bamccaig
Member #7,536
July 2006
avatar

Chaining is ambiguous and suggests the wrong pattern. I assume all he meant was to call one from the other since they do the same thing.

Eric Johnson
Member #14,841
January 2013
avatar

You're right. My bad. I updated it to return loadFontFace(), like you suggested, Edgar.

bamccaig
Member #7,536
July 2006
avatar

I'm not a fan of chaining. It becomes too messy too quickly. If everything were to be chainable, then every method would need to return "this", and it would have to save the old return values as members, and I don't want to do that...

Side note: you're better off returning a new object of your type that contains the return value because the caller might still be using that other object for things.

Go to: