Bitmap font

A little while ago there was a tool called GlyphDesigner released by 71squared. The app is for the mac and allows you to design cool effects for fonts you have on your computer. The tool is really good and I wonder you can add support for that tool so corona reads font files created by GlyphDesigner?

Merry Christmas...

[edit]
Old code removed - see link below for latest code.
[/edit]

I don't have the registered version of Glyph Designer to test with, but it works with BMFont output, so it ought to work with Glyph Designer as well.

[edit]
After playing with Glyph Designer, I bought it and exported a font. I discovered and fixed an issue in my code that didn't like the fact that space was encoded as a 0px by 0px bitmap, and I can now say I have tested it with Glyph Designer output and it works nicely.
[/edit]

Awesome, thanks.

I made arial32.fnt file and a .png in GlyphDesigner and tried it with your code but when I ran it in the simulator I got this error;

Runtime error
...1HGkKXNH+WWf6ydHU3uW++++TI/TemporaryItems/48/bmf.lua:71: ERROR: Invalid parameter passed to sprite.newSpriteSheetFromData(). Missing data.
stack traceback:
[C]: ?
[C]: in function
'newSpriteSheetFromData'
...1HGkKXNH+WWf6ydHU3uW++++TI/TemporaryItems/48/bmf.lua:71: in function 'loadFont'
...HGkKXNH+WWf6ydHU3uW++++TI/TemporaryItems/48/main.lua:13: in main chunk

Runtime error: ...1HGkKXNH+WWf6ydHU3uW++++TI/TemporaryItems/48/bmf.lua:71: ERROR: Invalid parameter passed to sprit
e.newSpriteSheetFromData(). Missing data.
stack traceback:
[C]: ?
[C]: in function 'newSpriteSheetFromData'
...1HGkKXNH+WWf6ydHU3uW++++TI/TemporaryItems/48/bmf.lua:71: in function 'loadFont'
...HG
kKXNH+WWf6ydHU3uW++++TI/TemporaryItems/48/main.lua:13: in main chunk

Do you have any ideas why this happen? I have the .fnt file and the .png in the same directory as the main.lua and the bmf.lua

I just copied your code and made the bmf.lua file and copied the other code into my main.lua. Do I have to make a spriteSheet out of my arial.png too? Do I have to slice the all the letters into individual sprites to make a arial32.lua spriteSheet?

How did you make it work?
David

Here is a link to my example project, including font file:

http://ember.awirtz.com/bmf.zip

If you are having trouble, you can send me your sample project and I can take a look and see if I can figure out what is being buggy...

I got it to work, but I had a strange problem though. I copied everything of your code exactly like in your file you posted for download and when I ran the project I got the error above, but here is the strange part...
when I made a new set of files and replaced the old ones, the project worked???

I tried the old files 20 times and they failed in simulator but when I copied the code and pasted them into new file it built fine, is that a bug in corona or something?

I wish a clean Target/All Targets option were built in Corona Simulator, just like in xcode.

