fix: cross-fade tiles to sky tile using alpha instead of color tint

Replace df_fade_color (multiplicative tint that preserves texture hue)
with tile_for_depth which cross-fades between real tile and sky tile:

- z_diff <= 0: real tile at full opacity (no fade)
- z_diff in (0, threshold): real tile fades out via alpha
- z_diff past threshold: sky tile (index 0) fades in
- invisible tiles: solid sky colour

Also fix tile_id_to_tileset_index to include sky (id=0) as index 0,
so sky tiles render correctly as the fade target.
This commit is contained in:
2026-03-20 14:27:24 +00:00
parent 6fbfb10e48
commit fc47e719d7
+47 -25
View File
@@ -69,7 +69,7 @@ pub const FIXTURE_ROW_OFFSET: u16 = 6;
fn tile_id_to_tileset_index(tile_id: u32) -> Option<u16> {
if tile_id == 0 {
return None;
return Some(0);
}
if tile_id <= 5 {
return Some(tile_id as u16);
@@ -82,22 +82,44 @@ fn tile_id_to_tileset_index(tile_id: u32) -> Option<u16> {
}
}
fn df_fade_color(z_diff: i32) -> Color {
fn tile_for_depth(real_index: u16, z_diff: i32) -> TileData {
const SKY_R: f32 = 133_f32 / 255_f32;
const SKY_G: f32 = 167_f32 / 255_f32;
const SKY_B: f32 = 178_f32 / 255_f32;
const LAYER_ALPHA: f32 = 70_f32 / 255_f32;
if z_diff <= 0 {
return Color::WHITE;
return TileData {
tileset_index: real_index,
color: Color::WHITE,
visible: true,
};
}
let n = (z_diff as f32).min(8_f32);
let overlay_r = 133_f32 / 255_f32;
let overlay_g = 167_f32 / 255_f32;
let overlay_b = 178_f32 / 255_f32;
let layer_alpha = 41_f32 / 255_f32;
let acc_alpha = 1_f32 - (1_f32 - layer_alpha).powf(n);
let inv = 1_f32 - acc_alpha;
Color::srgb(
overlay_r * acc_alpha + inv,
overlay_g * acc_alpha + inv,
overlay_b * acc_alpha + inv,
)
let t = 1_f32 - (1_f32 - LAYER_ALPHA).powf(n);
if t >= 0.98 {
return TileData {
tileset_index: 0,
color: Color::srgb(SKY_R, SKY_G, SKY_B),
visible: true,
};
}
if t < 0.5 {
TileData {
tileset_index: real_index,
color: Color::srgba(1_f32, 1_f32, 1_f32, 1_f32 - t * 2_f32),
visible: true,
}
} else {
TileData {
tileset_index: 0,
color: Color::srgba(SKY_R, SKY_G, SKY_B, (t - 0.5_f32) * 2_f32),
visible: true,
}
}
}
fn is_tile_visible_at_z(tile_data: &FloorTileData, z_index: usize) -> bool {
@@ -134,19 +156,19 @@ fn populate_chunk_tiles(
);
let tile = tilemap.get_floor(&world_pos);
match tile {
Some(t) if tile_id_to_tileset_index(t.id as u32).is_some() => {
let visible = is_tile_visible_at_z(t, z_index);
let color = if visible {
df_fade_color(z_diff)
Some(t) => {
let idx = tile_id_to_tileset_index(t.id as u32);
if let Some(tileset_idx) = idx {
let is_visible = is_tile_visible_at_z(t, z_index);
let tile_data = if is_visible {
tile_for_depth(tileset_idx, z_diff)
} else {
Color::BLACK
tile_for_depth(0, 999)
};
let tileset_idx = tile_id_to_tileset_index(t.id as u32).unwrap();
tiles.push(Some(TileData {
tileset_index: tileset_idx,
color,
visible,
}));
tiles.push(Some(tile_data));
} else {
tiles.push(None);
}
}
_ => tiles.push(None),
}