mirror of
https://github.com/whscullin/apple1js.git
synced 2024-12-27 04:29:29 +00:00
Convert canvas to Typescript
This commit is contained in:
parent
afe03b4057
commit
f611c09428
221
js/canvas1.js
221
js/canvas1.js
@ -1,221 +0,0 @@
|
|||||||
/* Copyright 2010-2019Will Scullin <scullin@scullinsteel.com>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
||||||
* documentation for any purpose is hereby granted without fee, provided that
|
|
||||||
* the above copyright notice appear in all copies and that both that
|
|
||||||
* copyright notice and this permission notice appear in supporting
|
|
||||||
* documentation. No representations are made about the suitability of this
|
|
||||||
* software for any purpose. It is provided "as is" without express or
|
|
||||||
* implied warranty.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { charset } from './roms/apple1char';
|
|
||||||
|
|
||||||
/*
|
|
||||||
0: A9 9 AA 20 EF FF E8 8A 4C 2 0
|
|
||||||
0R
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Text Page Drawing
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function TextPage()
|
|
||||||
{
|
|
||||||
var _page;
|
|
||||||
var _context;
|
|
||||||
|
|
||||||
var _buffer = [];
|
|
||||||
var _greenMode = false;
|
|
||||||
var _scanlines = false;
|
|
||||||
|
|
||||||
var _black = [0x00,0x00,0x00];
|
|
||||||
var _white = [0xee,0xff,0xff];
|
|
||||||
var _green = [0x00,0xff,0x80];
|
|
||||||
var _blinking = 0;
|
|
||||||
|
|
||||||
var _row = 0;
|
|
||||||
var _col = 0;
|
|
||||||
var _dirty = false;
|
|
||||||
|
|
||||||
function _init() {
|
|
||||||
_buffer = [];
|
|
||||||
for (var row = 0; row < 24; row++) {
|
|
||||||
_buffer[row] = [];
|
|
||||||
for (var col = 0; col < 40; col++) {
|
|
||||||
_buffer[row][col] = col % 2 ? 0x00 : 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
_init();
|
|
||||||
|
|
||||||
return {
|
|
||||||
init: function() {
|
|
||||||
var self = this;
|
|
||||||
window.setInterval(function() {
|
|
||||||
_blinking = (_blinking + 1) % 3;
|
|
||||||
self._blink();
|
|
||||||
_dirty = true;
|
|
||||||
}, 333);
|
|
||||||
},
|
|
||||||
|
|
||||||
write: function(val) {
|
|
||||||
var col;
|
|
||||||
val &= 0x7f;
|
|
||||||
|
|
||||||
if (this.transcript) {
|
|
||||||
if (val == 0xd) {
|
|
||||||
this.transcript += '\n';
|
|
||||||
} else if (val >= 0x20) {
|
|
||||||
if (val >= 0x60) {
|
|
||||||
val &= 0x5f;
|
|
||||||
}
|
|
||||||
this.transcript += String.fromCharCode(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val == 0x0d) {
|
|
||||||
for (col = _col; col < 40; col++) {
|
|
||||||
_buffer[_row][col] = 0x20;
|
|
||||||
}
|
|
||||||
_col = 0;
|
|
||||||
_row++;
|
|
||||||
} else {
|
|
||||||
_buffer[_row][_col] = val;
|
|
||||||
_col++;
|
|
||||||
if (_col > 39) {
|
|
||||||
_col = 0;
|
|
||||||
_row++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_row > 23) {
|
|
||||||
_row = 23;
|
|
||||||
_buffer.shift();
|
|
||||||
_buffer.push([]);
|
|
||||||
for (col = 0; col < 40; col++) {
|
|
||||||
_buffer[_row][col] = 0x20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_buffer[_row][_col] = 0x00;
|
|
||||||
this.refresh();
|
|
||||||
},
|
|
||||||
writeAt: function(row, col, val) {
|
|
||||||
_buffer[row][col] = val;
|
|
||||||
var data = _page.data, fore, back, color;
|
|
||||||
var off = (col * 14 + row * 560 * 8 * 2) * 4;
|
|
||||||
|
|
||||||
fore = _greenMode ? _green : _white;
|
|
||||||
back = _black;
|
|
||||||
var char = 0;
|
|
||||||
|
|
||||||
if (!val) {
|
|
||||||
if (_blinking) {
|
|
||||||
fore = _black;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
char = val & 0x1f;
|
|
||||||
char |= val & 0x40 ? 0 : 0x20;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var jdx = 0; jdx < 8; jdx++) {
|
|
||||||
var b = charset[char * 8 + jdx];
|
|
||||||
for (var idx = 0; idx < 7; idx += 1) {
|
|
||||||
b <<= 1;
|
|
||||||
color = (b & 0x80) ? fore : back;
|
|
||||||
var c0 = color[0], c1 = color[1], c2 = color[2];
|
|
||||||
data[off + 0] = data[off + 4] = c0;
|
|
||||||
data[off + 1] = data[off + 5] = c1;
|
|
||||||
data[off + 2] = data[off + 6] = c2;
|
|
||||||
if (!_scanlines) {
|
|
||||||
data[off + 560 * 4] = data[off + 560 * 4 + 4] = c0;
|
|
||||||
data[off + 560 * 4 + 1] = data[off + 560 * 4 + 5] = c1;
|
|
||||||
data[off + 560 * 4 + 2] = data[off + 560 * 4 + 6] = c2;
|
|
||||||
} else {
|
|
||||||
data[off + 560 * 4] = data[off + 560 * 4 + 4] = c0 >> 1;
|
|
||||||
data[off + 560 * 4 + 1] = data[off + 560 * 4 + 5] = c1 >> 1;
|
|
||||||
data[off + 560 * 4 + 2] = data[off + 560 * 4 + 6] = c2 >> 1;
|
|
||||||
}
|
|
||||||
off += 8;
|
|
||||||
}
|
|
||||||
off += 546 * 4 + 560 * 4;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_blink: function() {
|
|
||||||
for (var row = 0; row < 24; row++) {
|
|
||||||
for (var col = 0; col < 40; col++) {
|
|
||||||
var val = _buffer[row][col];
|
|
||||||
if (!val) {
|
|
||||||
this.writeAt(row, col, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_dirty = true;
|
|
||||||
},
|
|
||||||
refresh: function() {
|
|
||||||
for (var row = 0; row < 24; row++) {
|
|
||||||
for (var col = 0; col < 40; col++) {
|
|
||||||
this.writeAt(row, col, _buffer[row][col]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_dirty = true;
|
|
||||||
},
|
|
||||||
green: function(on) {
|
|
||||||
_greenMode = on;
|
|
||||||
this.refresh();
|
|
||||||
},
|
|
||||||
scanlines: function(on) {
|
|
||||||
_scanlines = on;
|
|
||||||
this.refresh();
|
|
||||||
},
|
|
||||||
blit: function() {
|
|
||||||
if (_dirty) {
|
|
||||||
_context.putImageData(_page, 0, 0, 0, 0, 7 * 40 * 2, 8 * 24 * 2);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setContext: function(context) {
|
|
||||||
_context = context;
|
|
||||||
_page = context.createImageData(560, 384);
|
|
||||||
for (var idx = 0; idx < 560 * 384 * 4; idx++) {
|
|
||||||
_page.data[idx] = 0xff;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getText: function() {
|
|
||||||
function mapCharCode(charCode) {
|
|
||||||
charCode &= 0x7F;
|
|
||||||
if (charCode < 0x20) {
|
|
||||||
charCode += 0x40;
|
|
||||||
}
|
|
||||||
if (charCode >= 0x60) {
|
|
||||||
charCode -= 0x40;
|
|
||||||
}
|
|
||||||
return charCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
var buffer = '', line, charCode;
|
|
||||||
var row, col;
|
|
||||||
for (row = 0; row < 24; row++) {
|
|
||||||
line = '';
|
|
||||||
for (col = 0; col < 40; col++) {
|
|
||||||
charCode = mapCharCode(_buffer[row][col]);
|
|
||||||
line += String.fromCharCode(charCode);
|
|
||||||
}
|
|
||||||
line = line.trimRight();
|
|
||||||
buffer += line + '\n';
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
},
|
|
||||||
clear: function canvas_clearScreen() {
|
|
||||||
for (var row = 0; row < 24; row++) {
|
|
||||||
for (var col = 0; col < 40; col++) {
|
|
||||||
_buffer[row][col] = 0x20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_col = 0;
|
|
||||||
_row = 0;
|
|
||||||
this.refresh();
|
|
||||||
},
|
|
||||||
transcript: ''
|
|
||||||
};
|
|
||||||
}
|
|
232
js/canvas1.ts
Normal file
232
js/canvas1.ts
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
/* Copyright 2010-2023 Will Scullin <scullin@scullinsteel.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||||
|
* documentation for any purpose is hereby granted without fee, provided that
|
||||||
|
* the above copyright notice appear in all copies and that both that
|
||||||
|
* copyright notice and this permission notice appear in supporting
|
||||||
|
* documentation. No representations are made about the suitability of this
|
||||||
|
* software for any purpose. It is provided "as is" without express or
|
||||||
|
* implied warranty.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { charset } from "./roms/apple1char";
|
||||||
|
import type { byte } from "./types";
|
||||||
|
|
||||||
|
/*
|
||||||
|
0: A9 9 AA 20 EF FF E8 8A 4C 2 0
|
||||||
|
0R
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Text Page Drawing
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class TextPage {
|
||||||
|
_page: ImageData;
|
||||||
|
_context: CanvasRenderingContext2D;
|
||||||
|
|
||||||
|
_buffer: byte[][] = [];
|
||||||
|
_greenMode = false;
|
||||||
|
_scanlines = false;
|
||||||
|
|
||||||
|
_black = [0x00, 0x00, 0x00];
|
||||||
|
_white = [0xee, 0xff, 0xff];
|
||||||
|
_green = [0x00, 0xff, 0x80];
|
||||||
|
_blinking = 0;
|
||||||
|
|
||||||
|
_row = 0;
|
||||||
|
_col = 0;
|
||||||
|
_dirty = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._buffer = [];
|
||||||
|
for (var row = 0; row < 24; row++) {
|
||||||
|
this._buffer[row] = [];
|
||||||
|
for (var col = 0; col < 40; col++) {
|
||||||
|
this._buffer[row][col] = col % 2 ? 0x00 : 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
window.setInterval(() => {
|
||||||
|
this._blinking = (this._blinking + 1) % 3;
|
||||||
|
this._blink();
|
||||||
|
this._dirty = true;
|
||||||
|
}, 333);
|
||||||
|
}
|
||||||
|
|
||||||
|
write(val: byte): void {
|
||||||
|
var col;
|
||||||
|
val &= 0x7f;
|
||||||
|
|
||||||
|
if (this.transcript) {
|
||||||
|
if (val == 0xd) {
|
||||||
|
this.transcript += "\n";
|
||||||
|
} else if (val >= 0x20) {
|
||||||
|
if (val >= 0x60) {
|
||||||
|
val &= 0x5f;
|
||||||
|
}
|
||||||
|
this.transcript += String.fromCharCode(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val == 0x0d) {
|
||||||
|
for (col = this._col; col < 40; col++) {
|
||||||
|
this._buffer[this._row][col] = 0x20;
|
||||||
|
}
|
||||||
|
this._col = 0;
|
||||||
|
this._row++;
|
||||||
|
} else {
|
||||||
|
this._buffer[this._row][this._col] = val;
|
||||||
|
this._col++;
|
||||||
|
if (this._col > 39) {
|
||||||
|
this._col = 0;
|
||||||
|
this._row++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this._row > 23) {
|
||||||
|
this._row = 23;
|
||||||
|
this._buffer.shift();
|
||||||
|
this._buffer.push([]);
|
||||||
|
for (col = 0; col < 40; col++) {
|
||||||
|
this._buffer[this._row][col] = 0x20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._buffer[this._row][this._col] = 0x00;
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
writeAt(row: byte, col: byte, val: byte): void {
|
||||||
|
this._buffer[row][col] = val;
|
||||||
|
var data = this._page.data,
|
||||||
|
fore,
|
||||||
|
back,
|
||||||
|
color;
|
||||||
|
var off = (col * 14 + row * 560 * 8 * 2) * 4;
|
||||||
|
|
||||||
|
fore = this._greenMode ? this._green : this._white;
|
||||||
|
back = this._black;
|
||||||
|
var char = 0;
|
||||||
|
|
||||||
|
if (!val) {
|
||||||
|
if (this._blinking) {
|
||||||
|
fore = this._black;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
char = val & 0x1f;
|
||||||
|
char |= val & 0x40 ? 0 : 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var jdx = 0; jdx < 8; jdx++) {
|
||||||
|
var b = charset[char * 8 + jdx];
|
||||||
|
for (var idx = 0; idx < 7; idx += 1) {
|
||||||
|
b <<= 1;
|
||||||
|
color = b & 0x80 ? fore : back;
|
||||||
|
var c0 = color[0],
|
||||||
|
c1 = color[1],
|
||||||
|
c2 = color[2];
|
||||||
|
data[off + 0] = data[off + 4] = c0;
|
||||||
|
data[off + 1] = data[off + 5] = c1;
|
||||||
|
data[off + 2] = data[off + 6] = c2;
|
||||||
|
if (!this._scanlines) {
|
||||||
|
data[off + 560 * 4] = data[off + 560 * 4 + 4] = c0;
|
||||||
|
data[off + 560 * 4 + 1] = data[off + 560 * 4 + 5] = c1;
|
||||||
|
data[off + 560 * 4 + 2] = data[off + 560 * 4 + 6] = c2;
|
||||||
|
} else {
|
||||||
|
data[off + 560 * 4] = data[off + 560 * 4 + 4] = c0 >> 1;
|
||||||
|
data[off + 560 * 4 + 1] = data[off + 560 * 4 + 5] = c1 >> 1;
|
||||||
|
data[off + 560 * 4 + 2] = data[off + 560 * 4 + 6] = c2 >> 1;
|
||||||
|
}
|
||||||
|
off += 8;
|
||||||
|
}
|
||||||
|
off += 546 * 4 + 560 * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_blink() {
|
||||||
|
for (var row = 0; row < 24; row++) {
|
||||||
|
for (var col = 0; col < 40; col++) {
|
||||||
|
var val = this._buffer[row][col];
|
||||||
|
if (!val) {
|
||||||
|
this.writeAt(row, col, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._dirty = true;
|
||||||
|
}
|
||||||
|
refresh() {
|
||||||
|
for (var row = 0; row < 24; row++) {
|
||||||
|
for (var col = 0; col < 40; col++) {
|
||||||
|
this.writeAt(row, col, this._buffer[row][col]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._dirty = true;
|
||||||
|
}
|
||||||
|
green(on: boolean) {
|
||||||
|
this._greenMode = on;
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
scanlines(on: boolean) {
|
||||||
|
this._scanlines = on;
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
blit() {
|
||||||
|
if (this._dirty) {
|
||||||
|
this._context.putImageData(
|
||||||
|
this._page,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
7 * 40 * 2,
|
||||||
|
8 * 24 * 2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setContext(context: CanvasRenderingContext2D) {
|
||||||
|
this._context = context;
|
||||||
|
this._page = context.createImageData(560, 384);
|
||||||
|
for (var idx = 0; idx < 560 * 384 * 4; idx++) {
|
||||||
|
this._page.data[idx] = 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getText() {
|
||||||
|
function mapCharCode(charCode: byte) {
|
||||||
|
charCode &= 0x7f;
|
||||||
|
if (charCode < 0x20) {
|
||||||
|
charCode += 0x40;
|
||||||
|
}
|
||||||
|
if (charCode >= 0x60) {
|
||||||
|
charCode -= 0x40;
|
||||||
|
}
|
||||||
|
return charCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
var buffer = "",
|
||||||
|
line,
|
||||||
|
charCode;
|
||||||
|
var row, col;
|
||||||
|
for (row = 0; row < 24; row++) {
|
||||||
|
line = "";
|
||||||
|
for (col = 0; col < 40; col++) {
|
||||||
|
charCode = mapCharCode(this._buffer[row][col]);
|
||||||
|
line += String.fromCharCode(charCode);
|
||||||
|
}
|
||||||
|
line = line.trimRight();
|
||||||
|
buffer += line + "\n";
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
clear() {
|
||||||
|
for (var row = 0; row < 24; row++) {
|
||||||
|
for (var col = 0; col < 40; col++) {
|
||||||
|
this._buffer[row][col] = 0x20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._col = 0;
|
||||||
|
this._row = 0;
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
transcript = "";
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user