# Permission is granted to use, modify and distribute # this code freely, provided that this license clause # remains intact. # This code is intended to convert AngelCode BMFont font files # (.fnt) into a header file, for use with Nintendo DS homebrew # development. # This is intended to be used with the object files created by bin2o # in devkitPro. If the font name has spaces in it, this will probably break. # Try using underscores instead. # Another feature provided is that the kerning nodes are sorted to allow # binary search of kerning nodes, if you don't want to go to the effort of # putting them in a proper data structure. # An example declaration of the FontInfo, CharInfo, and KerningInfo structures # expected by this code: %{ namespace demo { struct FontInfo { const char* name; //Font name uint16 size; //Font 'size' uint16 height; //Actual line height of the font (may be different from size) bool bold, italic; Rect padding; Rect rectangle; //Area of the image file containing font data (usually {0,0, width,height}) const u8* data; //Pointer to the data (format not specified) uint32 dataSize; //Size of data uint16 charCount; //Number of characters uint32 kerningCount; //Number of kerning nodes }; struct CharInfo { uint16 id; //Code point uint16 x, y; //Position of the glyph in the bitmap uint8 width, height; //Size of the glyph int8 xoffset, yoffset; //How much to offset the glyph on the screen uint8 xadvance; uint8 page; //If there are several bitmaps, this is useful. I usually avoid this. } PACKED; struct KerningInfo { uint16 first, second; signed char kerning; } PACKED; } } for file in ARGV lines = File.open(file, "r") do |f| f.read end face = nil size = nil width = nil height = nil line_height = nil chars = [] kerning = [] # This could be better, but it works... for line in lines m = /(\w+)\s+(.*)/.match(line) if m name = m[1] parts = {} m[2].split(/\s+/).each do |ma| ma=ma.split('=') parts[ma[0]] = ma[1] end case name when "info" face = parts["face"].gsub(/(^\")|(\"$)/,''); size = parts["size"].to_i bold = parts["bold"].to_i italic = parts["italic"].to_i when "common" line_height = parts["lineHeight"].to_i width = parts["scaleW"].to_i height = parts["scaleH"].to_i when "char" char = [] char << parts["id"] << parts["x"] << parts["y"] << parts["width"] << parts["height"] << parts["xoffset"] << parts["yoffset"] << parts["xadvance"] << parts["page"] chars << char when "kerning" kern = [] kern << parts["first"] << parts["second"] << parts["amount"] kerning << kern else end end end #Sort the kernings by first, then second. kerning = kerning.map {|k| k.map{|ki| ki.to_i } } kerning.sort! do |a,b| if a[0] != b[0] a[0] <=> b[0] elsif a[1] != b[1] a[1] <=> b[1] else 0 end end # Obviously, modify this part to suit your needs. # I should probably put the padding value in there too... File.open(file.gsub(/\.fnt$/,'.h'), "w") do |fh| fh.puts <