@awayjs/scene
Version:
AwayJS scene classes
203 lines (202 loc) • 8.05 kB
JavaScript
import { __extends } from "tslib";
import { FNTGeneratorBase } from './FNTGeneratrorBase';
import { BitmapImage2D } from '@awayjs/stage';
import { Rectangle } from '@awayjs/core';
import { GraphicsPathCommand } from '@awayjs/graphics';
var Bounds = /** @class */ (function () {
function Bounds() {
this.left = Number.MAX_VALUE;
this.right = Number.MIN_VALUE;
this.top = Number.MAX_VALUE;
this.bottom = Number.MIN_VALUE;
}
Bounds.prototype.grown = function (x, y) {
if (x < this.left)
this.left = x;
if (x > this.right)
this.right = x;
if (y < this.top)
this.top = y;
if (y > this.bottom)
this.bottom = y;
};
Bounds.prototype.toRect = function () {
return new Rectangle(this.left, this.top, this.right - this.left, this.bottom - this.top);
};
return Bounds;
}());
var FNTGeneratorCanvas = /** @class */ (function (_super) {
__extends(FNTGeneratorCanvas, _super);
function FNTGeneratorCanvas(stage, debug) {
if (debug === void 0) { debug = false; }
var _this = _super.call(this, stage) || this;
/**
* Debug mode.
* Prevent OffscreenCanvas and prevent canvas clear.
* Store canvas
*/
_this.debug = false;
_this.debug = debug;
return _this;
}
FNTGeneratorCanvas.getCanvasContext = function (width, height, debug) {
if (width === void 0) { width = 100; }
if (height === void 0) { height = 100; }
if (debug === void 0) { debug = false; }
var canvas = ('OffscreenCanvas' in self && !debug)
? new self.OffscreenCanvas(width, height)
: document.createElement('canvas');
canvas.width = width;
canvas.height = height;
return canvas.getContext('2d', { desynchronized: true, alpha: true });
};
FNTGeneratorCanvas.freeCanvasContext = function (ctx) {
if (ctx.canvas instanceof self.OffscreenCanvas) {
return;
}
// safari bug with canvas leaks
ctx.canvas.width = 0;
ctx.canvas.height = 0;
};
FNTGeneratorCanvas.transformChar = function (char) {
var fillData = char.fill_data_path;
// empty command
if (fillData.commands.length === 0) {
return null;
}
var path = new Path2D();
var box = new Bounds();
var data = fillData.data;
var commands = fillData.commands;
var pointer = 0;
for (var _i = 0, commands_1 = commands; _i < commands_1.length; _i++) {
var command = commands_1[_i];
switch (command) {
case GraphicsPathCommand.MOVE_TO: {
// flash path in twips, transform it
var px = data[pointer++] / 20;
var py = data[pointer++] / 20;
box.grown(px, py);
path.moveTo(px, py);
break;
}
case GraphicsPathCommand.LINE_TO: {
var px = data[pointer++] / 20;
var py = data[pointer++] / 20;
box.grown(px, py);
path.lineTo(px, py);
break;
}
case GraphicsPathCommand.CURVE_TO: {
var cx = data[pointer++] / 20;
var cy = data[pointer++] / 20;
var dx = data[pointer++] / 20;
var dy = data[pointer++] / 20;
box.grown(cx, cy);
box.grown(dx, dy);
path.quadraticCurveTo(cx, cy, dx, dy);
}
}
}
return {
path: path,
char: char,
rect: box.toRect(),
};
};
FNTGeneratorCanvas.sortPatches = function (a, b) {
return a.rect.height - b.rect.height;
};
FNTGeneratorCanvas.render = function (table, context, size, fontSize, padding) {
if (fontSize === void 0) { fontSize = 0; }
if (padding === void 0) { padding = 0; }
var chars = table.get_font_chars();
var patches = [];
var doublePad = padding * 2;
var totalArea = 0;
var scale = 1;
for (var _i = 0, chars_1 = chars; _i < chars_1.length; _i++) {
var char = chars_1[_i];
var path = FNTGeneratorCanvas.transformChar(char);
if (!path) {
continue;
}
totalArea += (doublePad + path.rect.width) * (doublePad + path.rect.height);
patches.push(path);
}
patches.sort(FNTGeneratorCanvas.sortPatches);
// TODO compute valid scale when fontSize is 0
if (fontSize) {
table.initFontSize(fontSize);
scale = /* 20 * table._size_multiply **/ size / table.get_font_em_size();
}
/**
* Render glyphs onto canvas
* We will render glyphs as white and background as black transparent
*/
context.save();
context.clearRect(0, 0, size, size);
context.fillStyle = '#fff';
var tx = padding;
var ty = padding;
var maxHeight = 0;
// pack glyph based on size
for (var _a = 0, patches_1 = patches; _a < patches_1.length; _a++) {
var path = patches_1[_a];
if (!path.path) {
continue;
}
// if overflow - jump next location
if (tx + path.rect.width + doublePad >= size / scale) {
tx = padding;
ty += maxHeight + doublePad;
maxHeight = 0;
}
/**
* @todo Support multiple channel table data
*/
if (ty + path.rect.height > size / scale) {
console.warn('[FNTGeneratorCanvas] Font image overflow, font will corrupted!');
}
maxHeight = Math.max(path.rect.height, maxHeight);
context.setTransform(scale, 0, 0, scale, (tx - path.rect.x) * scale, (ty - path.rect.y) * scale);
context.fill(path.path);
//context.strokeRect(path.rect.x,path.rect.y, path.rect.width, path.rect.height);
path.char.fnt_rect = new Rectangle((path.rect.x) / path.char.char_width, (path.rect.y) / table.get_font_em_size(), path.rect.width / path.char.char_width, path.rect.height / table.get_font_em_size());
path.char.fnt_uv = new Rectangle(tx * scale / size, ty * scale / size, path.rect.width * scale / size, path.rect.height * scale / size);
/*
path.char.fnt_uv = new Rectangle(
(tx - path.rect.x) * scale / size,
1 - (ty - path.rect.y) * scale / scale,
path.rect.width * scale / size,
path.rect.height * scale / size
);*/
path.char.fnt_channel = 0;
tx += path.rect.width + doublePad;
}
context.restore();
};
FNTGeneratorCanvas.prototype.generate = function (font, size, fontSize, padding) {
var context = FNTGeneratorCanvas.getCanvasContext(size, size, this.debug);
var bitmaps = [];
for (var key in font.font_styles) {
var table = font.font_styles[key];
// render table in context
FNTGeneratorCanvas.render(table, context, size, fontSize, padding);
var data = context.getImageData(0, 0, size, size);
var image = new BitmapImage2D(size, size, true, 0, true, this._stage);
image.setPixels(new Rectangle(0, 0, size, size), data.data);
bitmaps.push(image);
table.addFNTChannel(image);
}
if (!this.debug) {
FNTGeneratorCanvas.freeCanvasContext(context);
}
else {
this.canvas = context.canvas;
}
return bitmaps;
};
return FNTGeneratorCanvas;
}(FNTGeneratorBase));
export { FNTGeneratorCanvas };