Refactor and enhance documentation across the Wolf3D project
- Updated library imports to use the correct package paths for consistency. - Added detailed documentation comments to various classes and methods, improving code readability and maintainability. - Refined the GameSelectScreen, SpriteGallery, and VgaGallery classes with clearer descriptions of their functionality. - Enhanced the CliInput class to better explain the input handling process and its interaction with the engine. - Improved the SixelRasterizer and Opl2Emulator classes with comprehensive comments on their operations and state management. - Removed the deprecated wolf_3d.dart file and consolidated its functionality into wolf_3d_flutter.dart for a cleaner architecture. - Updated the Wolf3dFlutterInput class to clarify its role in merging keyboard and pointer events. - Enhanced the rendering classes to provide better context on their purpose and usage within the Flutter framework. Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -1,21 +1,30 @@
|
||||
/// Shared Flutter renderer shell for driving the Wolf3D engine from a widget tree.
|
||||
library;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
|
||||
|
||||
// 1. The widget now only requires the engine!
|
||||
/// Base widget for renderers that present frames from a [WolfEngine].
|
||||
abstract class BaseWolfRenderer extends StatefulWidget {
|
||||
/// Engine instance that owns world state and the shared framebuffer.
|
||||
final WolfEngine engine;
|
||||
|
||||
/// Creates a renderer bound to [engine].
|
||||
const BaseWolfRenderer({
|
||||
required this.engine,
|
||||
super.key,
|
||||
});
|
||||
}
|
||||
|
||||
/// Base [State] implementation that provides a ticker-driven render loop.
|
||||
abstract class BaseWolfRendererState<T extends BaseWolfRenderer>
|
||||
extends State<T>
|
||||
with SingleTickerProviderStateMixin {
|
||||
/// Per-frame ticker used to advance the engine and request renders.
|
||||
late final Ticker gameLoop;
|
||||
|
||||
/// Focus node used by the enclosing [KeyboardListener].
|
||||
final FocusNode focusNode = FocusNode();
|
||||
|
||||
Duration _lastTick = Duration.zero;
|
||||
@@ -50,8 +59,13 @@ abstract class BaseWolfRendererState<T extends BaseWolfRenderer>
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/// Renders the latest engine state into the concrete renderer's output type.
|
||||
void performRender();
|
||||
|
||||
/// Builds the visible viewport widget for the latest rendered frame.
|
||||
Widget buildViewport(BuildContext context);
|
||||
|
||||
/// Background color used by the surrounding scaffold.
|
||||
Color get scaffoldColor;
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
/// Flutter widget that renders Wolf3D frames using the ASCII rasterizer.
|
||||
library;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:wolf_3d_dart/wolf_3d_rasterizer.dart';
|
||||
import 'package:wolf_3d_renderer/base_renderer.dart';
|
||||
|
||||
/// Displays the game using a text-mode approximation of the original renderer.
|
||||
class WolfAsciiRenderer extends BaseWolfRenderer {
|
||||
/// Creates an ASCII renderer bound to [engine].
|
||||
const WolfAsciiRenderer({
|
||||
required super.engine,
|
||||
super.key,
|
||||
@@ -22,6 +27,8 @@ class _WolfAsciiRendererState extends BaseWolfRendererState<WolfAsciiRenderer> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// ASCII output uses a reduced logical framebuffer because glyph rendering
|
||||
// expands the final view significantly once laid out in Flutter text.
|
||||
if (widget.engine.frameBuffer.width != _renderWidth ||
|
||||
widget.engine.frameBuffer.height != _renderHeight) {
|
||||
widget.engine.setFrameBuffer(_renderWidth, _renderHeight);
|
||||
@@ -46,9 +53,12 @@ class _WolfAsciiRendererState extends BaseWolfRendererState<WolfAsciiRenderer> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Paints a pre-rasterized ASCII frame using grouped text spans per color run.
|
||||
class AsciiFrameWidget extends StatelessWidget {
|
||||
/// Two-dimensional text grid generated by [AsciiRasterizer.render].
|
||||
final List<List<ColoredChar>> frameData;
|
||||
|
||||
/// Creates a widget that displays [frameData].
|
||||
const AsciiFrameWidget({super.key, required this.frameData});
|
||||
|
||||
@override
|
||||
@@ -65,6 +75,8 @@ class AsciiFrameWidget extends StatelessWidget {
|
||||
children: frameData.map((row) {
|
||||
List<TextSpan> optimizedSpans = [];
|
||||
if (row.isNotEmpty) {
|
||||
// Merge adjacent cells with the same color to keep the rich
|
||||
// text tree smaller and reduce per-frame layout overhead.
|
||||
Color currentColor = Color(row[0].argb);
|
||||
StringBuffer currentSegment = StringBuffer(row[0].char);
|
||||
|
||||
|
||||
@@ -7,18 +7,26 @@ import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
||||
|
||||
/// A unified widget to display and cache Wolf3D assets.
|
||||
class WolfAssetPainter extends StatefulWidget {
|
||||
/// Decoded sprite source, when painting a sprite asset.
|
||||
final Sprite? sprite;
|
||||
|
||||
/// Decoded VGA image source, when painting a VGA asset.
|
||||
final VgaImage? vgaImage;
|
||||
|
||||
/// Pre-rendered game frame, when painting live gameplay output.
|
||||
final ui.Image? frame;
|
||||
|
||||
/// Creates a painter for a palette-indexed [Sprite].
|
||||
const WolfAssetPainter.sprite(this.sprite, {super.key})
|
||||
: vgaImage = null,
|
||||
frame = null;
|
||||
|
||||
/// Creates a painter for a planar VGA image.
|
||||
const WolfAssetPainter.vga(this.vgaImage, {super.key})
|
||||
: sprite = null,
|
||||
frame = null;
|
||||
|
||||
/// Creates a painter for an already decoded [ui.Image] frame.
|
||||
const WolfAssetPainter.frame(this.frame, {super.key})
|
||||
: sprite = null,
|
||||
vgaImage = null;
|
||||
@@ -30,7 +38,8 @@ class WolfAssetPainter extends StatefulWidget {
|
||||
class _WolfAssetPainterState extends State<WolfAssetPainter> {
|
||||
ui.Image? _cachedImage;
|
||||
|
||||
// Tracks if we should dispose the image to free native memory
|
||||
// Only images created inside this widget should be disposed here. Frames
|
||||
// handed in from elsewhere remain owned by their producer.
|
||||
bool _ownsImage = false;
|
||||
|
||||
@override
|
||||
@@ -58,13 +67,14 @@ class _WolfAssetPainterState extends State<WolfAssetPainter> {
|
||||
}
|
||||
|
||||
Future<void> _prepareImage() async {
|
||||
// Clean up previous internally generated image
|
||||
// Dispose previously generated images before creating a replacement so the
|
||||
// widget does not retain stale native image allocations.
|
||||
if (_ownsImage && _cachedImage != null) {
|
||||
_cachedImage!.dispose();
|
||||
_cachedImage = null;
|
||||
}
|
||||
|
||||
// If a pre-rendered frame is passed in, just use it directly
|
||||
// Pre-decoded frames can be used as-is and stay owned by the caller.
|
||||
if (widget.frame != null) {
|
||||
_ownsImage = false;
|
||||
if (mounted) {
|
||||
@@ -86,12 +96,13 @@ class _WolfAssetPainterState extends State<WolfAssetPainter> {
|
||||
_cachedImage = newImage;
|
||||
});
|
||||
} else {
|
||||
// If the widget was unmounted while building, dispose the unused image
|
||||
// If the widget was unmounted while work completed, dispose the image
|
||||
// immediately to avoid leaking native resources.
|
||||
newImage?.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a Sprite's 8-bit palette data to a 32-bit RGBA ui.Image
|
||||
/// Converts a sprite's indexed palette data into a Flutter [ui.Image].
|
||||
Future<ui.Image> _buildSpriteImage(Sprite sprite) {
|
||||
final completer = Completer<ui.Image>();
|
||||
final pixels = Uint8List(64 * 64 * 4); // 4 bytes per pixel (RGBA)
|
||||
@@ -124,7 +135,7 @@ class _WolfAssetPainterState extends State<WolfAssetPainter> {
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
/// Converts a VgaImage's planar 8-bit palette data to a 32-bit RGBA ui.Image
|
||||
/// Converts a planar VGA image into a row-major Flutter [ui.Image].
|
||||
Future<ui.Image> _buildVgaImage(VgaImage image) {
|
||||
final completer = Completer<ui.Image>();
|
||||
final pixels = Uint8List(image.width * image.height * 4);
|
||||
@@ -185,7 +196,9 @@ class _WolfAssetPainterState extends State<WolfAssetPainter> {
|
||||
}
|
||||
|
||||
class _ImagePainter extends CustomPainter {
|
||||
/// Image already decoded into Flutter's native image representation.
|
||||
final ui.Image image;
|
||||
|
||||
_ImagePainter(this.image);
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/// Flutter widget that renders Wolf3D frames as native pixel images.
|
||||
library;
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -6,7 +9,9 @@ import 'package:wolf_3d_dart/wolf_3d_rasterizer.dart';
|
||||
import 'package:wolf_3d_renderer/base_renderer.dart';
|
||||
import 'package:wolf_3d_renderer/wolf_3d_asset_painter.dart';
|
||||
|
||||
/// Presents the software rasterizer output by decoding the shared framebuffer.
|
||||
class WolfFlutterRenderer extends BaseWolfRenderer {
|
||||
/// Creates a pixel renderer bound to [engine].
|
||||
const WolfFlutterRenderer({
|
||||
required super.engine,
|
||||
super.key,
|
||||
@@ -28,6 +33,7 @@ class _WolfFlutterRendererState
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Match the original Wolf3D software resolution for the pixel renderer.
|
||||
if (widget.engine.frameBuffer.width != _renderWidth ||
|
||||
widget.engine.frameBuffer.height != _renderHeight) {
|
||||
widget.engine.setFrameBuffer(_renderWidth, _renderHeight);
|
||||
@@ -45,6 +51,8 @@ class _WolfFlutterRendererState
|
||||
final FrameBuffer frameBuffer = widget.engine.frameBuffer;
|
||||
_rasterizer.render(widget.engine);
|
||||
|
||||
// Convert the engine-owned framebuffer into a GPU-friendly ui.Image on
|
||||
// the Flutter side while preserving nearest-neighbor pixel fidelity.
|
||||
ui.decodeImageFromPixels(
|
||||
frameBuffer.pixels.buffer.asUint8List(),
|
||||
frameBuffer.width,
|
||||
@@ -64,7 +72,7 @@ class _WolfFlutterRendererState
|
||||
|
||||
@override
|
||||
Widget buildViewport(BuildContext context) {
|
||||
// If we don't have a frame yet, show the loading state
|
||||
// Delay painting until at least one decoded frame is available.
|
||||
if (_renderedFrame == null) {
|
||||
return const CircularProgressIndicator(color: Colors.white24);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user