mz700-js
Version:
MZ-700 Full JavaScript Emulator
747 lines (737 loc) • 24.2 kB
text/typescript
"use strict";
/* tslint:disable: class-name no-var-requires no-console no-bitwise max-classes-per-file */
const global = Function("return this")();
if(!global.ImageData) {
global.ImageData = require("canvas").ImageData;
}
/**
* MZ-700 Character Generator.
*
* @constructor
*
* @param {number[]} patternBuffer
* character pattern memory.
*
* @param {number} width
* Pixel width of a character.
*
* @param {number} height
* Pixel height of a character.
*/
export default class mz700cg {
_fontTable = null;
_patternBuffer:number[][];
_width:number;
_height:number;
constructor(patternBuffer:number[][], width:number, height:number) {
this._fontTable = null;
this._patternBuffer = patternBuffer;
this._width = width;
this._height = height;
this.createFontTable();
}
/**
* Create font table.
*
* @returns {undefined}
*/
createFontTable():void {
// 256 attributes x 256 character display codes
// attribute: b7 b6 b5 b4 b3 b2 b1 b0
// -- -------- -- --------
// ^ ^ ^ ^
// | | | |
// | | | +--- bgc: background color
// | | +------------ xxx: (not used)
// | +--------------- fgc: foreground color
// +------------------------ atb: bank selector bit
this._fontTable = new Array(256 * 256);
for (let atb = 0; atb < 2; atb++) {
for (let dispCode = 0; dispCode < 256; dispCode++) {
this.initFont(atb, dispCode);
}
}
for (let i = 0; i < 256 * 256; i++) {
if (!this._fontTable[i]) {
console.warn(`mz700cg._fontTable[0x${i.toString(16)}] is null`);
}
}
}
/**
* Initialize specific font in the table.
*
* @param {number} atb
* An attribute bit which select charactoer bank by zero or one.
*
* @param {number} dispCode
* A display code.
*
* @returns {undefined}
*/
initFont(atb:number, dispCode:number):void {
const pattern = this._patternBuffer[atb * 256 + dispCode];
for (let bg = 0; bg < 8; bg++) {
for (let fg = 0; fg < 8; fg++) {
const attr = (atb << 7) | (fg << 4) | bg;
const index0 = mz700cg.tableIndex(attr | 0x00, dispCode);
const index1 = mz700cg.tableIndex(attr | 0x08, dispCode);
const font = new FontImage(pattern,
mz700cg.Colors[fg], mz700cg.Colors[bg],
this._width, this._height);
this._fontTable[index0] = font;
this._fontTable[index1] = font;
}
}
}
/**
* @param {number} atb
* An attribute bit which select charactoer bank by zero or one.
*
* @param {number} dispCode
* A display code.
*
* @param {number} row
* Index of row to be set the pattern.
*
* @param {number} pattern
* Bit pattern to be set at the row.
*
* @returns {undefined}
*/
setPattern(atb:number, dispCode:number, row:number, pattern:number):void{
const cpos = atb * 256 + dispCode;
this._patternBuffer[cpos][row] = pattern;
this.initFont(atb, dispCode);
}
/**
* Get a font image instance.
*
* @param {number} attr
* An attribute 8 bits value including atb and fore and background color.
* [ atb:1 bit ][ fg color index:3 bits ][ bg color index: 3 bits ]
*
* @param {number} dispCode
* A display code.
*
* @returns {FontImage} A font image.
*/
get(attr:number, dispCode:number):FontImage {
return this._fontTable[mz700cg.tableIndex(attr, dispCode)];
}
/**
* Get a index of the font table by attribute and display code
*
* @param {number} attr
* An attribute 8 bits value including atb and fore and background color.
* [ atb:1 bit ][ fg color index:3 bits ][ bg color index: 3 bits ]
*
* @param {number} dispCode
* A display code.
*
* @returns {number} an index of the font table.
*/
static tableIndex(attr:number, dispCode:number):number {
return attr << 8 | dispCode;
}
//
// Color table
// [Black, Blue, Red, Magenta, Green, Cyan, Yellow, White]
//
static Colors:{R:number,G:number,B:number,A:number}[] = [
{R:0x00, G:0x00, B:0x00, A: 0xff},
{R:0x00, G:0x00, B:0xff, A: 0xff},
{R:0xff, G:0x00, B:0x00, A: 0xff},
{R:0xff, G:0x00, B:0xff, A: 0xff},
{R:0x00, G:0xff, B:0x00, A: 0xff},
{R:0x00, G:0xff, B:0xff, A: 0xff},
{R:0xff, G:0xff, B:0x00, A: 0xff},
{R:0xff, G:0xff, B:0xff, A: 0xff},
];
//
// Font bit pattern data for standard MZ-700
//
// An array of array that 512 characters are defined.
//
// [0x000 .. 0x0ff]: Uppercase alphabets, numbers, Japanese Kata-kana
// [0x100 .. 0x1ff]: Lower case alphabets, number, Japanese Hira-gana
//
// These represent a bit pattern in 8 bytes by one character.
//
// ----
//
// This is own data converted from the file 'mz700fon.txt' in
// a MZ700WIN distribution downloaded from
// http://www.retropc.net/mz-memories/mz700/
//
static ROM:number[][] = [
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[]
];
}
/**
* Font image offering CANVAS element.
*
* @param {number[]} pattern
* A pixel bit pattern of font. An 8 length array of 8 bit numbers.
*
* @param {number} fg
* An index of foreground color (0-7).
*
* @param {number} bg
* An index of foreground color (0-7).
*
* @param {number} width
* Pixel width of a character.
*
* @param {number} height
* Pixel height of a character.
*
* @constructor
*/
class FontImage {
getImageData:() => ImageData;
constructor(
pattern:number[],
fg:{R:number,G:number,B:number,A:number},
bg:{R:number,G:number,B:number,A:number},
width:number,
height:number)
{
this.getImageData = () => {
const buf:number[] = Array(width * 4 * height).fill(0);
let index = 0;
for(let row = 0; row < 8; row++) {
const bits = pattern[row];
for(let col = 0; col < 8; col++) {
if((bits & (0x80 >> col)) !== 0) {
buf[index + 0] = fg.R;
buf[index + 1] = fg.G;
buf[index + 2] = fg.B;
buf[index + 3] = fg.A;
} else {
buf[index + 0] = bg.R;
buf[index + 1] = bg.G;
buf[index + 2] = bg.B;
buf[index + 3] = bg.A;
}
index += 4;
}
}
const array = Uint8ClampedArray.from(buf);
const imageData = new ImageData(array, width, height);
this.getImageData = () => imageData;
return this.getImageData();
};
}
}
module.exports = mz700cg;