Tile outlines on floors, wall tops and wall corners (toggle with G)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
220d9543cc
commit
a101f6ddc4
4 files changed
+75
-6
No files matched your search
+70
-5
@@ -319,6 +319,25 @@ impl MB {
|
||||
);
|
||||
}
|
||||
}
|
||||
// Thin strip lying on a surface (normal n) from p to q, used for tile outlines
|
||||
fn strip(&mut self, p: Vec3, q: Vec3, n: Vec3, w: f32, c: [u8; 4]) {
|
||||
let side = (q - p).cross(n).normalize_or_zero() * (w * 0.5);
|
||||
let o = n * 0.006;
|
||||
self.quad([p - side + o, q - side + o, q + side + o, p + side + o], [Vec2::ZERO; 4], [c; 4], [n; 4]);
|
||||
}
|
||||
// Polyline along displaced points
|
||||
fn polyline(&mut self, pts: &[Vec3], n: Vec3, w: f32, c: [u8; 4]) {
|
||||
for k in 0..pts.len().saturating_sub(1) {
|
||||
self.strip(pts[k], pts[k + 1], n, w, c);
|
||||
}
|
||||
}
|
||||
fn into_plain_mesh(self) -> Option<Mesh> {
|
||||
if self.v.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Mesh { vertices: self.v, indices: self.i, texture: None })
|
||||
}
|
||||
}
|
||||
fn into_mesh(self, tex: &Texture2D) -> Option<Mesh> {
|
||||
if self.v.is_empty() {
|
||||
None
|
||||
@@ -379,9 +398,23 @@ fn solid_at(map: &Map, x: i32, z: i32) -> bool {
|
||||
map.get(x, z).map_or(true, |t| t.solid())
|
||||
}
|
||||
|
||||
fn build_chunk(map: &Map, amb: &[f32], cx: i32, cz: i32, gold_fill: f32, atlas: &Texture2D) -> (Option<Mesh>, Option<Mesh>) {
|
||||
const OUTLINE_W: f32 = 0.035;
|
||||
const OUTLINE_C: [u8; 4] = [8, 5, 6, 150];
|
||||
|
||||
// Displaced points along a straight edge (same displacement as the wall grids -> lines follow the surface)
|
||||
fn edge_pts(a: Vec3, b: Vec3, n: usize) -> Vec<Vec3> {
|
||||
(0..=n)
|
||||
.map(|k| {
|
||||
let p = a.lerp(b, k as f32 / n as f32);
|
||||
p + displace(p)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn build_chunk(map: &Map, amb: &[f32], cx: i32, cz: i32, gold_fill: f32, atlas: &Texture2D) -> (Option<Mesh>, Option<Mesh>, Option<Mesh>) {
|
||||
let mut mb = MB::new();
|
||||
let mut ov = MB::new();
|
||||
let mut ln = MB::new();
|
||||
let ld = LIGHT_DIR.normalize();
|
||||
for z in cz * CHUNK..(cz + 1) * CHUNK {
|
||||
for x in cx * CHUNK..(cx + 1) * CHUNK {
|
||||
@@ -406,6 +439,13 @@ fn build_chunk(map: &Map, amb: &[f32], cx: i32, cz: i32, gold_fill: f32, atlas:
|
||||
c,
|
||||
[Vec3::Y; 4],
|
||||
);
|
||||
// outlines: north and west edge, only between two open tiles (each edge once)
|
||||
if !solid_at(map, x, z - 1) {
|
||||
ln.strip(vec3(xf, 0.0, zf), vec3(xf + 1.0, 0.0, zf), Vec3::Y, OUTLINE_W, OUTLINE_C);
|
||||
}
|
||||
if !solid_at(map, x - 1, z) {
|
||||
ln.strip(vec3(xf, 0.0, zf), vec3(xf, 0.0, zf + 1.0), Vec3::Y, OUTLINE_W, OUTLINE_C);
|
||||
}
|
||||
// room decor
|
||||
let dc = col(Vec3::splat(amb_at(amb, xf + 0.5, zf + 0.5)), 1.0);
|
||||
match t.kind {
|
||||
@@ -455,6 +495,19 @@ fn build_chunk(map: &Map, amb: &[f32], cx: i32, cz: i32, gold_fill: f32, atlas:
|
||||
(ua, ub),
|
||||
|_p, nrm| Vec3::splat(top_amb * (0.75 + 0.25 * nrm.dot(ld).max(0.0))),
|
||||
);
|
||||
// outlines on the wall top: north/west always, south/east where no wall continues
|
||||
let tl = vec3(xf, WALL_H, zf);
|
||||
let tr = vec3(xf + 1.0, WALL_H, zf);
|
||||
let br = vec3(xf + 1.0, WALL_H, zf + 1.0);
|
||||
let bl = vec3(xf, WALL_H, zf + 1.0);
|
||||
ln.polyline(&edge_pts(tl, tr, n), Vec3::Y, OUTLINE_W, OUTLINE_C);
|
||||
ln.polyline(&edge_pts(tl, bl, n), Vec3::Y, OUTLINE_W, OUTLINE_C);
|
||||
if !solid_at(map, x, z + 1) {
|
||||
ln.polyline(&edge_pts(bl, br, n), Vec3::Y, OUTLINE_W, OUTLINE_C);
|
||||
}
|
||||
if !solid_at(map, x + 1, z) {
|
||||
ln.polyline(&edge_pts(tr, br, n), Vec3::Y, OUTLINE_W, OUTLINE_C);
|
||||
}
|
||||
if t.marked {
|
||||
let (a, b) = cell_uv(T_MARK);
|
||||
let y = WALL_H + 0.12;
|
||||
@@ -478,6 +531,10 @@ fn build_chunk(map: &Map, amb: &[f32], cx: i32, cz: i32, gold_fill: f32, atlas:
|
||||
_ => (vec3(xf, 0.0, zf), vec3(xf, 0.0, zf + 1.0)), // west
|
||||
};
|
||||
let out = vec3(dx as f32, 0.0, dz as f32);
|
||||
// vertical outlines at both ends of the exposed face (tile borders and corners)
|
||||
for end in [a, b] {
|
||||
ln.polyline(&edge_pts(end, end + vec3(0.0, WALL_H, 0.0), n), out, OUTLINE_W, OUTLINE_C);
|
||||
}
|
||||
build_grid(
|
||||
&mut mb,
|
||||
|u, v| a + (b - a) * u + vec3(0.0, WALL_H * (1.0 - v), 0.0),
|
||||
@@ -492,7 +549,7 @@ fn build_chunk(map: &Map, amb: &[f32], cx: i32, cz: i32, gold_fill: f32, atlas:
|
||||
}
|
||||
}
|
||||
}
|
||||
(mb.into_mesh(atlas), ov.into_mesh(atlas))
|
||||
(mb.into_mesh(atlas), ov.into_mesh(atlas), ln.into_plain_mesh())
|
||||
}
|
||||
|
||||
// Subdivided, displaced face. pos(u, v) gives the undisplaced point (u, v in 0..1).
|
||||
@@ -542,6 +599,7 @@ struct Chunk {
|
||||
sig: u64,
|
||||
mesh: Option<Mesh>,
|
||||
overlay: Option<Mesh>,
|
||||
lines: Option<Mesh>,
|
||||
}
|
||||
|
||||
pub struct Overlay {
|
||||
@@ -556,6 +614,7 @@ pub struct R3d {
|
||||
lit: Material,
|
||||
glow: Material,
|
||||
chunks: Vec<Chunk>,
|
||||
pub outlines: bool, // tile outlines on/off
|
||||
}
|
||||
|
||||
fn rgba(u: u32) -> Color {
|
||||
@@ -585,8 +644,8 @@ fn chunk_sig(map: &Map, cx: i32, cz: i32, fill_bucket: u8) -> u64 {
|
||||
|
||||
impl R3d {
|
||||
pub fn new() -> R3d {
|
||||
let chunks = (0..NCH * NCH).map(|_| Chunk { sig: 0, mesh: None, overlay: None }).collect();
|
||||
R3d { lit: lit_material(), glow: glow_material(), chunks }
|
||||
let chunks = (0..NCH * NCH).map(|_| Chunk { sig: 0, mesh: None, overlay: None, lines: None }).collect();
|
||||
R3d { lit: lit_material(), glow: glow_material(), chunks, outlines: true }
|
||||
}
|
||||
|
||||
fn update_chunks(&mut self, g: &Game, gfx: &Gfx) {
|
||||
@@ -599,9 +658,10 @@ impl R3d {
|
||||
let ch = &mut self.chunks[(cz * NCH + cx) as usize];
|
||||
if ch.sig != sig {
|
||||
let a = amb.get_or_insert_with(|| ambient_field(&g.map));
|
||||
let (m, o) = build_chunk(&g.map, a, cx, cz, bucket as f32 / 6.0, &gfx.atlas);
|
||||
let (m, o, l) = build_chunk(&g.map, a, cx, cz, bucket as f32 / 6.0, &gfx.atlas);
|
||||
ch.mesh = m;
|
||||
ch.overlay = o;
|
||||
ch.lines = l;
|
||||
ch.sig = sig;
|
||||
}
|
||||
}
|
||||
@@ -725,6 +785,11 @@ impl R3d {
|
||||
// ---- unlit glow / overlays
|
||||
gl_use_material(&self.glow);
|
||||
for c in &self.chunks {
|
||||
if self.outlines {
|
||||
if let Some(l) = &c.lines {
|
||||
draw_mesh(l);
|
||||
}
|
||||
}
|
||||
if let Some(o) = &c.overlay {
|
||||
draw_mesh(o);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user