Actual font rendering support

This commit is contained in:
Pyrex 2023-09-09 18:40:56 -07:00
parent 50a5fc6985
commit fa8d09d504
5 changed files with 117 additions and 31 deletions

View File

@ -3,4 +3,6 @@ import 'package:flutter/material.dart';
class Palette { class Palette {
static const defaultBg = Colors.black; static const defaultBg = Colors.black;
static const defaultFg = Colors.white; static const defaultFg = Colors.white;
static const subtitle = Colors.yellow;
} }

12
lib/game.dart Normal file
View File

@ -0,0 +1,12 @@
import 'package:dartterm/colors.dart';
import 'package:dartterm/terminal.dart';
void main() async {
at(0, 0).puts("Hello, bats!");
at(0, 2).fg(Palette.subtitle).small().puts("Beware of the bat!");
at(4, 4)
.bg(Palette.subtitle)
.fg(Palette.defaultBg)
.big()
.puts("BEWARE OF THE BAT!");
}

View File

@ -1,9 +1,11 @@
import 'package:dartterm/colors.dart'; import 'package:dartterm/colors.dart';
import 'package:dartterm/terminal.dart'; import 'package:dartterm/game.dart' as game;
import 'package:dartterm/terminal.dart' as terminal;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
void main() { void main() {
// terminal.at(0, 0).puts("Hello, world!");
runApp(const App()); runApp(const App());
} }
@ -41,6 +43,7 @@ class _ViewerState extends State<Viewer> {
super.initState(); super.initState();
ticker = Ticker(tick); ticker = Ticker(tick);
ticker!.start(); ticker!.start();
game.main();
} }
@override @override
@ -48,7 +51,8 @@ class _ViewerState extends State<Viewer> {
return Scaffold( return Scaffold(
body: Center( body: Center(
child: AspectRatio( child: AspectRatio(
aspectRatio: width / height, child: terminal.toWidget(context)), aspectRatio: terminal.width / terminal.height,
child: terminal.toWidget(context)),
)); ));
} }

View File

@ -13,32 +13,6 @@ class Terminal {
Terminal() { Terminal() {
tiles = [for (var i = 0; i < nTiles; i += 1) Tile.empty()]; tiles = [for (var i = 0; i < nTiles; i += 1) Tile.empty()];
for (final (x, c) in toCp437String("Hello, world!").indexed) {
tiles[x].content = Content(Font.normal.imageName, c % 32, 2 * (c ~/ 32));
tiles[x + Terminal.width].content =
Content(Font.normal.imageName, c % 32, 2 * (c ~/ 32) + 1);
}
for (final (x, c) in toCp437String("BEWARE OF THE BAT!").indexed) {
tiles[x + Terminal.width * 2].content =
Content(Font.small.imageName, c % 16, c ~/ 16);
}
for (final (x, c) in toCp437String("BEWARE OF THE BAT!").indexed) {
tiles[Terminal.width * (x + 2)].content =
Content(Font.small.imageName, c % 16, c ~/ 16);
}
for (final (x, c) in toCp437String("BEWARE OF THE BAT!").indexed) {
tiles[2 * x + 4 + Terminal.width * 4].content =
Content(Font.big.imageName, 2 * (c % 32), 2 * (c ~/ 32));
tiles[2 * x + 4 + Terminal.width * 5].content =
Content(Font.big.imageName, 2 * (c % 32), 2 * (c ~/ 32) + 1);
tiles[2 * x + 1 + 4 + Terminal.width * 4].content =
Content(Font.big.imageName, 2 * (c % 32) + 1, 2 * (c ~/ 32));
tiles[2 * x + 1 + 4 + Terminal.width * 5].content =
Content(Font.big.imageName, 2 * (c % 32) + 1, 2 * (c ~/ 32) + 1);
}
} }
CustomPaint toWidget(BuildContext context) { CustomPaint toWidget(BuildContext context) {
@ -65,6 +39,92 @@ class Terminal {
} }
} }
class Cursor {
final Terminal t;
int x, y;
Color? _bg, _fg;
Font font = Font.normal;
// TODO: Clip
Cursor({required this.t, required this.x, required this.y});
void clear() {
t.tiles = [for (var i = 0; i < nTiles; i += 1) Tile.empty()];
}
void putc(int c) {
for (var dx = 0; dx < font.cellWidth; dx += 1) {
for (var dy = 0; dy < font.cellHeight; dy += 1) {
var i = t.fromXY(x + dx, y + dy);
if (i != null) {
final (sourceCx, sourceCy) = (
(c % font.nCellsW) * font.cellWidth + dx,
(c ~/ font.nCellsW) * font.cellHeight + dy
);
t.tiles[i].content = Content(font.imageName, sourceCx, sourceCy);
final (bg, fg) = (_bg, _fg);
if (bg != null) {
t.tiles[i].bg = bg;
}
if (fg != null) {
t.tiles[i].fg = fg;
}
}
}
}
}
void puts(String s) {
var startX = x;
for (final c in toCp437String(s)) {
if (c == 10) {
// newline
x = startX;
y += font.cellHeight;
continue;
}
if (c == 13) {
// carriage return
x = startX;
continue;
}
putc(c);
x += font.cellWidth;
}
}
Cursor fg(Color c) {
_fg = c;
return this;
}
Cursor bg(Color c) {
_bg = c;
return this;
}
Cursor small() {
font = Font.small;
return this;
}
Cursor normal() {
font = Font.normal;
return this;
}
Cursor big() {
font = Font.big;
return this;
}
}
class Clip {}
class Tile { class Tile {
Content? content; Content? content;
@ -85,11 +145,19 @@ class Content {
} }
// reexports // reexports
Terminal terminal = Terminal(); Terminal _terminal = Terminal();
const int width = Terminal.width; const int width = Terminal.width;
const int height = Terminal.height; const int height = Terminal.height;
const int nTiles = Terminal.nTiles; const int nTiles = Terminal.nTiles;
Widget toWidget(BuildContext context) { Widget toWidget(BuildContext context) {
return terminal.toWidget(context); return _terminal.toWidget(context);
}
void clear() {
at(0, 0).clear();
}
Cursor at(int x, int y) {
return Cursor(t: _terminal, x: x, y: y);
} }

View File

@ -44,7 +44,7 @@ class TerminalCustomPainter extends CustomPainter {
// == Draw the background and foreground of every tile == // == Draw the background and foreground of every tile ==
for (var i = 0; i < nTiles; i++) { for (var i = 0; i < nTiles; i++) {
final (pcxDst, pcyDst) = terminal.toXY(i) ?? (0, 0); final (pcxDst, pcyDst) = t.toXY(i) ?? (0, 0);
final (pxDst, pyDst) = (pcxDst * cellW, pcyDst * cellH); final (pxDst, pyDst) = (pcxDst * cellW, pcyDst * cellH);
final rectDst = Rect.fromLTWH(pxDst.toDouble(), pyDst.toDouble(), final rectDst = Rect.fromLTWH(pxDst.toDouble(), pyDst.toDouble(),
cellW.toDouble(), cellH.toDouble()); cellW.toDouble(), cellH.toDouble());