Refactor menu rendering and improve projection sampling

- Updated AsciiRasterizer to support game and episode selection menus with improved layout and cursor handling.
- Enhanced SixelRasterizer and SoftwareRasterizer to modularize menu drawing logic for game and episode selection.
- Introduced new methods for drawing menus and applying fade effects across rasterizers.
- Adjusted wall texture sampling in Rasterizer to anchor to projection height center for consistent rendering.
- Added tests for wall texture sampling behavior to ensure legacy compatibility and new functionality.
- Modified Flutter audio adapter to use nullable access for active game and adjusted game selection logic in the main class.
- Cleaned up input handling in Wolf3dFlutterInput by removing unused menu tap variables.

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-18 20:06:18 +01:00
parent d93f467163
commit 0e143892f0
15 changed files with 1090 additions and 204 deletions

View File

@@ -147,7 +147,7 @@ WolfEngine _buildEngine({
startingEpisode: 0,
frameBuffer: FrameBuffer(64, 64),
input: input,
audio: audio,
engineAudio: audio,
onGameWon: () {},
);
}

View File

@@ -0,0 +1,85 @@
import 'package:test/test.dart';
import 'package:wolf_3d_dart/src/rasterizer/rasterizer.dart';
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
import 'package:wolf_3d_dart/wolf_3d_engine.dart';
void main() {
group('Rasterizer wall texture sampling', () {
test('anchors wall texel sampling to projection height center', () {
final rasterizer = _TestRasterizer(customProjectionViewHeight: 40);
rasterizer.configureViewGeometry(width: 64, height: 64, viewHeight: 20);
// With sceneHeight=40 and columnHeight=20, projected wall spans y=10..30.
// Top pixel should sample from top texel row.
expect(rasterizer.wallTexY(10, 20), 0);
// Bottom visible pixel should sample close to bottom texel row.
expect(rasterizer.wallTexY(29, 20), inInclusiveRange(60, 63));
});
test('keeps legacy behavior when projection height equals view height', () {
final rasterizer = _TestRasterizer(customProjectionViewHeight: 20);
rasterizer.configureViewGeometry(width: 64, height: 64, viewHeight: 20);
// With sceneHeight=viewHeight=20 and columnHeight=20, top starts at y=0.
expect(rasterizer.wallTexY(0, 20), 0);
expect(rasterizer.wallTexY(19, 20), inInclusiveRange(60, 63));
});
});
}
class _TestRasterizer extends Rasterizer<FrameBuffer> {
_TestRasterizer({required this.customProjectionViewHeight});
final int customProjectionViewHeight;
@override
int get projectionViewHeight => customProjectionViewHeight;
void configureViewGeometry({
required int width,
required int height,
required int viewHeight,
}) {
this.width = width;
this.height = height;
this.viewHeight = viewHeight;
}
@override
void prepareFrame(WolfEngine engine) {}
@override
void drawWallColumn(
int x,
int drawStart,
int drawEnd,
int columnHeight,
Sprite texture,
int texX,
double perpWallDist,
int side,
) {}
@override
void drawSpriteStripe(
int stripeX,
int drawStartY,
int drawEndY,
int spriteHeight,
Sprite texture,
int texX,
double transformY,
) {}
@override
void drawWeapon(WolfEngine engine) {}
@override
void drawHud(WolfEngine engine) {}
@override
FrameBuffer finalizeFrame() {
return FrameBuffer(1, 1);
}
}