Fix ASCII rasterizer scaling for CLI
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user