Fixed HUD background rendering

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-16 00:22:54 +01:00
parent a73a36e21d
commit e9e56eac9a
4 changed files with 99 additions and 160 deletions

View File

@@ -22,12 +22,16 @@ class SoftwareRasterizer {
// NEW: Apply the full-screen damage tint last
_drawDamageFlash(engine, buffer);
_drawHud(engine, buffer);
}
void _clearScreen(FrameBuffer buffer) {
int halfScreen = (buffer.width * buffer.height) ~/ 2;
const int viewHeight = 160;
int halfScreen = (buffer.width * viewHeight) ~/ 2;
// Only clear the top 160 rows!
buffer.pixels.fillRange(0, halfScreen, ceilingColor);
buffer.pixels.fillRange(halfScreen, buffer.pixels.length, floorColor);
buffer.pixels.fillRange(halfScreen, buffer.width * viewHeight, floorColor);
}
void _castWalls(WolfEngine engine, FrameBuffer buffer, List<double> zBuffer) {
@@ -235,15 +239,16 @@ class SoftwareRasterizer {
FrameBuffer buffer,
double playerAngle,
) {
const int viewHeight = 160;
if (distance <= 0.01) distance = 0.01;
int lineHeight = (buffer.height / distance).toInt();
int lineHeight = (viewHeight / distance).toInt();
int drawStart = -lineHeight ~/ 2 + buffer.height ~/ 2;
int drawStart = -lineHeight ~/ 2 + viewHeight ~/ 2;
if (drawStart < 0) drawStart = 0;
int drawEnd = lineHeight ~/ 2 + buffer.height ~/ 2;
if (drawEnd >= buffer.height) drawEnd = buffer.height - 1;
int drawEnd = lineHeight ~/ 2 + viewHeight ~/ 2;
if (drawEnd >= viewHeight) drawEnd = viewHeight - 1;
int texNum;
if (hitWallId >= 90) {
@@ -258,7 +263,7 @@ class SoftwareRasterizer {
if (side == 1 && math.sin(playerAngle) < 0) texX = 63 - texX;
double step = 64.0 / lineHeight;
double texPos = (drawStart - buffer.height / 2 + lineHeight / 2) * step;
double texPos = (drawStart - viewHeight / 2 + lineHeight / 2) * step;
Sprite texture = textures[texNum];
@@ -278,6 +283,7 @@ class SoftwareRasterizer {
FrameBuffer buffer,
List<double> zBuffer,
) {
const int viewHeight = 160;
final Player player = engine.player;
final List<Entity> activeSprites = List.from(engine.entities);
@@ -306,16 +312,16 @@ class SoftwareRasterizer {
if (transformY > 0) {
int spriteScreenX = ((buffer.width / 2) * (1 + transformX / transformY))
.toInt();
int spriteHeight = (buffer.height / transformY).abs().toInt();
int spriteHeight = (viewHeight / transformY).abs().toInt();
// In 1x1 buffer pixels, the width of the sprite is equal to its height
int spriteWidth = spriteHeight;
int drawStartY = -spriteHeight ~/ 2 + buffer.height ~/ 2;
int drawStartY = -spriteHeight ~/ 2 + viewHeight ~/ 2;
if (drawStartY < 0) drawStartY = 0;
int drawEndY = spriteHeight ~/ 2 + buffer.height ~/ 2;
if (drawEndY >= buffer.height) drawEndY = buffer.height - 1;
int drawEndY = spriteHeight ~/ 2 + viewHeight ~/ 2;
if (drawEndY >= buffer.height) drawEndY = viewHeight - 1;
int drawStartX = -spriteWidth ~/ 2 + spriteScreenX;
int drawEndX = spriteWidth ~/ 2 + spriteScreenX;
@@ -336,7 +342,7 @@ class SoftwareRasterizer {
double step = 64.0 / spriteHeight;
double texPos =
(drawStartY - buffer.height / 2 + spriteHeight / 2) * step;
(drawStartY - viewHeight / 2 + spriteHeight / 2) * step;
for (int y = drawStartY; y < drawEndY; y++) {
int texY = texPos.toInt() & 63;
@@ -357,6 +363,7 @@ class SoftwareRasterizer {
}
void _drawWeapon(WolfEngine engine, FrameBuffer buffer) {
const int viewHeight = 160;
int spriteIndex = engine.player.currentWeapon.getCurrentSpriteIndex(
engine.data.sprites.length,
);
@@ -371,7 +378,7 @@ class SoftwareRasterizer {
// Kept the grounding to the bottom of the screen
int startY =
buffer.height - weaponHeight + (engine.player.weaponAnimOffset ~/ 2);
viewHeight - weaponHeight + (engine.player.weaponAnimOffset ~/ 2);
for (int x = 0; x < 64; x++) {
for (int y = 0; y < 64; y++) {
@@ -420,4 +427,82 @@ class SoftwareRasterizer {
buffer.pixels[i] = (a << 24) | (b << 16) | (g << 8) | r;
}
}
void _drawHud(WolfEngine engine, FrameBuffer buffer) {
// Clever trick: Find the only 320x40 graphic in the VGA chunks!
int statusBarIndex = engine.data.vgaImages.indexWhere(
(img) => img.width == 320 && img.height == 40,
);
if (statusBarIndex == -1) return; // Safety check if it fails to find it
VgaImage statusBar = engine.data.vgaImages[statusBarIndex];
// Draw the background status bar at Y=160
_blitVgaImage(statusBar, 0, 160, buffer);
// --- We will add the digits and face here next ---
}
void _drawNumber(
int value,
int rightAlignX,
int startY,
FrameBuffer buffer,
List<VgaImage> vgaImages,
int zeroIndex, // The VGA index of the '0' digit
) {
String numStr = value.toString();
// Original Wolf3D status bar digits are exactly 8 pixels wide
// We calculate the starting X by moving left based on how many digits there are
int currentX = rightAlignX - (numStr.length * 8);
for (int i = 0; i < numStr.length; i++) {
int digit = int.parse(numStr[i]);
// Because digits 0-9 are stored sequentially, we can just add the
// actual number to the base 'zeroIndex' to get the right graphic!
_blitVgaImage(vgaImages[zeroIndex + digit], currentX, startY, buffer);
currentX += 8; // Move right for the next digit
}
}
void _blitVgaImage(
VgaImage image,
int startX,
int startY,
FrameBuffer buffer,
) {
// Wolfenstein 3D VGA images are stored in "Mode Y" Planar format.
// We must de-interleave the 4 planes to draw them correctly!
int planeWidth = image.width ~/ 4;
int planeSize = planeWidth * image.height;
for (int y = 0; y < image.height; y++) {
for (int x = 0; x < image.width; x++) {
int drawX = startX + x;
int drawY = startY + y;
if (drawX >= 0 &&
drawX < buffer.width &&
drawY >= 0 &&
drawY < buffer.height) {
// Planar to Linear coordinate conversion
int plane = x % 4;
int sx = x ~/ 4;
int index = (plane * planeSize) + (y * planeWidth) + sx;
int colorByte = image.pixels[index];
if (colorByte != 255) {
// 255 is transparent
buffer.pixels[drawY * buffer.width + drawX] =
ColorPalette.vga32Bit[colorByte];
}
}
}
}
}
}