feat: Add GLSL renderer and implement FPS overlay across rendering backends

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-19 19:12:39 +01:00
parent c62ea013ba
commit c8cd2cb144
9 changed files with 344 additions and 8 deletions

View File

@@ -7,6 +7,13 @@ import 'package:wolf_3d_dart/wolf_3d_engine.dart';
import 'package:wolf_3d_flutter/wolf_3d_flutter.dart';
import 'package:wolf_3d_renderer/wolf_3d_ascii_renderer.dart';
import 'package:wolf_3d_renderer/wolf_3d_flutter_renderer.dart';
import 'package:wolf_3d_renderer/wolf_3d_glsl_renderer.dart';
enum _RendererMode {
software,
ascii,
glsl,
}
/// Launches a [WolfEngine] via [Wolf3d] and exposes renderer/input integrations.
class GameScreen extends StatefulWidget {
@@ -25,7 +32,7 @@ class GameScreen extends StatefulWidget {
class _GameScreenState extends State<GameScreen> {
late final WolfEngine _engine;
bool _useAsciiMode = false;
_RendererMode _rendererMode = _RendererMode.software;
@override
void initState() {
@@ -60,11 +67,7 @@ class _GameScreenState extends State<GameScreen> {
onPointerHover: widget.wolf3d.input.onPointerMove,
child: Stack(
children: [
// Keep both renderers behind the same engine so mode switching does
// not reset level state or audio playback.
_useAsciiMode
? WolfAsciiRenderer(engine: _engine)
: WolfFlutterRenderer(engine: _engine),
_buildRenderer(),
if (!_engine.isInitialized)
Container(
@@ -93,7 +96,7 @@ class _GameScreenState extends State<GameScreen> {
onKeyEvent: (node, event) {
if (event is KeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.tab) {
setState(() => _useAsciiMode = !_useAsciiMode);
setState(_cycleRendererMode);
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
@@ -115,7 +118,7 @@ class _GameScreenState extends State<GameScreen> {
top: 16,
right: 16,
child: Text(
'TAB: Swap Renderer',
'TAB: ${_modeLabel(_rendererMode)}',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.5),
),
@@ -129,4 +132,54 @@ class _GameScreenState extends State<GameScreen> {
),
);
}
Widget _buildRenderer() {
// Keep all renderers behind the same engine so mode switching does not
// reset level state or audio playback.
switch (_rendererMode) {
case _RendererMode.software:
return WolfFlutterRenderer(engine: _engine);
case _RendererMode.ascii:
return WolfAsciiRenderer(engine: _engine);
case _RendererMode.glsl:
return WolfGlslRenderer(
engine: _engine,
onUnavailable: _onGlslUnavailable,
);
}
}
void _cycleRendererMode() {
switch (_rendererMode) {
case _RendererMode.software:
_rendererMode = _RendererMode.ascii;
break;
case _RendererMode.ascii:
_rendererMode = _RendererMode.glsl;
break;
case _RendererMode.glsl:
_rendererMode = _RendererMode.software;
break;
}
}
void _onGlslUnavailable() {
if (!mounted || _rendererMode != _RendererMode.glsl) {
return;
}
setState(() {
_rendererMode = _RendererMode.software;
});
}
String _modeLabel(_RendererMode mode) {
switch (mode) {
case _RendererMode.software:
return 'Software';
case _RendererMode.ascii:
return 'ASCII';
case _RendererMode.glsl:
return 'GLSL';
}
}
}