@micahdb/tscon 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +44 -2
- package/dist/canvas.d.ts +147 -0
- package/dist/canvas.js +369 -0
- package/dist/colour.d.ts +56 -0
- package/dist/colour.js +77 -0
- package/dist/cp437.d.ts +48 -0
- package/dist/cp437.js +124 -0
- package/dist/glyphs.d.ts +222 -0
- package/dist/glyphs.js +449 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +9 -0
- package/dist/math.d.ts +214 -0
- package/dist/math.js +499 -0
- package/dist/moderndos.d.ts +1 -0
- package/dist/moderndos.js +322 -0
- package/dist/program.d.ts +72 -0
- package/dist/program.js +127 -0
- package/dist/rect.d.ts +26 -0
- package/dist/rect.js +1 -0
- package/dist/renderer.d.ts +59 -0
- package/dist/renderer.js +172 -0
- package/dist/shaders.d.ts +5 -0
- package/dist/shaders.js +470 -0
- package/dist/terminal.d.ts +92 -0
- package/dist/terminal.js +275 -0
- package/dist/texture.d.ts +66 -0
- package/dist/texture.js +119 -0
- package/package.json +44 -5
package/dist/glyphs.js
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
import { Colour } from "./colour.js";
|
|
2
|
+
import { charCodeInCp437 } from "./cp437.js";
|
|
3
|
+
/**
|
|
4
|
+
* Number of columns a tab advances the cursor by.
|
|
5
|
+
*
|
|
6
|
+
* Tabs in text processed by {@link textToLines} and {@link textGlyphs}
|
|
7
|
+
* advance the column position to the next multiple of this width.
|
|
8
|
+
*/
|
|
9
|
+
export const TAB_WIDTH = 8;
|
|
10
|
+
function finalSpaceIdx(text, start) {
|
|
11
|
+
// skip remaining white space
|
|
12
|
+
while (start < text.length &&
|
|
13
|
+
(text[start] === " " || text[start] === "\t")) {
|
|
14
|
+
start++;
|
|
15
|
+
}
|
|
16
|
+
// just incase there was a newline
|
|
17
|
+
if (start < text.length && text[start] === "\n") {
|
|
18
|
+
start++;
|
|
19
|
+
}
|
|
20
|
+
// reached the end of text
|
|
21
|
+
if (start >= text.length) {
|
|
22
|
+
return -1;
|
|
23
|
+
}
|
|
24
|
+
// return index of last space
|
|
25
|
+
return start - 1;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Layout `text` into lines no wider than `cols` columns.
|
|
29
|
+
*
|
|
30
|
+
* This is the line-breaking pass used by {@link textGlyphs}. It interprets
|
|
31
|
+
* the tscon text escape sequences so they are not counted against the
|
|
32
|
+
* column budget, and returns the raw visible content of each line as a
|
|
33
|
+
* string (still containing the escape codes for later processing).
|
|
34
|
+
*
|
|
35
|
+
* The following escape sequences are recognised and treated as taking up
|
|
36
|
+
* zero columns:
|
|
37
|
+
*
|
|
38
|
+
* - `\\` -- a literal backslash (collapses to one displayed char)
|
|
39
|
+
* - `\aX` and `\aX{options}` -- an anchor in group `X` (0-9), with an
|
|
40
|
+
* optional `{...}` options string
|
|
41
|
+
* - `\fX` / `\FX` -- set foreground to colour `X` (dark / bright)
|
|
42
|
+
* - `\bX` / `\BX` -- set background to colour `X` (dark / bright)
|
|
43
|
+
*
|
|
44
|
+
* Newlines always break the line. A backslash immediately followed by a
|
|
45
|
+
* newline is a line continuation: the two characters are removed and the
|
|
46
|
+
* following content joins the current line. Tabs advance to the next
|
|
47
|
+
* multiple of {@link TAB_WIDTH}.
|
|
48
|
+
*
|
|
49
|
+
* When `wrap` is `true`, lines longer than `cols` are wrapped at the most
|
|
50
|
+
* recent space (or broken mid-word if a single word fills a whole line).
|
|
51
|
+
* When `wrap` is `false`, lines longer than `cols` are truncated at the
|
|
52
|
+
* end of the line and the rest of that logical line is discarded.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* import { textToLines } from "@micahdb/tscon";
|
|
57
|
+
*
|
|
58
|
+
* textToLines("hello world", 80, true); // ["hello world"]
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @param text The text to lay out, possibly with escape sequences.
|
|
62
|
+
* @param cols Maximum number of visible columns per line. If `<= 0`, an
|
|
63
|
+
* empty array is returned.
|
|
64
|
+
* @param wrap Whether to word-wrap long lines (`true`) or truncate them
|
|
65
|
+
* (`false`).
|
|
66
|
+
* @returns The laid-out visible lines, with escape sequences preserved.
|
|
67
|
+
*/
|
|
68
|
+
export function textToLines(text, cols, wrap) {
|
|
69
|
+
const lines = [];
|
|
70
|
+
if (cols <= 0) {
|
|
71
|
+
return lines; // empty
|
|
72
|
+
}
|
|
73
|
+
let start = 0;
|
|
74
|
+
let running_cols = 0;
|
|
75
|
+
let last_space = -1;
|
|
76
|
+
// "text that breaks \
|
|
77
|
+
// a line into two"
|
|
78
|
+
// ->
|
|
79
|
+
// "text that breaks a line into two"
|
|
80
|
+
text = text.replaceAll("\\\n", "");
|
|
81
|
+
for (let i = 0; i < text.length; i++) {
|
|
82
|
+
const c = text[i];
|
|
83
|
+
let escape = c === "\\";
|
|
84
|
+
// single back slash
|
|
85
|
+
if (escape && i + 1 < text.length && text[i + 1] === "\\") {
|
|
86
|
+
i++; // skip one character
|
|
87
|
+
escape = false;
|
|
88
|
+
}
|
|
89
|
+
// anchor escape sequence
|
|
90
|
+
// \aX : anchor in group X, no options
|
|
91
|
+
// \aX{options string} : anchor in group X, with options
|
|
92
|
+
if (escape && i + 2 < text.length && text[i + 1] === "a" &&
|
|
93
|
+
!isNaN(Number(text[i + 2]))) {
|
|
94
|
+
let skip_chars = 2;
|
|
95
|
+
// options string
|
|
96
|
+
if (i + 3 < text.length && text[i + 3] === "{") {
|
|
97
|
+
const closing_brace = text.indexOf("}", i + 3);
|
|
98
|
+
if (closing_brace > i + 3) {
|
|
99
|
+
// skip right until the closing brace
|
|
100
|
+
skip_chars = closing_brace - i;
|
|
101
|
+
} // else, no matching closing brace, ignore "{"
|
|
102
|
+
}
|
|
103
|
+
i += skip_chars;
|
|
104
|
+
continue; // i++
|
|
105
|
+
}
|
|
106
|
+
// colours escape sequence
|
|
107
|
+
// \fX : set foreground to X, dark
|
|
108
|
+
// \FX : set foreground to X, bright
|
|
109
|
+
// \bX : set background to X, dark
|
|
110
|
+
// \BX : set background to X, bright
|
|
111
|
+
if (escape &&
|
|
112
|
+
i + 2 < text.length &&
|
|
113
|
+
"fFbB".includes(text[i + 1]) &&
|
|
114
|
+
!isNaN(Number(text[i + 2]))) {
|
|
115
|
+
// skip the 3 char combo
|
|
116
|
+
i += 2;
|
|
117
|
+
continue; // i++
|
|
118
|
+
}
|
|
119
|
+
// newline
|
|
120
|
+
if (c === "\n") {
|
|
121
|
+
lines.push(text.slice(start, i).trimEnd());
|
|
122
|
+
start = i + 1;
|
|
123
|
+
running_cols = 0;
|
|
124
|
+
last_space = -1;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
// tab
|
|
128
|
+
if (c === "\t") {
|
|
129
|
+
const cols_to_tab = TAB_WIDTH -
|
|
130
|
+
(running_cols % TAB_WIDTH);
|
|
131
|
+
if (running_cols + cols_to_tab > cols) {
|
|
132
|
+
lines.push(text.slice(start, i).trimEnd());
|
|
133
|
+
if (!wrap) {
|
|
134
|
+
i = text.indexOf("\n", i + 1);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
i = finalSpaceIdx(text, i + 1);
|
|
138
|
+
}
|
|
139
|
+
// end of text
|
|
140
|
+
if (i < 0) {
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
start = i + 1;
|
|
144
|
+
running_cols = 0;
|
|
145
|
+
last_space = -1;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
running_cols += cols_to_tab;
|
|
149
|
+
last_space = i;
|
|
150
|
+
}
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
// space
|
|
154
|
+
if (c === " ") {
|
|
155
|
+
last_space = i;
|
|
156
|
+
}
|
|
157
|
+
// exceeding available width
|
|
158
|
+
if (running_cols + 1 > cols) {
|
|
159
|
+
// skip rest of line if not wrapping
|
|
160
|
+
if (!wrap) {
|
|
161
|
+
lines.push(text.slice(start, i).trimEnd());
|
|
162
|
+
i = text.indexOf("\n", i + 1);
|
|
163
|
+
// end of text
|
|
164
|
+
if (i < 0) {
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
start = i + 1;
|
|
168
|
+
running_cols = 0;
|
|
169
|
+
last_space = -1;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
// this is a continuous word that filled the whole line
|
|
173
|
+
if (last_space < 0) {
|
|
174
|
+
lines.push(text.slice(start, i).trimEnd());
|
|
175
|
+
start = i;
|
|
176
|
+
running_cols = 0;
|
|
177
|
+
i--;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
// otherwise, will break at last space
|
|
181
|
+
lines.push(text.slice(start, last_space).trimEnd());
|
|
182
|
+
i = finalSpaceIdx(text, last_space);
|
|
183
|
+
start = i + 1;
|
|
184
|
+
running_cols = 0;
|
|
185
|
+
last_space = -1;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
running_cols++;
|
|
189
|
+
}
|
|
190
|
+
// push last line if it isn't a space
|
|
191
|
+
if (start < text.length) {
|
|
192
|
+
lines.push(text.slice(start));
|
|
193
|
+
}
|
|
194
|
+
return lines;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Render `text` into a grid of terminal glyphs `cols` wide.
|
|
198
|
+
*
|
|
199
|
+
* This is the primary text-rendering entry point. It runs {@link textToLines}
|
|
200
|
+
* to lay the text out, then encodes each visible character as a packed
|
|
201
|
+
* 16-bit glyph (CP437 code + colour pair) into the resulting {@link Glyphs}.
|
|
202
|
+
*
|
|
203
|
+
* The escape sequences understood by the text format are interpreted here:
|
|
204
|
+
*
|
|
205
|
+
* - `\\` -- emits a single literal backslash
|
|
206
|
+
* - `\aX` / `\aX{options}` -- records an anchor in group `X` (0-9) at the
|
|
207
|
+
* current position, with optional `options` string (see {@link Anchor})
|
|
208
|
+
* - `\fX` / `\FX` -- set foreground colour to `X` (dark / bright)
|
|
209
|
+
* - `\bX` / `\BX` -- set background colour to `X` (dark / bright)
|
|
210
|
+
*
|
|
211
|
+
* Colours `X` are clamped to 0-7; the `F`/`B` (capital) variants add 8 to
|
|
212
|
+
* select the bright half of the palette. The initial foreground is
|
|
213
|
+
* {@link Colour.WHITE} and the initial background is {@link Colour.BLACK}.
|
|
214
|
+
*
|
|
215
|
+
* Tabs advance the column to the next multiple of {@link TAB_WIDTH} but
|
|
216
|
+
* do not emit anything. Characters outside the CP437 range map to 0
|
|
217
|
+
* (blank), and trailing space on the default colour is left as zero so it
|
|
218
|
+
* does not overwrite whatever is already on the console.
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```ts
|
|
222
|
+
* import { textGlyphs } from "@micahdb/tscon";
|
|
223
|
+
*
|
|
224
|
+
* // bright-blue on black "Link", 4 cols wide
|
|
225
|
+
* const g = textGlyphs("\\F4\\b0Link", 4, false);
|
|
226
|
+
* ```
|
|
227
|
+
*
|
|
228
|
+
* @param text The text to render, with escape sequences.
|
|
229
|
+
* @param cols Width of the grid in cells. If `<= 0`, an empty grid is
|
|
230
|
+
* returned.
|
|
231
|
+
* @param wrap Whether to word-wrap long lines (`true`) or truncate them
|
|
232
|
+
* (`false`).
|
|
233
|
+
* @returns The rendered glyph grid, with anchors populated.
|
|
234
|
+
*/
|
|
235
|
+
export function textGlyphs(text, cols, wrap) {
|
|
236
|
+
if (cols <= 0) {
|
|
237
|
+
return {
|
|
238
|
+
data: new Uint16Array(),
|
|
239
|
+
rows: 0,
|
|
240
|
+
cols: 0,
|
|
241
|
+
anchors: {},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const lines = textToLines(text, cols, wrap);
|
|
245
|
+
const rows = lines.length;
|
|
246
|
+
if (rows === 0) {
|
|
247
|
+
return {
|
|
248
|
+
data: new Uint16Array(),
|
|
249
|
+
rows: 0,
|
|
250
|
+
cols: 0,
|
|
251
|
+
anchors: {},
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
const glyphs = {
|
|
255
|
+
data: new Uint16Array(rows * cols),
|
|
256
|
+
rows,
|
|
257
|
+
cols: cols,
|
|
258
|
+
anchors: {},
|
|
259
|
+
};
|
|
260
|
+
let fg = Colour.WHITE;
|
|
261
|
+
let bg = Colour.BLACK;
|
|
262
|
+
for (let row = 0; row < rows; row++) {
|
|
263
|
+
const line = lines[row];
|
|
264
|
+
let col = 0;
|
|
265
|
+
for (let i = 0; i < line.length; i++) {
|
|
266
|
+
const c = line[i];
|
|
267
|
+
let escape = c === "\\";
|
|
268
|
+
// \\ : display a single back slash
|
|
269
|
+
if (escape && i + 1 < line.length &&
|
|
270
|
+
line[i + 1] === "\\") {
|
|
271
|
+
i++; // this will be displayed as a single character
|
|
272
|
+
escape = false; // skip below checks
|
|
273
|
+
}
|
|
274
|
+
// anchor escape sequence
|
|
275
|
+
// \aX : anchor in group X, no options
|
|
276
|
+
// \aX{options string} : anchor in group X, with options
|
|
277
|
+
if (escape && i + 2 < line.length &&
|
|
278
|
+
line[i + 1] === "a" &&
|
|
279
|
+
!isNaN(Number(line[i + 2]))) {
|
|
280
|
+
const num = Math.max(Math.min(Number(line[i + 2]), 9), 0); // 0..9
|
|
281
|
+
let skip_chars = 2;
|
|
282
|
+
if (glyphs.anchors[num] === undefined) {
|
|
283
|
+
glyphs.anchors[num] = [];
|
|
284
|
+
}
|
|
285
|
+
const anchors = glyphs.anchors[num];
|
|
286
|
+
let options = null;
|
|
287
|
+
// options string
|
|
288
|
+
if (i + 4 <= line.length &&
|
|
289
|
+
line[i + 3] === "{") {
|
|
290
|
+
const closing_brace = line.indexOf("}", i + 3);
|
|
291
|
+
if (closing_brace > i + 3) {
|
|
292
|
+
// \aX{options} <- take text from inner braces
|
|
293
|
+
options = line.slice(i + 4, closing_brace);
|
|
294
|
+
// skip right until the closing brace
|
|
295
|
+
skip_chars = closing_brace - i;
|
|
296
|
+
} // else, options = null
|
|
297
|
+
}
|
|
298
|
+
// empty string should be null
|
|
299
|
+
if (options === "") {
|
|
300
|
+
options = null;
|
|
301
|
+
}
|
|
302
|
+
anchors.push({ options, row, col });
|
|
303
|
+
i += skip_chars;
|
|
304
|
+
continue; // i++
|
|
305
|
+
}
|
|
306
|
+
// colour escape sequence:
|
|
307
|
+
// \fX : foreground X, dark
|
|
308
|
+
// \FX : foreground X, bright
|
|
309
|
+
// \bX : background X, dark
|
|
310
|
+
// \BX : background X, bright
|
|
311
|
+
if (escape &&
|
|
312
|
+
i + 2 < line.length &&
|
|
313
|
+
"fFbB".includes(line[i + 1]) &&
|
|
314
|
+
!isNaN(Number(line[i + 2]))) {
|
|
315
|
+
const num = Math.max(Math.min(Number(line[i + 2]), 7), 0); // 0..7
|
|
316
|
+
switch (line[i + 1]) {
|
|
317
|
+
case "f":
|
|
318
|
+
fg = num;
|
|
319
|
+
break;
|
|
320
|
+
case "F":
|
|
321
|
+
fg = num + 8;
|
|
322
|
+
break;
|
|
323
|
+
case "b":
|
|
324
|
+
bg = num;
|
|
325
|
+
break;
|
|
326
|
+
case "B":
|
|
327
|
+
bg = num + 8;
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
i += 2;
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
// tab
|
|
334
|
+
if (c === "\t") {
|
|
335
|
+
const tab_chars = TAB_WIDTH - (col % TAB_WIDTH);
|
|
336
|
+
col += tab_chars;
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
if (col + 1 > cols) {
|
|
340
|
+
// in theory, shouldn't happen; but be safe if it does
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
const char_code = charCodeInCp437(line.codePointAt(i) ?? " ".codePointAt(0));
|
|
344
|
+
const colour_byte = ((fg & 0b1111) << 4) |
|
|
345
|
+
(bg & 0b1111);
|
|
346
|
+
if (char_code !== " ".codePointAt(0) ||
|
|
347
|
+
colour_byte !== 0) {
|
|
348
|
+
const data_idx = row * cols + col;
|
|
349
|
+
const glyph = (colour_byte << 8) |
|
|
350
|
+
(char_code & 0xff);
|
|
351
|
+
glyphs.data[data_idx] = glyph;
|
|
352
|
+
}
|
|
353
|
+
col++;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return glyphs;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* How each cell of a {@link TexGlyphs} grid samples its source texture.
|
|
360
|
+
*
|
|
361
|
+
* The value is packed into each texture-glyph and read by the renderer's
|
|
362
|
+
* vertex shader to decide, per cell, how to turn the source texture into a
|
|
363
|
+
* drawn glyph.
|
|
364
|
+
*
|
|
365
|
+
* - `SAMPLE` -- render the source texture directly. Each cell is given UV
|
|
366
|
+
* coordinates into the texture, so the full rendered region
|
|
367
|
+
* simply shows the source texture as-is.
|
|
368
|
+
* - `GLYPHS` -- sample the texture and convert it to a glyph: the
|
|
369
|
+
* character is chosen by the sample's brightness and the
|
|
370
|
+
* colour by dithering (Bayer matrix + nearest palette hue).
|
|
371
|
+
* The background stays black. Preferred when you want the
|
|
372
|
+
* texture rendered as coloured characters without it being
|
|
373
|
+
* too bright or jarring.
|
|
374
|
+
* - `BG_GLYPHS` -- like `GLYPHS`, but also sets the background colour, so
|
|
375
|
+
* the full glyph (foreground + background) carries more of
|
|
376
|
+
* the sample's colour. This is noticeably brighter and more
|
|
377
|
+
* visually accurate; use it when no text is drawn on top of
|
|
378
|
+
* the rendered texture.
|
|
379
|
+
* - `MIX` -- alternate `SAMPLE`/`GLYPHS` in a checkerboard pattern.
|
|
380
|
+
* - `ROWS` -- alternate `SAMPLE`/`GLYPHS` by row.
|
|
381
|
+
* - `COLS` -- alternate `SAMPLE`/`GLYPHS` by column.
|
|
382
|
+
*/
|
|
383
|
+
export var TexGlyphMode;
|
|
384
|
+
(function (TexGlyphMode) {
|
|
385
|
+
TexGlyphMode[TexGlyphMode["SAMPLE"] = 0] = "SAMPLE";
|
|
386
|
+
TexGlyphMode[TexGlyphMode["GLYPHS"] = 1] = "GLYPHS";
|
|
387
|
+
TexGlyphMode[TexGlyphMode["BG_GLYPHS"] = 2] = "BG_GLYPHS";
|
|
388
|
+
TexGlyphMode[TexGlyphMode["MIX"] = 3] = "MIX";
|
|
389
|
+
TexGlyphMode[TexGlyphMode["ROWS"] = 4] = "ROWS";
|
|
390
|
+
TexGlyphMode[TexGlyphMode["COLS"] = 5] = "COLS";
|
|
391
|
+
})(TexGlyphMode || (TexGlyphMode = {}));
|
|
392
|
+
/**
|
|
393
|
+
* Build a {@link TexGlyphs} grid of `rows` by `cols` cells that samples a
|
|
394
|
+
* texture in the given {@link TexGlyphMode}.
|
|
395
|
+
*
|
|
396
|
+
* The grid is sized to match a region of the terminal (typically the whole
|
|
397
|
+
* canvas, `canvas.rows` x `canvas.cols`, or a smaller sub-region) and is
|
|
398
|
+
* passed to {@link Renderer.draw} along with the texture to display.
|
|
399
|
+
*
|
|
400
|
+
* For the `MIX`, `ROWS`, and `COLS` modes the requested `mode` is used as a
|
|
401
|
+
* base and individual cells are switched between `SAMPLE` and `GLYPHS`
|
|
402
|
+
* according to the pattern (see {@link TexGlyphMode} for what each mode does
|
|
403
|
+
* to the sampled texture). The packed per-cell value encodes the cell's own
|
|
404
|
+
* row/column and the (possibly per-cell) effective mode.
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* ```ts
|
|
408
|
+
* import { TexGlyphMode, textureGlyphs } from "@micahdb/tscon";
|
|
409
|
+
*
|
|
410
|
+
* // whole-canvas glyphs that sample the texture as coloured characters
|
|
411
|
+
* const tg = textureGlyphs(canvas.rows, canvas.cols, TexGlyphMode.GLYPHS);
|
|
412
|
+
* ```
|
|
413
|
+
*
|
|
414
|
+
* @param rows Height of the grid in cells.
|
|
415
|
+
* @param cols Width of the grid in cells.
|
|
416
|
+
* @param mode Sampling mode to apply to the cells.
|
|
417
|
+
* @returns The packed texture-glyph grid.
|
|
418
|
+
*/
|
|
419
|
+
export function textureGlyphs(rows, cols, mode) {
|
|
420
|
+
const tglyphs = {
|
|
421
|
+
data: new Uint32Array(rows * cols),
|
|
422
|
+
rows,
|
|
423
|
+
cols,
|
|
424
|
+
};
|
|
425
|
+
const global_mode = mode;
|
|
426
|
+
for (let data_idx = 0; data_idx < rows * cols; data_idx++) {
|
|
427
|
+
const row = Math.floor(data_idx / cols);
|
|
428
|
+
const col = data_idx % cols;
|
|
429
|
+
if (global_mode == TexGlyphMode.MIX) {
|
|
430
|
+
mode = (row + col) % 2 == 0
|
|
431
|
+
? TexGlyphMode.SAMPLE
|
|
432
|
+
: TexGlyphMode.GLYPHS;
|
|
433
|
+
}
|
|
434
|
+
else if (global_mode == TexGlyphMode.ROWS) {
|
|
435
|
+
mode = row % 2 == 0
|
|
436
|
+
? TexGlyphMode.SAMPLE
|
|
437
|
+
: TexGlyphMode.GLYPHS;
|
|
438
|
+
}
|
|
439
|
+
else if (global_mode == TexGlyphMode.COLS) {
|
|
440
|
+
mode = col % 2 == 0
|
|
441
|
+
? TexGlyphMode.SAMPLE
|
|
442
|
+
: TexGlyphMode.GLYPHS;
|
|
443
|
+
}
|
|
444
|
+
const glyph = ((row & 0xff) << 24) | ((mode & 0xff) << 16) |
|
|
445
|
+
(col & 0xffff);
|
|
446
|
+
tglyphs.data[data_idx] = glyph;
|
|
447
|
+
}
|
|
448
|
+
return tglyphs;
|
|
449
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { Canvas } from "./canvas.ts";
|
|
2
|
+
export { Terminal } from "./terminal.ts";
|
|
3
|
+
export { TAB_WIDTH, TexGlyphMode, textGlyphs, textToLines, textureGlyphs, } from "./glyphs.ts";
|
|
4
|
+
export type { Anchor, Glyphs, TexGlyphs } from "./glyphs.ts";
|
|
5
|
+
export { Renderer } from "./renderer.ts";
|
|
6
|
+
export { Mat4, Vec4 } from "./math.ts";
|
|
7
|
+
export { compileProgram, getAttribLocations, getUniformLocations, } from "./program.ts";
|
|
8
|
+
export { renderCp437 } from "./cp437.ts";
|
|
9
|
+
export { Colour, PALETTE } from "./colour.ts";
|
|
10
|
+
export type { Rect } from "./rect.ts";
|
|
11
|
+
export { loadCubeMap, loadTexture } from "./texture.ts";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { Canvas } from "./canvas.js";
|
|
2
|
+
export { Terminal } from "./terminal.js";
|
|
3
|
+
export { TAB_WIDTH, TexGlyphMode, textGlyphs, textToLines, textureGlyphs, } from "./glyphs.js";
|
|
4
|
+
export { Renderer } from "./renderer.js";
|
|
5
|
+
export { Mat4, Vec4 } from "./math.js";
|
|
6
|
+
export { compileProgram, getAttribLocations, getUniformLocations, } from "./program.js";
|
|
7
|
+
export { renderCp437 } from "./cp437.js";
|
|
8
|
+
export { Colour, PALETTE } from "./colour.js";
|
|
9
|
+
export { loadCubeMap, loadTexture } from "./texture.js";
|
package/dist/math.d.ts
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A column-major 4x4 matrix stored as a 16-element `Float32Array`.
|
|
3
|
+
*
|
|
4
|
+
* `Mat4` provides static helpers for creating and operating on 4x4 matrices
|
|
5
|
+
* following the conventions of `gl-matrix`-style libraries: the `o` argument
|
|
6
|
+
* of each operation is the output buffer (which may alias an input) and the
|
|
7
|
+
* same buffer is returned to allow chaining.
|
|
8
|
+
*
|
|
9
|
+
* Matrices are stored column-major; element `m[col * 4 + row]` is row `row`,
|
|
10
|
+
* column `col`.
|
|
11
|
+
*/
|
|
12
|
+
export declare class Mat4 {
|
|
13
|
+
/**
|
|
14
|
+
* Create and return a new 4x4 identity matrix.
|
|
15
|
+
*
|
|
16
|
+
* @returns A 16-element `Float32Array` initialised to the identity
|
|
17
|
+
* matrix.
|
|
18
|
+
*/
|
|
19
|
+
static create(): Float32Array;
|
|
20
|
+
/**
|
|
21
|
+
* Set all 16 components of matrix `o` to the given values, which are
|
|
22
|
+
* supplied in column-major order (`m00, m01, m02, m03, m10, ...`).
|
|
23
|
+
*
|
|
24
|
+
* `o` is returned for convenience.
|
|
25
|
+
*
|
|
26
|
+
* @param o The matrix to write into.
|
|
27
|
+
* @returns The same matrix `o`, with its components overwritten.
|
|
28
|
+
*/
|
|
29
|
+
static set(o: Float32Array, m00: number, m01: number, m02: number, m03: number, m10: number, m11: number, m12: number, m13: number, m20: number, m21: number, m22: number, m23: number, m30: number, m31: number, m32: number, m33: number): Float32Array;
|
|
30
|
+
/**
|
|
31
|
+
* Multiply matrices `a` and `b` and store the result in `o`
|
|
32
|
+
* (`o = a * b`).
|
|
33
|
+
*
|
|
34
|
+
* `o` may be the same buffer as `a` or `b`. The result is equivalent to
|
|
35
|
+
* first applying `b` then `a` (i.e. `a * b` in standard column-vector
|
|
36
|
+
* notation), which is the order used for building model/view/projection
|
|
37
|
+
* chains.
|
|
38
|
+
*
|
|
39
|
+
* @param o Output matrix (may alias `a` or `b`).
|
|
40
|
+
* @param a Left-hand matrix.
|
|
41
|
+
* @param b Right-hand matrix.
|
|
42
|
+
* @returns The matrix `o`.
|
|
43
|
+
*/
|
|
44
|
+
static multiply(o: Float32Array, a: Float32Array, b: Float32Array): Float32Array;
|
|
45
|
+
/**
|
|
46
|
+
* Set `o` to the transpose of `a`.
|
|
47
|
+
*
|
|
48
|
+
* `o` may be the same buffer as `a`; in that case the transpose is
|
|
49
|
+
* performed in place.
|
|
50
|
+
*
|
|
51
|
+
* @param o Output matrix (may alias `a`).
|
|
52
|
+
* @param a Source matrix.
|
|
53
|
+
* @returns The matrix `o`.
|
|
54
|
+
*/
|
|
55
|
+
static transpose(o: Float32Array, a: Float32Array): Float32Array;
|
|
56
|
+
/**
|
|
57
|
+
* Set `o` to the inverse of `a`.
|
|
58
|
+
*
|
|
59
|
+
* The determinant is computed internally; if it is zero the resulting
|
|
60
|
+
* matrix is undefined. `o` must not alias `a` (the computation
|
|
61
|
+
* reads `a` while writing `o`).
|
|
62
|
+
*
|
|
63
|
+
* @param o Output matrix (must not alias `a`).
|
|
64
|
+
* @param a Source matrix.
|
|
65
|
+
* @returns The matrix `o`.
|
|
66
|
+
*/
|
|
67
|
+
static inverse(o: Float32Array, a: Float32Array): Float32Array;
|
|
68
|
+
/**
|
|
69
|
+
* Compute the upper-left 3x3 inverse-transpose of `a` and write it into
|
|
70
|
+
* the 9-element output `o`.
|
|
71
|
+
*
|
|
72
|
+
* This is the standard "normal matrix" used to transform normals in a
|
|
73
|
+
* lighting shader. `o` must be a `Float32Array` of length 9 and
|
|
74
|
+
* must not alias `a`.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* import { Mat4 } from "@micahdb/tscon";
|
|
79
|
+
*
|
|
80
|
+
* const mv = Mat4.create();
|
|
81
|
+
* Mat4.multiply(mv, view, model);
|
|
82
|
+
* const normals = new Float32Array(9);
|
|
83
|
+
* Mat4.inverseTranspose3x3(normals, mv);
|
|
84
|
+
* gl.uniformMatrix3fv(loc, false, normals);
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @param o Output 3x3 matrix (length-9 `Float32Array`).
|
|
88
|
+
* @param a Source 4x4 matrix.
|
|
89
|
+
* @returns The matrix `o`.
|
|
90
|
+
*/
|
|
91
|
+
static inverseTranspose3x3(o: Float32Array, a: Float32Array): Float32Array;
|
|
92
|
+
/**
|
|
93
|
+
* Set `o` to a perspective projection matrix.
|
|
94
|
+
*
|
|
95
|
+
* The matrix maps a view frustum defined by a vertical field of view
|
|
96
|
+
* `fovy` (in radians), the viewport `aspect` ratio (width /
|
|
97
|
+
* height), and the `near` and `far` clip-plane distances into clip
|
|
98
|
+
* space, with the camera looking down -Z.
|
|
99
|
+
*
|
|
100
|
+
* @param o Output matrix.
|
|
101
|
+
* @param fovy Vertical field of view, in radians.
|
|
102
|
+
* @param aspect Width / height of the viewport.
|
|
103
|
+
* @param near Distance to the near clip plane.
|
|
104
|
+
* @param far Distance to the far clip plane.
|
|
105
|
+
* @returns The matrix `o`.
|
|
106
|
+
*/
|
|
107
|
+
static perspective(o: Float32Array, fovy: number, aspect: number, near: number, far: number): Float32Array;
|
|
108
|
+
/**
|
|
109
|
+
* Set `o` to an orthographic projection matrix.
|
|
110
|
+
*
|
|
111
|
+
* The matrix maps the axis-aligned box with the given left/right,
|
|
112
|
+
* bottom/top, and near/far planes into clip space.
|
|
113
|
+
*
|
|
114
|
+
* @param o Output matrix.
|
|
115
|
+
* @param left Left edge of the view volume.
|
|
116
|
+
* @param right Right edge of the view volume.
|
|
117
|
+
* @param bottom Bottom edge of the view volume.
|
|
118
|
+
* @param top Top edge of the view volume.
|
|
119
|
+
* @param near Distance to the near clip plane.
|
|
120
|
+
* @param far Distance to the far clip plane.
|
|
121
|
+
* @returns The matrix `o`.
|
|
122
|
+
*/
|
|
123
|
+
static orthographic(o: Float32Array, left: number, right: number, bottom: number, top: number, near: number, far: number): Float32Array;
|
|
124
|
+
/**
|
|
125
|
+
* Set `o` to a "look at" view matrix.
|
|
126
|
+
*
|
|
127
|
+
* Builds a camera/view matrix placed at `eye`, oriented to look towards
|
|
128
|
+
* `center`, with the given `up` axis. The result transforms world-space
|
|
129
|
+
* coordinates into view space (camera looking down -Z).
|
|
130
|
+
*
|
|
131
|
+
* @param o Output matrix.
|
|
132
|
+
* @param eye Camera position as a length-3 array `[x, y, z]`.
|
|
133
|
+
* @param center Point the camera looks towards, `[x, y, z]`.
|
|
134
|
+
* @param up Camera up direction, `[x, y, z]`.
|
|
135
|
+
* @returns The matrix `o`.
|
|
136
|
+
*/
|
|
137
|
+
static lookAt(o: Float32Array, e: Float32Array, c: Float32Array, up: Float32Array): Float32Array;
|
|
138
|
+
/**
|
|
139
|
+
* Create and return a translation matrix for the given offsets.
|
|
140
|
+
*
|
|
141
|
+
* @param tx Translation along X.
|
|
142
|
+
* @param ty Translation along Y.
|
|
143
|
+
* @param tz Translation along Z.
|
|
144
|
+
* @returns A new translation matrix.
|
|
145
|
+
*/
|
|
146
|
+
static translation(tx: number, ty: number, tz: number): Float32Array;
|
|
147
|
+
/**
|
|
148
|
+
* Create and return a non-uniform scale matrix.
|
|
149
|
+
*
|
|
150
|
+
* @param sx Scale factor along X.
|
|
151
|
+
* @param sy Scale factor along Y.
|
|
152
|
+
* @param sz Scale factor along Z.
|
|
153
|
+
* @returns A new scale matrix.
|
|
154
|
+
*/
|
|
155
|
+
static scale(sx: number, sy: number, sz: number): Float32Array;
|
|
156
|
+
/**
|
|
157
|
+
* Create and return a rotation matrix.
|
|
158
|
+
*
|
|
159
|
+
* The rotation is by `radians` about one of the principal axes. The
|
|
160
|
+
* returned matrix follows a right-handed convention.
|
|
161
|
+
*
|
|
162
|
+
* @param axis The axis to rotate about: `"x"`, `"y"`, or `"z"`.
|
|
163
|
+
* @param radians Rotation angle in radians.
|
|
164
|
+
* @returns A new rotation matrix, or an identity matrix if
|
|
165
|
+
* `axis` is not recognised.
|
|
166
|
+
*/
|
|
167
|
+
static rotation(axis: string, radians: number): Float32Array;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* A 4-component vector stored as a 4-element `Float32Array`.
|
|
171
|
+
*
|
|
172
|
+
* Like {@link Mat4}, `Vec4` exposes static helpers that take an output buffer
|
|
173
|
+
* `o` (returned for chaining) rather than allocating on each operation.
|
|
174
|
+
*/
|
|
175
|
+
export declare class Vec4 {
|
|
176
|
+
/**
|
|
177
|
+
* Create and return a new zeroed 4-component vector.
|
|
178
|
+
*
|
|
179
|
+
* @returns A length-4 `Float32Array` initialised to `[0, 0, 0, 0]`.
|
|
180
|
+
*/
|
|
181
|
+
static create(): Float32Array;
|
|
182
|
+
/**
|
|
183
|
+
* Set the four components of vector `o` to the given values.
|
|
184
|
+
*
|
|
185
|
+
* @param o The vector to write into.
|
|
186
|
+
* @param x Component 0.
|
|
187
|
+
* @param y Component 1.
|
|
188
|
+
* @param z Component 2.
|
|
189
|
+
* @param w Component 3.
|
|
190
|
+
*/
|
|
191
|
+
static set(o: Float32Array, x: number, y: number, z: number, w: number): void;
|
|
192
|
+
/**
|
|
193
|
+
* Create and return a new vector initialised to the given values.
|
|
194
|
+
*
|
|
195
|
+
* @param x Component 0.
|
|
196
|
+
* @param y Component 1.
|
|
197
|
+
* @param z Component 2.
|
|
198
|
+
* @param w Component 3.
|
|
199
|
+
* @returns A new length-4 `Float32Array`.
|
|
200
|
+
*/
|
|
201
|
+
static from(x: number, y: number, z: number, w: number): Float32Array;
|
|
202
|
+
/**
|
|
203
|
+
* Transform vector `a` by matrix `m` and store the result in `o`
|
|
204
|
+
* (`o = m * a`, treating `a` as a column vector).
|
|
205
|
+
*
|
|
206
|
+
* `o` may be the same buffer as `a`.
|
|
207
|
+
*
|
|
208
|
+
* @param o Output vector (may alias `a`).
|
|
209
|
+
* @param a Source vector.
|
|
210
|
+
* @param m Transformation matrix.
|
|
211
|
+
* @returns The vector `o`.
|
|
212
|
+
*/
|
|
213
|
+
static transformMat4(o: Float32Array, a: Float32Array, m: Float32Array): Float32Array;
|
|
214
|
+
}
|