Are you perhaps using Windows?
(I wouldn't assume so if you are talking about Glyph Designer, which is a Mac program)
If so, maybe it's a Windows vs Mac end-of-line marker issue?

I tried freshly downloading and running the zip on my Mac and it doesn't have issues.

I got a mac, I've been testing some more and it seems to be something wrong with the font I used. I made a few different fonts and there was only that one that didn't work (materhorn.fnt, 64pt). I only changed the fonts and the rest was the standard presets that starts with glyph designer.

I have no clue what the problem could be? I can sent you the font file.
David

Thanks for sending the file.

After trial and error removing various lines from the FNT file until I isolated the problem, I discovered that the "`" (backtick) character for this font has a negative y-offset.
This confuses some of the math which calculates the spritesheet coordinates.
Also, I noticed that this FNT file has quite a few kernings, which my code currently ignores.
I'm working on updating the code to handle the negative y-offset and adding support for kernings.
In the mean time, if you delete the line for backtick (id=96) from the FNT file, you should be able to start working with your Materhorn.FNT while you are waiting for me.

I've updated my code to support negative offsets, added kerning support, and added support for newlines.

The new code is available at the link above. I also included an Impact-based font rather than the old Futura-based one to demonstrate the kerning support. (Notice that the "W"s and "A"s interlock properly)

One other caveat that I have discovered (technically it could be considered a bug in Glyph Designer) is that if you set the spacing too low (e.g. 0), some of the character x/y coordinates end up negative. Just make sure you have spacing set to at least 1px.

Cool, what does the dumper.lua file do?
Do I have to include that file in my projects when i use bmf?

No, you don't. Sorry I didn't mean to include that in the zip. (removed it now)

It is a Lua library for dumping the contents of data structures to the console so I can see what's going on inside of them when debugging.

@p120ph37:
thanks for the bmf.lua file!
i got a glyph designer license now and i am using the bmf.lua file to render a big bitmap font style timer that is updated by a Runtime "enterframe" event handler.
it is a central element of my game and it looks amazing.
--> thanks so far!

the only problem i face now is that when i check for memory leaks with instruments, it seems that the graphics that are created are not deallocated and i get memory warnings/crashes after a while.
i experimented with 'object:removeSelf()' and set the variables in my code to nil, it didn't help.

this is what it looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- SHOW TIME PLAYED WITH BMP CUSTOM FONT
 
--initialize bmp font timer:
local Timestring = bmf.newString(font2, "00:00:00:00")
Timestring.x = 55
Timestring.y = 70
 
 
--update bmp font timer:
function TimestringUpdate (newString)
Timestring:removeSelf()
Timestring = nil
Timestring = bmf.newString(font2, newString)
Timestring.x = 55
Timestring.y = 70 
newString=nil
end
 
--newString parameter comes from another function 
-- this is called by a runtime "enterframe"event listener

I edited the code a little so it only draws a new picture every 50ms.
helps a little because now it uses up the memory much slower, but doesn't solve the problem.

Thanks for the feedback - So far I have used it mostly for fairly low-refresh things so I hadn't seen the memory leak issues. I will look into it when I get a chance. Can you provide me with the debug statements you are using to track the memory usage too?

In the mean time, I have some minor updates of my own that I've made to the BMF library while working on my own projects, which I have uploaded to the ZIP. I fixed an off-by-one issue with spritesheet alignment, added support for newlines, and added placeholder rectangles so that the text centers correctly when there are leading/trailing spaces or blank lines.

Actually, I think I've located the issue. ( I took your example code and fed it system.getTimer() data every frame while monitoring the value of collectgarbage( 'count' ) )

It seems that Corona does not automatically free the memory used by children of a group object when the group object is removed.

As a work-around, I have overridden the 'removeSelf' method of my string objects (really just group objects under the hood) so that it removes its children before removing itself.

Your memory leak should now be gone with the latest version of the library.

Cheers!

NB: If you use the parent:remove( string ) form rather than string:removeSelf(), this will not hit my custom removeSelf method.

Wow, Great News! I will try it out Tomorrow!

ahh.. download link seems to be broken. could you check?

works like a charm:

thank you!

I threw a few more examples and sample fonts into the demo - this should give people something decent to play with before deciding if they want to buy Glyph Designer.

This is great, very much help. As an owner of Glyph Designer who likes the look of Text Candy how can I easily convert angelcode .fnt into .lua spritesheet?

I don't own Text Candy, and there doesn't seem to be any detailed information on the website describing the spritesheet definition format that they are using, so I don't know for sure, but I imagine it shouldn't be terribly difficult to take my .fnt parsing routine and modify it slightly to work as a Text Candy .lua file.

Incidentally, I have some new code I've been working on for my BMF library that allows you to use bitmap fonts for text input fields and to change the text or font of a label without having to destroy and recreate it entirely. Stay tuned... :-D

Thanks for the speedy response and very much looking forward to BMF developments:)

It looks like Candy are using the the standard Corona table .lua spritesheet definition as produced by Zwoptex/Texturepacker.

Thanks for the info.

I looked at how Zwoptex structures its .lua file and it's pretty straightforward.
So to use AngelCode-style .fnt files as font definitions for TextCandy, you should be able to just save this code snippet with the same base name as your myfont.png and myfont.fnt files (e.g. myfont.lua) and use that as your TextCandy definition file.

1
2
3
4
5
module( ... )
require( 'bmf' )
function getSpriteSheetData()
  return bmf.loadFont( _M._NAME ).spritesheets[0]
end

Thanks again http://developer.anscamobile.com/forum/2011/03/19/new-candy-tool-text-candy-corona-50-coupon-inside#comment-28723 is posted as a tutorial for creating fonts
I haven't bought Candy yet as I was hoping to purchase both products together:) but I guess I will just have to take the plungette now and pay a pal!

Your BMF lib takes kerning into account? I don't think text Candy does.

Right - from the settings I they describe in the documentation, it doesn't seem that TextCandy handles kerning or any sort of character overlap for that matter.

Also, my example probably won't work as-is... I forgot that in the version of my BMF library that's on the server right now I'm destroying the spritesheet definition once the spritesheet is loaded so it's no longer accessible after loadFont has completed.

Plus you probably want to get additional information from the .fnt file besides just the sprite locations - like the line height and the space width and y-offsets.

I've updated the library so it doesn't destroy the spritesheet definition.

I've also included a sneak-peek at a few new features that I haven't had a chance to show off in the demo yet:

object.text and object.font are now properties which can be read/written after the object is created.
object.align allows some rudimentary text alignment options.
object.input() allows you to use a text object as an input field - no more ugly white input boxes! (this is still a bit in development - expect more detailed documentation soon...)

Finally, I've posted to the TextCandy thread with some ideas on integration - we'll see if X-Pressive wants to help with that.

