Moved the weapon and damage flash to the rasterizer.
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -10,18 +10,18 @@ class SoftwareRasterizer {
|
|||||||
final int floorColor = ColorPalette.vga32Bit[29];
|
final int floorColor = ColorPalette.vga32Bit[29];
|
||||||
|
|
||||||
void render(WolfEngine engine, FrameBuffer buffer) {
|
void render(WolfEngine engine, FrameBuffer buffer) {
|
||||||
// 1. Wipe the screen clean with ceiling and floor colors
|
|
||||||
_clearScreen(buffer);
|
_clearScreen(buffer);
|
||||||
|
|
||||||
// 2. We need a Z-Buffer (1D array mapping to screen width) so sprites
|
|
||||||
// know if they are hiding behind a wall slice.
|
|
||||||
List<double> zBuffer = List.filled(buffer.width, 0.0);
|
List<double> zBuffer = List.filled(buffer.width, 0.0);
|
||||||
|
|
||||||
// 3. Do the math and draw the walls, filling the Z-Buffer as we go
|
|
||||||
_castWalls(engine, buffer, zBuffer);
|
_castWalls(engine, buffer, zBuffer);
|
||||||
|
|
||||||
// 4. Draw the entities/sprites
|
|
||||||
_castSprites(engine, buffer, zBuffer);
|
_castSprites(engine, buffer, zBuffer);
|
||||||
|
|
||||||
|
// NEW: Draw the weapon on top of the 3D world
|
||||||
|
_drawWeapon(engine, buffer);
|
||||||
|
|
||||||
|
// NEW: Apply the full-screen damage tint last
|
||||||
|
_drawDamageFlash(engine, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _clearScreen(FrameBuffer buffer) {
|
void _clearScreen(FrameBuffer buffer) {
|
||||||
@@ -355,4 +355,69 @@ class SoftwareRasterizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _drawWeapon(WolfEngine engine, FrameBuffer buffer) {
|
||||||
|
int spriteIndex = engine.player.currentWeapon.getCurrentSpriteIndex(
|
||||||
|
engine.data.sprites.length,
|
||||||
|
);
|
||||||
|
Sprite weaponSprite = engine.data.sprites[spriteIndex];
|
||||||
|
|
||||||
|
// Dropped the scale from 4 to 2 (a 50% reduction in size)
|
||||||
|
const int scale = 2;
|
||||||
|
const int weaponWidth = 64 * scale;
|
||||||
|
const int weaponHeight = 64 * scale;
|
||||||
|
|
||||||
|
int startX = (buffer.width ~/ 2) - (weaponWidth ~/ 2);
|
||||||
|
|
||||||
|
// Kept the grounding to the bottom of the screen
|
||||||
|
int startY =
|
||||||
|
buffer.height - weaponHeight + (engine.player.weaponAnimOffset ~/ 2);
|
||||||
|
|
||||||
|
for (int x = 0; x < 64; x++) {
|
||||||
|
for (int y = 0; y < 64; y++) {
|
||||||
|
int colorByte = weaponSprite.pixels[x * 64 + y];
|
||||||
|
|
||||||
|
if (colorByte != 255) {
|
||||||
|
int color32 = ColorPalette.vga32Bit[colorByte];
|
||||||
|
|
||||||
|
for (int sx = 0; sx < scale; sx++) {
|
||||||
|
for (int sy = 0; sy < scale; sy++) {
|
||||||
|
int drawX = startX + (x * scale) + sx;
|
||||||
|
int drawY = startY + (y * scale) + sy;
|
||||||
|
|
||||||
|
if (drawX >= 0 &&
|
||||||
|
drawX < buffer.width &&
|
||||||
|
drawY >= 0 &&
|
||||||
|
drawY < buffer.height) {
|
||||||
|
buffer.pixels[drawY * buffer.width + drawX] = color32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _drawDamageFlash(WolfEngine engine, FrameBuffer buffer) {
|
||||||
|
if (engine.damageFlashOpacity <= 0) return;
|
||||||
|
|
||||||
|
int alpha = (engine.damageFlashOpacity * 256).toInt().clamp(0, 256);
|
||||||
|
int invAlpha = 256 - alpha;
|
||||||
|
|
||||||
|
for (int i = 0; i < buffer.pixels.length; i++) {
|
||||||
|
int color = buffer.pixels[i];
|
||||||
|
|
||||||
|
int r = color & 0xFF;
|
||||||
|
int g = (color >> 8) & 0xFF;
|
||||||
|
int b = (color >> 16) & 0xFF;
|
||||||
|
int a = (color >> 24) & 0xFF;
|
||||||
|
|
||||||
|
// Blend with Red
|
||||||
|
r = ((r * invAlpha) + (255 * alpha)) >> 8;
|
||||||
|
g = (g * invAlpha) >> 8;
|
||||||
|
b = (b * invAlpha) >> 8;
|
||||||
|
|
||||||
|
buffer.pixels[i] = (a << 24) | (b << 16) | (g << 8) | r;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import 'package:wolf_3d_data_types/wolf_3d_data_types.dart';
|
|||||||
import 'package:wolf_3d_engine/wolf_3d_engine.dart';
|
import 'package:wolf_3d_engine/wolf_3d_engine.dart';
|
||||||
import 'package:wolf_3d_input/wolf_3d_input.dart';
|
import 'package:wolf_3d_input/wolf_3d_input.dart';
|
||||||
import 'package:wolf_3d_renderer/hud.dart';
|
import 'package:wolf_3d_renderer/hud.dart';
|
||||||
import 'package:wolf_3d_renderer/weapon_painter.dart';
|
|
||||||
|
|
||||||
class WolfRenderer extends StatefulWidget {
|
class WolfRenderer extends StatefulWidget {
|
||||||
const WolfRenderer(
|
const WolfRenderer(
|
||||||
@@ -125,57 +124,9 @@ class _WolfRendererState extends State<WolfRenderer>
|
|||||||
return Center(
|
return Center(
|
||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: 16 / 10,
|
aspectRatio: 16 / 10,
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
// --- 3D WORLD (PIXEL BUFFER) ---
|
|
||||||
CustomPaint(
|
|
||||||
size: Size(
|
|
||||||
constraints.maxWidth,
|
|
||||||
constraints.maxHeight,
|
|
||||||
),
|
|
||||||
painter: BufferPainter(_renderedFrame),
|
|
||||||
),
|
|
||||||
|
|
||||||
// --- FIRST PERSON WEAPON ---
|
|
||||||
Positioned(
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
child: Center(
|
|
||||||
child: Transform.translate(
|
|
||||||
offset: Offset(
|
|
||||||
0,
|
|
||||||
engine.player.weaponAnimOffset,
|
|
||||||
),
|
|
||||||
child: SizedBox(
|
|
||||||
width: 500,
|
|
||||||
height: 500,
|
|
||||||
child: CustomPaint(
|
child: CustomPaint(
|
||||||
painter: WeaponPainter(
|
size: Size(constraints.maxWidth, constraints.maxHeight),
|
||||||
sprite:
|
painter: BufferPainter(_renderedFrame),
|
||||||
widget.data.sprites[engine
|
|
||||||
.player
|
|
||||||
.currentWeapon
|
|
||||||
.getCurrentSpriteIndex(
|
|
||||||
widget.data.sprites.length,
|
|
||||||
)],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// --- DAMAGE FLASH ---
|
|
||||||
if (engine.damageFlashOpacity > 0)
|
|
||||||
Positioned.fill(
|
|
||||||
child: Container(
|
|
||||||
color: Colors.red.withValues(
|
|
||||||
alpha: engine.damageFlashOpacity,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -190,8 +141,6 @@ class _WolfRendererState extends State<WolfRenderer>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- DEAD SIMPLE PAINTER ---
|
|
||||||
// It literally just stretches the 320x200 image to fill the screen
|
|
||||||
class BufferPainter extends CustomPainter {
|
class BufferPainter extends CustomPainter {
|
||||||
final ui.Image? frame;
|
final ui.Image? frame;
|
||||||
|
|
||||||
@@ -201,7 +150,6 @@ class BufferPainter extends CustomPainter {
|
|||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
if (frame == null) return;
|
if (frame == null) return;
|
||||||
|
|
||||||
// FilterQuality.none guarantees the classic, chunky, un-blurred pixels!
|
|
||||||
final Paint paint = Paint()..filterQuality = FilterQuality.none;
|
final Paint paint = Paint()..filterQuality = FilterQuality.none;
|
||||||
|
|
||||||
final Rect srcRect = Rect.fromLTWH(
|
final Rect srcRect = Rect.fromLTWH(
|
||||||
|
|||||||
Reference in New Issue
Block a user