Adding simplistic font rendering for HTML5 and Flash

This commit is contained in:
Matt Tuttle
2014-07-13 22:16:15 -05:00
parent 6d7388212a
commit d5084081e2
3 changed files with 213 additions and 27 deletions

View File

@@ -4,6 +4,7 @@ package lime;
import haxe.Unserializer;
import lime.graphics.Image;
import lime.graphics.Font;
import lime.utils.ByteArray;
@@ -456,11 +457,11 @@ class Assets {
}
/*if (type == AssetType.FONT || type == null) {
if (type == AssetType.FONT || type == null) {
if (cache.font.exists (id)) return true;
}*/
}
if (type == AssetType.SOUND || type == AssetType.MUSIC || type == null) {
@@ -1100,13 +1101,13 @@ class AssetCache {
public var enabled:Bool = true;
public var image:Map<String, Image>;
//public var font:Map<String, Font>;
public var font:Map<String, Font>;
public var sound:Map<String, Dynamic /*Sound*/>;
public function new () {
//font = new Map<String, Font> ();
font = new Map<String, Font> ();
image = new Map<String, Image> ();
sound = new Map<String, Dynamic /*Sound*/> ();
@@ -1117,7 +1118,7 @@ class AssetCache {
if (prefix == null) {
//font = new Map<String, Font> ();
font = new Map<String, Font> ();
image = new Map<String, Image> ();
sound = new Map<String, Dynamic /*Sound*/> ();
@@ -1135,7 +1136,7 @@ class AssetCache {
}
/*var keys = font.keys ();
var keys = font.keys ();
for (key in keys) {
@@ -1145,7 +1146,7 @@ class AssetCache {
}
}*/
}
var keys = sound.keys ();
@@ -1462,22 +1463,22 @@ class Assets {
#end
var bytes = File.getBytes (path);
var resourceName = "NME_font_" + (classType.pack.length > 0 ? classType.pack.join ("_") + "_" : "") + classType.name;
var resourceName = "LIME_font_" + (classType.pack.length > 0 ? classType.pack.join ("_") + "_" : "") + classType.name;
Context.addResource (resourceName, bytes);
var fieldValue = { pos: position, expr: EConst(CString(resourceName)) };
fields.push ({ kind: FVar(macro :String, fieldValue), name: "resourceName", access: [ APublic, AStatic ], pos: position });
//var constructor = macro {
//
//super();
//
//fontName = resourceName;
//
//};
//
//fields.push ({ name: "new", access: [ APublic ], kind: FFun({ args: [], expr: constructor, params: [], ret: null }), pos: Context.currentPos() });
var constructor = macro {
super();
fontName = resourceName;
};
fields.push ({ name: "new", access: [ APublic ], kind: FFun({ args: [], expr: constructor, params: [], ret: null }), pos: Context.currentPos() });
return fields;

View File

@@ -1,30 +1,205 @@
package lime.graphics;
import haxe.ds.StringMap;
import lime.utils.UInt8Array;
import lime.system.System;
#if js
import js.html.CanvasElement;
import js.html.CanvasRenderingContext2D;
#end
typedef GlyphRect = {
var x:Float;
var y:Float;
var width:Float;
var height:Float;
}
typedef GlyphData = {
var image:Image;
var glyphs:Array<Dynamic>;
var glyphs:StringMap<GlyphRect>;
};
@:autoBuild(lime.Assets.embedFont())
class Font {
#if (cpp || neko)
public var handle:Dynamic;
#if js
private static var __canvas:CanvasElement;
private static var __context:CanvasRenderingContext2D;
#elseif (cpp || neko)
public var handle:GlyphRect;
#end
public var fontFace(default, null):String;
public function new (fontFace:String) {
this.fontFace = fontFace;
#if (cpp || neko)
handle = lime_font_load (fontFace);
#end
}
public function createImage (size:Int, glyphs:String="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^`'\"/\\&*()[]{}<>|:;_-+=?,. "):GlyphData {
#if (cpp || neko)
var glyphRects = new StringMap<GlyphRect>();
#if js
if (__canvas == null) {
__canvas = cast js.Browser.document.createElement ("canvas");
__context = cast __canvas.getContext ("2d");
}
__canvas.width = __canvas.height = 128;
__context.fillStyle = "#000000";
__context.textBaseline = "top";
__context.textAlign = "left";
__context.font = size + "px " + fontFace;
// canvas doesn't give the appropriate metrics so the values have to be padded...
var padding = size / 4;
var x = 0.0, y = 0.0, i = 0;
var height = size + padding;
while (i < glyphs.length) {
var c = glyphs.charAt(i++);
var metrics = __context.measureText (c);
var width = metrics.width + 4; // fudge because of incorrect text metrics
if (x + width > __canvas.width) {
y += height + 1;
x = 0;
}
if (y + height > __canvas.height) {
if (__canvas.width < __canvas.height) {
__canvas.width *= 2;
} else {
__canvas.height *= 2;
}
__context.clearRect (0, 0, __canvas.width, __canvas.height);
__context.textBaseline = "top";
__context.textAlign = "left";
__context.fillStyle = "#000000";
__context.font = size + "px " + fontFace;
glyphRects = new StringMap<GlyphRect>();
x = y = i = 0;
continue;
}
__context.fillText (c, x + 2, y);
glyphRects.set(c, {
x: x,
y: y,
width: width,
height: height
});
x += width;
}
var image = new js.html.Image ();
image.src = __canvas.toDataURL();
return {
glyphs: glyphRects,
image: new lime.graphics.Image (image, __canvas.width, __canvas.height)
}
#elseif flash
var bd = new flash.display.BitmapData(128, 128, true, 0);
var tf = new flash.text.TextField ();
var format = new flash.text.TextFormat ();
format.size = size;
format.font = fontFace;
tf.defaultTextFormat = format;
// tf.embedFonts = true;
var mat = new flash.geom.Matrix ();
var i = 0, x = 0.0, y = 0.0, maxHeight = 0.0;
while (i < glyphs.length) {
var c = glyphs.charAt(i++);
tf.text = c;
if (x + tf.textWidth > bd.width) {
y += maxHeight + 1;
x = maxHeight = 0;
}
if (y + tf.textHeight > bd.height) {
if (bd.width < bd.height) {
bd = new flash.display.BitmapData(bd.width * 2, bd.height, true, 0);
} else {
bd = new flash.display.BitmapData(bd.width, bd.height * 2, true, 0);
}
glyphRects = new StringMap<GlyphRect>();
x = y = maxHeight = i = 0;
continue;
}
mat.identity ();
mat.translate (x, y);
bd.draw (tf, mat);
glyphRects.set(c, {
x: x,
y: y,
width: tf.textWidth + 2,
height: tf.textHeight + 2
});
x += tf.textWidth + 4;
if (tf.textHeight + 4 > maxHeight) {
maxHeight = tf.textHeight + 4;
}
}
return {
glyphs: glyphRects,
image: new Image (bd, bd.width, bd.height)
}
#elseif (cpp || neko)
var data = lime_font_load_glyphs (handle, size, glyphs);
@@ -34,8 +209,19 @@ class Font {
} else {
for (glyph in cast (data.glyphs, Array<Dynamic>)) {
glyphRects.set (glyph.char, {
x: glyph.x,
y: glyph.y,
width: glyph.width,
height: glyph.height,
});
}
return {
glyphs: data.glyphs,
glyphs: glyphRects,
image: new Image (new UInt8Array (data.image.data), data.image.width, data.image.height, data.image.bpp)
};
@@ -43,8 +229,6 @@ class Font {
#end
return null;
}
#if (cpp || neko)

View File

@@ -610,8 +610,8 @@ class DefaultAssetLibrary extends AssetLibrary {
#elseif html5
//::foreach assets::::if (type == "font")::@:keep class __ASSET__::flatName:: extends openfl.text.Font { #if (!openfl_html5_dom) public function new () { super (); fontName = "::id::"; } #end }::end::
//::end::
::foreach assets::::if (type == "font")::@:keep class __ASSET__::flatName:: extends lime.graphics.Font { public function new () { super ("::id::"); } }::end::
::end::
#elseif (windows || mac || linux)
@@ -621,7 +621,8 @@ class DefaultAssetLibrary extends AssetLibrary {
//::elseif (type == "music")::@:sound("::sourcePath::") class __ASSET__::flatName:: extends openfl.media.Sound {}
//::elseif (type == "font")::@:font("::sourcePath::") class __ASSET__::flatName:: extends openfl.text.Font {}
//::else::@:file("::sourcePath::") class __ASSET__::flatName:: extends lime.utils.ByteArray {}
::end::::end::::end::::end::
//::end::::end::::end::
::end::
#end