Imp in 64x64 when close, 32x32 at normal zoom; detailed sprites in their own texture

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-07 21:17:17 +01:00
1 parent 2d1ed177a7
commit 69a6b13006
9 files changed
+173 -89

No files matched your search

+16 -10
View File
@@ -1563,8 +1563,9 @@ impl R3d {
// sprites as billboards
// the world's pixel rows (detailed sprites only where they get enough pixels)
let world_rows = pix.map_or(screen_height() * screen_dpi_scale(), |(_, th, _)| th as f32);
if let Some(mesh) = self.billboards(g, gfx, cam, t, world_rows) {
draw_mesh(&mesh);
let (small, detailed) = self.billboards(g, gfx, cam, t, world_rows);
for mesh in [small, detailed].iter().flatten() {
draw_mesh(mesh);
}
// solid unlit objects (default material, depth tested)
gl_use_default_material();
@@ -1638,7 +1639,8 @@ impl R3d {
self.draw_2d(g, gfx, cam, &m, t);
}
fn billboards(&self, g: &Game, gfx: &Gfx, cam: &Cam, t: f32, world_rows: f32) -> Option<Mesh> {
// the units as billboards: the 10x10 sprites and the detailed ones (two textures)
fn billboards(&self, g: &Game, gfx: &Gfx, cam: &Cam, t: f32, world_rows: f32) -> (Option<Mesh>, Option<Mesh>) {
let (_, r, _) = cam.basis();
let toward = cam.eye_dir();
let amb = |x: f32, z: f32| {
@@ -1656,6 +1658,7 @@ impl R3d {
let rg = vec2(r.x, r.z).normalize_or_zero();
let tg = vec2(toward.x, toward.z).normalize_or_zero();
let mut mb = MB::new();
let mut mb_hd = MB::new();
let sw = SPRITE_TEX_W;
let sh = SPRITE_TEX_H;
// detailed sprites only in the high-res style, and only where a sprite's cell (1.2 sizes
@@ -1761,19 +1764,24 @@ impl R3d {
}
let white = e.flash > 0.07;
let v = if e.captive != 0 { 0 } else { view };
let detailed = hd && w * 1.2 * px_per_tile >= crate::gfx::ACELL as f32 * 0.85;
// screen pixels of the cell per texel of a detailed cell (64x64 level), the 32x32
// level has two texels per pixel
let texel = w * 1.2 * px_per_tile / crate::gfx::HD_CELL as f32;
let detailed = hd && texel * 2.0 >= 0.85;
let fine = texel >= 0.85;
// treasure in a sack on the back; digging as a drawn animation (detailed sprites),
// frame by frame with the same rhythm as the swing below
let sack = e.carry > 0 && Gfx::has_sack(e.kind);
let hacking = e.working && !e.moving && !sleeping && matches!(e.job, Job::Dig(_) | Job::TearBridge(_));
let frame = ((ph * 1.3 / std::f32::consts::TAU).rem_euclid(1.0) * crate::gfx::HACK_FRAMES as f32) as u32;
let hd = if detailed { Gfx::hd_cell_view(e.kind, white, v, hacking.then_some(frame), sack) } else { None };
let hd = if detailed { Gfx::hd_cell_view(e.kind, white, v, hacking.then_some(frame), sack, fine) } else { None };
if hd.is_some() && hacking {
// the frames swing the pickaxe: no tilting of the whole figure
rot = 0.0;
lunge = 0.0;
}
let src = hd.or_else(|| sack.then(|| Gfx::sprite_cell_sack(e.kind, white, e.level, v)).flatten()).unwrap_or_else(|| Gfx::sprite_cell_view(e.kind, white, e.level, v));
let (sw, sh) = if hd.is_some() { (crate::gfx::HD_TEX_W, crate::gfx::HD_TEX_H) } else { (sw, sh) };
let (mut u0, v0) = (src.x / sw, src.y / sh);
let (mut u1, v1) = ((src.x + src.w) / sw, (src.y + src.h) / sh);
if mirror {
@@ -1813,6 +1821,7 @@ impl R3d {
};
// the 12x12 cell (sprite with a one pixel border for the gear): the sprite's feet
// (bottom of its 11th pixel row) stay on the ground
let mb = if hd.is_some() { &mut mb_hd } else { &mut mb };
mb.quad(
[corner(-w * 0.6, h * 1.1), corner(w * 0.6, h * 1.1), corner(w * 0.6, -h * 0.1), corner(-w * 0.6, -h * 0.1)],
[vec2(u0, v0), vec2(u1, v0), vec2(u1, v1), vec2(u0, v1)],
@@ -1820,11 +1829,8 @@ impl R3d {
[toward; 4],
);
}
if mb.v.is_empty() {
None
} else {
Some(Mesh { vertices: mb.v, indices: mb.i, texture: Some(gfx.sprites.clone()) })
}
let mesh = |mb: MB, tex: &Texture2D| if mb.v.is_empty() { None } else { Some(Mesh { vertices: mb.v, indices: mb.i, texture: Some(tex.clone()) }) };
(mesh(mb, &gfx.sprites), mesh(mb_hd, &gfx.hd_sprites))
}
fn draw_2d(&self, g: &Game, gfx: &Gfx, cam: &Cam, m: &Mat4, t: f32) {