Guard and attack markers (shields and swords, up to eight each, right click removes); the world and the interface are copied opaque so glows keep their brightness
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a1a53273cd
commit
c9dafb1606
24 files changed
+470
-46
No files matched your search
+81
-1
@@ -312,6 +312,35 @@ fn lit_material() -> Material {
|
||||
}
|
||||
|
||||
// Unlit, alpha-blended material for glows, shadows and effects
|
||||
// the world target onto the virtual screen: fully opaque. Translucent glows (flames, the heart)
|
||||
// leave the target's alpha below one; blended, the black behind would shine through and dim them.
|
||||
pub(crate) fn opaque_material() -> Material {
|
||||
const V: &str = r#"#version 100
|
||||
attribute vec3 position;
|
||||
attribute vec2 texcoord;
|
||||
attribute vec4 color0;
|
||||
varying lowp vec2 uv;
|
||||
varying lowp vec4 color;
|
||||
uniform mat4 Model;
|
||||
uniform mat4 Projection;
|
||||
void main() {
|
||||
gl_Position = Projection * Model * vec4(position, 1.0);
|
||||
color = color0 / 255.0;
|
||||
uv = texcoord;
|
||||
}
|
||||
"#;
|
||||
const F: &str = r#"#version 100
|
||||
precision mediump float;
|
||||
varying lowp vec4 color;
|
||||
varying lowp vec2 uv;
|
||||
uniform sampler2D Texture;
|
||||
void main() {
|
||||
gl_FragColor = vec4(color.rgb * texture2D(Texture, uv).rgb, 1.0);
|
||||
}
|
||||
"#;
|
||||
load_material(ShaderSource::Glsl { vertex: V, fragment: F }, MaterialParams { pipeline_params: PipelineParams::default(), uniforms: vec![], textures: vec![] }).expect("opaque material")
|
||||
}
|
||||
|
||||
fn glow_material() -> Material {
|
||||
const V: &str = r#"#version 100
|
||||
attribute vec3 position;
|
||||
@@ -1122,6 +1151,7 @@ pub struct R3d {
|
||||
pub outlines: bool, // tile outlines on/off
|
||||
wall_sub: usize, // wall face subdivisions (detail)
|
||||
pub max_lights: usize,
|
||||
opaque: Material, // the world target onto the screen without blending
|
||||
pub pixel_rows: u32, // pixel look: the world is rendered this many rows high (0: off)
|
||||
target: Option<(RenderTarget, u32, u32)>, // low resolution render target
|
||||
lava: Vec<f32>, // lava light per tile (see lava_field)
|
||||
@@ -1174,7 +1204,7 @@ fn chunk_sig(map: &Map, cx: i32, cz: i32) -> u64 {
|
||||
|
||||
impl R3d {
|
||||
pub fn new() -> R3d {
|
||||
R3d { lit: lit_material(), glow: glow_material(), chunks: Vec::new(), ncx: 0, ncz: 0, outlines: true, wall_sub: 3, max_lights: MAX_LIGHTS, pixel_rows: 360, target: None, lava: Vec::new() }
|
||||
R3d { lit: lit_material(), glow: glow_material(), opaque: opaque_material(), chunks: Vec::new(), ncx: 0, ncz: 0, outlines: true, wall_sub: 3, max_lights: MAX_LIGHTS, pixel_rows: 360, target: None, lava: Vec::new() }
|
||||
}
|
||||
|
||||
// Changing the wall detail rebuilds all chunks
|
||||
@@ -1505,6 +1535,12 @@ impl R3d {
|
||||
if let Some(f) = g.flag {
|
||||
draw_flag(f, t);
|
||||
}
|
||||
for &m in &g.guard_marks {
|
||||
draw_shield_mark(m, t);
|
||||
}
|
||||
for &m in &g.attack_marks {
|
||||
draw_sword_mark(m, t);
|
||||
}
|
||||
draw_marks(g, t);
|
||||
draw_overlay(&g.map, ov, self.wall_sub);
|
||||
draw_entry_warnings(g, t, self.wall_sub);
|
||||
@@ -1523,7 +1559,9 @@ impl R3d {
|
||||
crate::ui::begin_ui();
|
||||
if let (Some((_, _, k)), Some((rt, tw, th))) = (pix, self.target.as_ref()) {
|
||||
// the world onto the virtual screen, every pixel k x k (scaled to the device at the end)
|
||||
gl_use_material(&self.opaque);
|
||||
draw_texture_ex(&rt.texture, 0.0, 0.0, WHITE, DrawTextureParams { dest_size: Some(vec2(*tw as f32 * k, *th as f32 * k)), flip_y: true, ..Default::default() });
|
||||
gl_use_default_material();
|
||||
}
|
||||
|
||||
// ---- 2D overlay in device pixels: health bars, sleep marks, levels, gate HP
|
||||
@@ -2569,6 +2607,48 @@ fn draw_flag(f: usize, t: f32) {
|
||||
draw_mesh(&Mesh { vertices: v, indices: vec![0, 1, 2], texture: None });
|
||||
}
|
||||
|
||||
// a flat polygon in a vertical plane (x along `right`, y up) around `base`
|
||||
fn draw_plate(base: Vec3, right: Vec3, pts: &[(f32, f32)], c: [u8; 4]) {
|
||||
let v: Vec<Vertex> = pts.iter().map(|&(x, y)| Vertex { position: base + right * x + Vec3::Y * y, uv: Vec2::ZERO, color: c, normal: Vec4::Y }).collect();
|
||||
let mut idx = Vec::new();
|
||||
for k in 1..pts.len() as u16 - 1 {
|
||||
idx.extend([0, k, k + 1]);
|
||||
}
|
||||
draw_mesh(&Mesh { vertices: v, indices: idx, texture: None });
|
||||
}
|
||||
|
||||
// guard marker: a shield on a short pole, gently bobbing
|
||||
fn draw_shield_mark(m: usize, t: f32) {
|
||||
let (x, z) = xy(m);
|
||||
let base = vec3(x as f32 + 0.5, 0.0, z as f32 + 0.5);
|
||||
draw_cube(base + vec3(0.0, 0.45, 0.0), vec3(0.05, 0.9, 0.05), None, Color::from_rgba(120, 90, 60, 255));
|
||||
let bob = (t * 2.0 + m as f32).sin() * 0.03;
|
||||
let c = base + vec3(0.0, 0.95 + bob, 0.0);
|
||||
let right = vec3(0.7071, 0.0, -0.7071);
|
||||
let outline: [(f32, f32); 7] = [(-0.26, 0.24), (0.26, 0.24), (0.26, 0.02), (0.18, -0.16), (0.0, -0.3), (-0.18, -0.16), (-0.26, 0.02)];
|
||||
// the rim, the face and a cross (both sides, so it shows from every angle)
|
||||
for (r, off) in [(right, 0.0f32), (-right, 0.01)] {
|
||||
let at = c + vec3(0.0, 0.0, 0.0) + right.cross(Vec3::Y) * off;
|
||||
draw_plate(at, r, &outline, [230, 190, 70, 255]);
|
||||
let inner: Vec<(f32, f32)> = outline.iter().map(|&(a, b)| (a * 0.8, b * 0.8 + 0.01)).collect();
|
||||
draw_plate(at + right.cross(Vec3::Y) * 0.004, r, &inner, [50, 80, 170, 255]);
|
||||
draw_plate(at + right.cross(Vec3::Y) * 0.008, r, &[(-0.03, 0.18), (0.03, 0.18), (0.03, -0.2), (-0.03, -0.2)], [230, 190, 70, 255]);
|
||||
draw_plate(at + right.cross(Vec3::Y) * 0.008, r, &[(-0.16, 0.06), (0.16, 0.06), (0.16, 0.0), (-0.16, 0.0)], [230, 190, 70, 255]);
|
||||
}
|
||||
}
|
||||
|
||||
// attack marker: a sword stuck in the ground, its blade glinting
|
||||
fn draw_sword_mark(m: usize, t: f32) {
|
||||
let (x, z) = xy(m);
|
||||
let base = vec3(x as f32 + 0.5, 0.0, z as f32 + 0.5);
|
||||
let glint = 200 + ((t * 3.0 + m as f32).sin() * 40.0) as i32;
|
||||
let blade = Color::from_rgba(glint.clamp(0, 255) as u8, glint.clamp(0, 255) as u8, (glint + 15).clamp(0, 255) as u8, 255);
|
||||
draw_cube(base + vec3(0.0, 0.4, 0.0), vec3(0.07, 0.8, 0.02), None, blade);
|
||||
draw_cube(base + vec3(0.0, 0.82, 0.0), vec3(0.34, 0.05, 0.06), None, Color::from_rgba(150, 120, 50, 255));
|
||||
draw_cube(base + vec3(0.0, 0.98, 0.0), vec3(0.05, 0.26, 0.05), None, Color::from_rgba(170, 30, 30, 255));
|
||||
draw_cube(base + vec3(0.0, 1.13, 0.0), vec3(0.08, 0.06, 0.08), None, Color::from_rgba(230, 190, 70, 255));
|
||||
}
|
||||
|
||||
fn mark_color(kind: u8) -> Color {
|
||||
match kind {
|
||||
MARK_DIG => Color::new(0.45, 0.95, 0.55, 1.0),
|
||||
|
||||
Reference in new issue
Block a user