So, I worked around this by extending the Font class (see below for code). It functions as it used to, but you can call extendFont() and pass an array of Images and it will rebuild the font, assuming it's been chopped up into the original file followed by the files in the list.
For example:
newFont: new ig.Font('pathToFonts\font.png'),
fontExImg: [ new ig.Image('pathToFonts\second_font_file.png'),
new ig.Image('pathToFonts\third_font_file.png')],
...
init: function() {
this.newFont.extendFont(this.fontExImg);
}
In this case, I've chopped the original font file into 3 sub-images: font.png, second_font_file.png, third_font_file.png.
Yeah, this is hacky. A better way would be to subclass Font to MultiFileFont, but I'm on a tight schedule and didn't want to ramp up on adding new native classes.
Here's the new version of Font.js:
ig.module(
'impact.font'
)
.requires(
'impact.image'
)
.defines(function(){
ig.Font = ig.Image.extend({
widthMap: [],
indices: [],
extImages: [],
extBreakpoints: [],
firstChar: 32,
height: 0,
extendFont: function( extPath ) {
while (extPath && extPath.length) {
this.extImages.push(extPath.shift());
}
this._loadMetrics( this.data );
},
onload: function( ev ) {
this._loadMetrics( this.data );
this.parent( ev );
},
widthForString: function( s ) {
var width = 0;
for( var i = 0; i < s.length; i++ ) {
width += this.widthMap[s.charCodeAt(i) - this.firstChar] + 1;
}
return width;
},
draw: function( text, x, y, align ) {
var curImage = this;
if( typeof(text) != 'string' ) {
text = text.toString();
}
if( align == ig.Font.ALIGN.RIGHT || align == ig.Font.ALIGN.CENTER ) {
var width = 0;
for( var i = 0; i < text.length; i++ ) {
var c = text.charCodeAt(i);
width += this.widthMap[c - this.firstChar] + 1;
}
x -= align == ig.Font.ALIGN.CENTER ? width/2 : width;
}
for( var i = 0; i < text.length; i++ ) {
var c = text.charCodeAt(i);
x += this._drawChar( c - this.firstChar, x, y );
}
ig.Image.drawCount += text.length;
},
_drawChar: function( c, targetX, targetY ) {
if( !this.loaded || c < 0 || c >= this.indices.length ) { return 0; }
var scale = ig.system.scale;
var realIndex = c;
// Figure out which image to use.
curImage = this;
for (var i=0; i<this.extImages.length; ++i) {
if (c >= this.extBreakpoints[i]) {
curImage = this.extImages[i];
}
}
var charX = this.indices[c] * scale;
var charY = 0;
var charWidth = this.widthMap[c] * scale;
var charHeight = (this.height-2) * scale;
ig.system.context.drawImage(
curImage.data,
charX, charY,
charWidth, charHeight,
ig.system.getDrawPos(targetX), ig.system.getDrawPos(targetY),
charWidth, charHeight
);
return this.widthMap[c] + 1;
},
_loadMetrics: function( image ) {
// Draw the bottommost line of this font image into an offscreen canvas
// and analyze it pixel by pixel.
// A run of non-transparent pixels represents a character and its width
this.height = image.height-1;
this.widthMap = [];
this.indices = [];
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
var ctx = canvas.getContext('2d');
ctx.drawImage( image, 0, 0 );
var px = ctx.getImageData(0, image.height-1, image.width, 1);
var currentImage = 0;
var currentChar = 0;
var currentWidth = 0;
for (var i=0; i<1 + this.extImages.length; ++i) {
if (i > 0) {
image = this.extImages[i - 1].data;
this.extBreakpoints.push(currentChar);
currentWidth = 0;
if (image) {
canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
ctx = canvas.getContext('2d');
ctx.drawImage( image, 0, 0 );
px = ctx.getImageData(0, image.height-1, image.width, 1);
}
else {
break;
}
}
for( var x = 0; x < image.width; x++ ) {
var index = x * 4 + 3; // alpha component of this pixel
if( px.data[index] > ig.Font.ALPHA_THRESHOLD ) {
currentWidth++;
}
else if( px.data[index] <= ig.Font.ALPHA_THRESHOLD && currentWidth ) {
this.widthMap.push( currentWidth );
this.indices.push( x-currentWidth );
currentChar++;
currentWidth = 0;
}
}
}
this.widthMap.push( currentWidth );
this.indices.push( x-currentWidth );
}
});
ig.Font.ALPHA_THRESHOLD = 2;
ig.Font.ALIGN = {
LEFT: 0,
RIGHT: 1,
CENTER: 2
};
});