Thanks very much for all your help with this, I still have a tonne to learn but hopefully I will get there. :)

You can Download Computer Fonts which you required and upload in your system.

p120ph37, thanks for sharing! But do you have any updates for this? When navigating away from the scene that uses BMF fonts the simulator hangs for me with 100% CPU. I'm using the Director class to manage scenes, so maybe this has something to do with Director's cleangroups() method.
Also, I noticed there is 1px clipping at the bottom with the font I generated with BMFFont.

EDIT: I found the reason for trimming, changed code on line 40 to:

1
textureRect = { x = 0 + t.x, y = 0 + t.y, width = -1 + t.width, height = t.height }, -- removed "-1" for "height"

@vitalyx

Hi,
Sorry I haven't updated the code in a while. One of the tricks in my BMF implementation was that I had to clean out the contents of the group objects as they were destroyed since Corona at the time I wrote the code had a bug which would leak memory if I didn't. I understand that has been fixed in the more recent builds, but I haven't had a chance to try it out yet. You might try removing that part of my code and see if it helps your issue. As far as coordinates and the 1px clipping, I did most of my testing with the fonts from Glyph Designer, so it may be possible that BMFFont uses slightly different coordinate numbering - I'll have to look into that at some point, but if you have it working for your particular font, great! If you do decide that BMF fonts are a good option in Corona and if you have a Mac available, I would highly recommend trying out Glyph Designer... ;-)

I can't promise anything on timeframes, but I'll try to get back to this library sometime soon to update it and release a couple of extras I've been working on for it.

Hi p120ph37, thanks for your reply. I will be looking forward to this update. Till then I will probably put up a tiny module of my own, since my only need for now is displaying outlined numbers, so no worries.

I decided to dive into your code instead and understand what it does.
Pretty clever, but quite hard to read, IMO.
I've modified the newString() function.
Now there is no need for accessorize/removerize functions, behavior looks the same (though, I haven't done much testing), there is less code and it's easier to understand.

Here it is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
function newString(sFont, sText)
    local obj = display.newGroup()
 
    local font, text, align
 
    function obj:getFont()
        return font
    end
 
    function obj:getText()
        return text
    end
 
    function obj:getAlign()
        return align
    end
 
    function obj:setAlign(a)
        align = a
        local width = self.contentWidth
        if a == "right" then
            for i = 1, self.numChildren do
                self[i].x = self[i].x + width
            end
        elseif a == "center" then
            for i = 1, self.numChildren do
                self[i].x = self[i].x - math.floor(width * 0.5)
            end
        end
    end
 
    function obj:setText(t)
        if type(t) ~= "string" then return end
 
        text = t
        for i = self.numChildren, 1, -1 do self[i].removeSelf() end
        local x, y, xMax, yMax = 0, 0, 0, 0
        local last = ""
 
        for c in string.gmatch(text .. "\n", "(.)") do
            if c == "\n" then
                x = 0
                y = y + font.info.lineHeight
                if y >= yMax then yMax = y end
            elseif font.chars[c] then
                if 0 + font.chars[c].width > 0 and 0 + font.chars[c].height > 0 then
                    local letter = sprite.newSprite(font.sprites[c])
                    letter:setReferencePoint(display.TopLeftReferencePoint)
                    if font.kernings[last .. c] then
                        x = x + font.kernings[last .. c]
                    end
                    letter.x = font.chars[c].xoffset + x
                    letter.y = font.chars[c].yoffset - font.info.base + y
                    self:insert(letter)
                    last = c
                end
                x = x + font.chars[c].xadvance
                if x >= xMax then xMax = x end
            end
        end
 
        local background = display.newRect(0, -font.info.base, xMax, yMax)
        obj:insert(background)
        background:setFillColor(0, 0, 0, 0)
 
        self:setAlign(align)
    end
 
    function obj:setFont(f)
        font = f
        self:setText(text)
    end
 
    align = "left"
    text = sText
    obj:setFont(sFont)
 
    return obj
end

@vitalyx:

That's similar to what I had at first. I added the "accessor" functionality so that it would behave more like the native text strings where you can change the displayed text by just setting the value of the "text" attribute rather than by calling a method. The idea was to make it usable as a drop-in replacement for the native text objects. Removing that layer of abstraction will certainly make the code easier for you to understand and work on if you want to learn how it works though!

Oh, I see :) Well, maybe this will make it easier for somebody else who is curious what's going on there. As I rarely just copy-paste other people's code and usually try to at least understand it. But most of the time modify it to suit the needs of my project or just to make it conform with the rest of the code better.

BTW, the above code appears to work fine with the Director class, so if somebody had this same problem, this is worth noting.

Also, I haven't figured out how alignment works.
I would expect "right" to look like this:

1
2
3
abcdefg
  abcde
    abc
views:3837 update:2011/9/17 18:17:57
corona forums © 2003-2011