Fix ASCII rasterizer scaling for CLI

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-16 16:29:08 +01:00
parent 5b417c9182
commit 400720a56e
4 changed files with 40 additions and 22 deletions

View File

@@ -41,7 +41,10 @@ void main() async {
final input = CliInput(); final input = CliInput();
final cliAudio = CliSilentAudio(); final cliAudio = CliSilentAudio();
final rasterizer = AsciiRasterizer(); final rasterizer = AsciiRasterizer(
aspectMultiplier: 1.0,
verticalStretch: 2.0,
);
FrameBuffer buffer = FrameBuffer( FrameBuffer buffer = FrameBuffer(
stdout.terminalColumns, stdout.terminalColumns,
@@ -107,8 +110,6 @@ void main() async {
// Move cursor to top-left (0,0) before drawing the frame // Move cursor to top-left (0,0) before drawing the frame
stdout.write('\x1b[H'); stdout.write('\x1b[H');
input.update();
engine.tick(elapsed); engine.tick(elapsed);
rasterizer.render(engine, buffer); rasterizer.render(engine, buffer);
rasterizer.finalizeFrame(); rasterizer.finalizeFrame();

View File

@@ -54,6 +54,27 @@ class _GameScreenState extends State<GameScreen> {
? WolfAsciiRenderer(engine: _engine) ? WolfAsciiRenderer(engine: _engine)
: WolfFlutterRenderer(engine: _engine), : WolfFlutterRenderer(engine: _engine),
if (!_engine.isInitialized)
Container(
color: Colors.black,
child: const Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(color: Colors.teal),
SizedBox(height: 20),
Text(
"GET PSYCHED!",
style: TextStyle(
color: Colors.teal,
fontFamily: 'monospace',
),
),
],
),
),
),
// TAB listener // TAB listener
Focus( Focus(
autofocus: true, autofocus: true,

View File

@@ -47,19 +47,21 @@ class ColoredChar {
} }
class AsciiRasterizer extends Rasterizer { class AsciiRasterizer extends Rasterizer {
final AsciiTheme activeTheme = AsciiThemes.blocks; AsciiRasterizer({
this.activeTheme = AsciiThemes.blocks,
this.aspectMultiplier = 1.0,
this.verticalStretch = 1.0,
});
AsciiTheme activeTheme = AsciiThemes.blocks;
late List<List<ColoredChar>> _screen; late List<List<ColoredChar>> _screen;
late WolfEngine _engine; late WolfEngine _engine;
// Terminal characters are usually twice as tall as they are wide.
// We override the base multiplier to squish sprites horizontally.
@override @override
double get aspectMultiplier => 1.0; final double aspectMultiplier;
// Squish the entire 3D projection vertically by 50% to counteract tall terminal fonts
@override @override
double get verticalStretch => 1.0; final double verticalStretch;
// Intercept the base render call to initialize our text grid // Intercept the base render call to initialize our text grid
@override @override

View File

@@ -26,22 +26,13 @@ class _WolfFlutterRendererState
@override @override
Color get scaffoldColor => const Color.fromARGB(255, 4, 64, 64); Color get scaffoldColor => const Color.fromARGB(255, 4, 64, 64);
@override
void dispose() {
_renderedFrame?.dispose();
super.dispose();
}
@override @override
void performRender() { void performRender() {
// Avoid overlapping render calls since decodeImageFromPixels is async
if (_isRendering) return; if (_isRendering) return;
_isRendering = true; _isRendering = true;
// 1. Rasterize the frame into the pixel buffer
_rasterizer.render(widget.engine, _frameBuffer); _rasterizer.render(widget.engine, _frameBuffer);
// 2. Convert raw pixels to a Flutter ui.Image
ui.decodeImageFromPixels( ui.decodeImageFromPixels(
_frameBuffer.pixels.buffer.asUint8List(), _frameBuffer.pixels.buffer.asUint8List(),
_frameBuffer.width, _frameBuffer.width,
@@ -61,13 +52,16 @@ class _WolfFlutterRendererState
@override @override
Widget buildViewport(BuildContext context) { Widget buildViewport(BuildContext context) {
// If we don't have a frame yet, show the loading state
if (_renderedFrame == null) {
return const CircularProgressIndicator(color: Colors.white24);
}
return Padding( return Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: AspectRatio( child: AspectRatio(
aspectRatio: 4 / 3, aspectRatio: 4 / 3,
child: CustomPaint( child: CustomPaint(painter: BufferPainter(_renderedFrame)),
painter: BufferPainter(_renderedFrame),
),
), ),
); );
} }