Last active
January 9, 2024 02:59
-
-
Save paulsmith/366eb9efc47cd2d27d5e0690058b22f2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 8x8 monochrome bitmap fonts for rendering | |
* Author: Daniel Hepper <[email protected]> | |
* | |
* License: Public Domain | |
* | |
* Based on: | |
* // Summary: font8x8.h | |
* // 8x8 monochrome bitmap fonts for rendering | |
* // | |
* // Author: | |
* // Marcel Sondaar | |
* // International Business Machines (public domain VGA fonts) | |
* // | |
* // License: | |
* // Public Domain | |
* | |
* Fetched from: http://dimensionalrift.homelinux.net/combuster/mos3/?p=viewsource&file=/modules/gfx/font8_8.asm | |
**/ | |
const font_8x8 = [ | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0000 (nul) | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0001 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0002 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0003 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0004 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0005 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0006 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0007 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0008 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0009 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+000A | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+000B | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+000C | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+000D | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+000E | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+000F | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0010 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0011 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0012 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0013 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0014 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0015 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0016 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0017 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0018 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0019 | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+001A | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+001B | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+001C | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+001D | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+001E | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+001F | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0020 (space) | |
0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00, // U+0021 (!) | |
0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0022 (") | |
0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00, // U+0023 (#) | |
0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00, // U+0024 ($) | |
0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00, // U+0025 (%) | |
0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00, // U+0026 (&) | |
0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0027 (') | |
0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00, // U+0028 (() | |
0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00, // U+0029 ()) | |
0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, // U+002A (*) | |
0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00, // U+002B (+) | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06, // U+002C (,) | |
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, // U+002D (-) | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, // U+002E (.) | |
0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00, // U+002F (/) | |
0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00, // U+0030 (0) | |
0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00, // U+0031 (1) | |
0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00, // U+0032 (2) | |
0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00, // U+0033 (3) | |
0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00, // U+0034 (4) | |
0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00, // U+0035 (5) | |
0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00, // U+0036 (6) | |
0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00, // U+0037 (7) | |
0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00, // U+0038 (8) | |
0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00, // U+0039 (9) | |
0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00, // U+003A (:) | |
0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06, // U+003B (;) | |
0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00, // U+003C (<) | |
0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00, // U+003D (=) | |
0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00, // U+003E (>) | |
0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00, // U+003F (?) | |
0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00, // U+0040 (@) | |
0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00, // U+0041 (A) | |
0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00, // U+0042 (B) | |
0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00, // U+0043 (C) | |
0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00, // U+0044 (D) | |
0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00, // U+0045 (E) | |
0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00, // U+0046 (F) | |
0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00, // U+0047 (G) | |
0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00, // U+0048 (H) | |
0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, // U+0049 (I) | |
0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00, // U+004A (J) | |
0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00, // U+004B (K) | |
0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00, // U+004C (L) | |
0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00, // U+004D (M) | |
0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00, // U+004E (N) | |
0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, // U+004F (O) | |
0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00, // U+0050 (P) | |
0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00, // U+0051 (Q) | |
0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00, // U+0052 (R) | |
0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00, // U+0053 (S) | |
0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, // U+0054 (T) | |
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00, // U+0055 (U) | |
0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00, // U+0056 (V) | |
0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00, // U+0057 (W) | |
0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00, // U+0058 (X) | |
0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00, // U+0059 (Y) | |
0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00, // U+005A (Z) | |
0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00, // U+005B ([) | |
0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, // U+005C (\) | |
0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00, // U+005D (]) | |
0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, // U+005E (^) | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // U+005F (_) | |
0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // U+0060 (`) | |
0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00, // U+0061 (a) | |
0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00, // U+0062 (b) | |
0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00, // U+0063 (c) | |
0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00, // U+0064 (d) | |
0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00, // U+0065 (e) | |
0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00, // U+0066 (f) | |
0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F, // U+0067 (g) | |
0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00, // U+0068 (h) | |
0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, // U+0069 (i) | |
0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, // U+006A (j) | |
0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00, // U+006B (k) | |
0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, // U+006C (l) | |
0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00, // U+006D (m) | |
0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00, // U+006E (n) | |
0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00, // U+006F (o) | |
0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F, // U+0070 (p) | |
0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78, // U+0071 (q) | |
0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00, // U+0072 (r) | |
0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00, // U+0073 (s) | |
0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00, // U+0074 (t) | |
0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00, // U+0075 (u) | |
0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00, // U+0076 (v) | |
0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00, // U+0077 (w) | |
0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00, // U+0078 (x) | |
0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F, // U+0079 (y) | |
0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00, // U+007A (z) | |
0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00, // U+007B ({) | |
0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, // U+007C (|) | |
0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00, // U+007D (}) | |
0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+007E (~) | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U+007F | |
]; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Old school screen graphics and text</title> | |
<style> | |
body { | |
display: flex; | |
align-items: center; | |
height: 100vh; | |
justify-content: center; | |
} | |
canvas { | |
border: 1px solid black; | |
} | |
</style> | |
</head> | |
<body> | |
<main> | |
<canvas width="320" height="200"></canvas> | |
</main> | |
<script src="./font_8x8.js"></script> | |
<script> | |
const COLUMNS = 40; | |
const ROWS = 25; | |
const canvas = document.querySelector('canvas'); | |
const ctx = canvas.getContext('2d'); | |
const FONT_WIDTH = canvas.width / COLUMNS; | |
const FONT_HEIGHT = canvas.height / ROWS; | |
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); | |
const screenMem = imageData.data; | |
const pixelsPerColumn = canvas.width / COLUMNS; | |
const pixelsPerRow = canvas.height / ROWS; | |
// color is a RGBA 32-bit number | |
function clearScreen(color) { | |
for (let i = 0; i < screenMem.length; i += 4) { | |
screenMem[i + 0] = (color >> 24) & 0xff; | |
screenMem[i + 1] = (color >> 16) & 0xff; | |
screenMem[i + 2] = (color >> 8) & 0xff; | |
screenMem[i + 3] = (color >> 0) & 0xff; | |
} | |
ctx.putImageData(imageData, 0, 0); | |
} | |
function drawPixel(x, y, color) { | |
const index = (y * canvas.width + x) * 4; | |
screenMem[index + 0] = (color >> 24) & 0xff; | |
screenMem[index + 1] = (color >> 16) & 0xff; | |
screenMem[index + 2] = (color >> 8) & 0xff; | |
screenMem[index + 3] = (color >> 0) & 0xff; | |
ctx.putImageData(imageData, 0, 0); | |
} | |
// x and y are column and row, not in terms of pixels | |
function drawChar(x, y, ch, color) { | |
const cp = ch.charCodeAt(0); | |
const bitmap = font_8x8.slice(cp * FONT_WIDTH, cp * FONT_WIDTH + FONT_WIDTH); | |
for (let cy = 0; cy < FONT_HEIGHT; cy++) { | |
let bmRow = bitmap[cy]; | |
for (let cx = 0; cx < FONT_WIDTH; cx++) { | |
if ((bmRow & (1 << cx)) > 0) { | |
drawPixel(x * pixelsPerColumn + cx, y * pixelsPerRow + cy, color); | |
} | |
} | |
} | |
} | |
// x and y are column and row, not in terms of pixels | |
function drawString(x, y, s, color) { | |
let col = x; | |
let row = y; | |
for (let i = 0; i < s.length; i++) { | |
let ch = s[i]; | |
if (ch === "\n") { | |
row += 1; | |
col = 0; | |
} else { | |
drawChar(col, row, ch, color); | |
col += 1; | |
if (col >= COLUMNS) { | |
row += 1; | |
col = 0; | |
} | |
} | |
} | |
return [col, row]; | |
} | |
function drawLine(x0, y0, x1, y1, color) { | |
let dx = Math.abs(x1 - x0); | |
let dy = Math.abs(y1 - y0); | |
let sx = (x0 < x1) ? 1 : -1; | |
let sy = (y0 < y1) ? 1 : -1; | |
let err = dx - dy; | |
while (true) { | |
drawPixel(x0, y0, color); | |
if (x0 === x1 && y0 === y1) break; | |
let e2 = 2 * err; | |
if (e2 > -dy) { | |
err -= dy; | |
x0 += sx; | |
} | |
if (e2 < dx) { | |
err += dx; | |
y0 += sy; | |
} | |
} | |
} | |
function rgba(r, g, b, a) { | |
return (r << 24) | (g << 16) | (b << 8) | a; | |
} | |
clearScreen(0x867ADEFF); // C64 bg | |
drawChar(0, 0, 'A', 0xff0000ff); | |
drawChar(1, 0, 'B', 0x0000ffff); | |
drawChar(0, 1, 'C', 0x00ff00ff); | |
drawString(0, 2, "Hello, world!", 0xffffffff); | |
for (let i = 0; i < 10; i++) { | |
drawLine(0, 100, 319, i * 15 + 50, rgba(0xff, 0xff, 25 * i, 0xff)); | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment