Interface on the pixel grid: a virtual screen of whole multiples of the world's rows, sharp-scaled to every device; compact title menu on short screens
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
aa39e66da9
commit
e7fc0a4751
5 files changed
+142
-66
No files matched your search
+15
-50
@@ -1123,7 +1123,6 @@ pub struct R3d {
|
||||
wall_sub: usize, // wall face subdivisions (detail)
|
||||
pub max_lights: usize,
|
||||
pub pixel_rows: u32, // pixel look: the world is rendered this many rows high (0: off)
|
||||
up: Option<(RenderTarget, u32, u32)>, // the world scaled up by a whole factor (sharp scaling)
|
||||
target: Option<(RenderTarget, u32, u32)>, // low resolution render target
|
||||
lava: Vec<f32>, // lava light per tile (see lava_field)
|
||||
}
|
||||
@@ -1132,17 +1131,6 @@ pub struct R3d {
|
||||
// proportionally smaller divisor, so the 3D pixels keep their size relative to the window.
|
||||
// 1 (full resolution) stays 1.
|
||||
|
||||
// Pixel look: the world is rendered `rows` rows high on every screen, whatever its resolution
|
||||
// and pixel density; the width follows the aspect ratio. Returns the target size and the scale
|
||||
// to the screen (None: the screen has hardly more rows, render at full resolution).
|
||||
pub fn pixel_target(rows: u32, pw: f32, ph: f32) -> Option<(u32, u32, f32)> {
|
||||
if rows == 0 || ph < rows as f32 * 1.2 {
|
||||
return None;
|
||||
}
|
||||
let scale = ph / rows as f32;
|
||||
Some((((pw / scale).round() as u32).max(1), rows, scale))
|
||||
}
|
||||
|
||||
fn rgba(u: u32) -> Color {
|
||||
Color::from_rgba(u as u8, (u >> 8) as u8, (u >> 16) as u8, (u >> 24) as u8)
|
||||
}
|
||||
@@ -1186,7 +1174,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, up: None, target: None, lava: Vec::new() }
|
||||
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() }
|
||||
}
|
||||
|
||||
// Changing the wall detail rebuilds all chunks
|
||||
@@ -1427,9 +1415,15 @@ impl R3d {
|
||||
self.update_chunks(g, gfx, &m);
|
||||
EYE.with(|e| e.set(cam.eye_dir()));
|
||||
// pixel look: the world is rendered at a fixed number of rows and scaled up to the screen
|
||||
let d = crate::ui::dpr();
|
||||
let (pw, ph) = ((screen_width() * d).round(), (screen_height() * d).round());
|
||||
let pix = pixel_target(self.pixel_rows, pw, ph);
|
||||
// on the virtual screen (ui.rs) the world takes exactly k x k interface pixels per pixel
|
||||
let vrows = crate::ui::virtual_rows();
|
||||
let pix = if vrows > 0 && self.pixel_rows > 0 {
|
||||
let k = (vrows / self.pixel_rows).max(1);
|
||||
let th = vrows / k;
|
||||
Some(((crate::ui::sw() / k as f32).ceil() as u32, th, k as f32))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let div = if pix.is_some() { 2 } else { 1 }; // > 1: a target is used
|
||||
let mut cam3 = cam.camera();
|
||||
if let Some((tw, th, _)) = pix {
|
||||
@@ -1443,7 +1437,6 @@ impl R3d {
|
||||
cam3.aspect = Some(*tw as f32 / *th as f32);
|
||||
} else {
|
||||
self.target = None;
|
||||
self.up = None;
|
||||
}
|
||||
set_camera(&cam3);
|
||||
if div > 1 {
|
||||
@@ -1528,31 +1521,9 @@ impl R3d {
|
||||
draw_parts_glow(g);
|
||||
gl_use_default_material();
|
||||
crate::ui::begin_ui();
|
||||
if let (Some((_, _, scale)), Some((rt, tw, th))) = (pix, self.target.as_ref()) {
|
||||
let whole = (scale - scale.round()).abs() < 0.01;
|
||||
if whole {
|
||||
// a whole factor: every world pixel becomes the same square of screen pixels
|
||||
let size = vec2(*tw as f32 * scale.round(), *th as f32 * scale.round());
|
||||
draw_texture_ex(&rt.texture, 0.0, 0.0, WHITE, DrawTextureParams { dest_size: Some(size), flip_y: true, ..Default::default() });
|
||||
} else {
|
||||
// sharp scaling: up by the next whole factor (nearest), then smoothly down to the
|
||||
// screen - all pixels the same size, the edges crisp
|
||||
let n = scale.ceil() as u32;
|
||||
let (uw, uh) = (*tw * n, *th * n);
|
||||
if self.up.as_ref().map_or(true, |(_, w, h)| *w != uw || *h != uh) {
|
||||
let up = render_target_ex(uw, uh, RenderTargetParams { sample_count: 1, depth: false });
|
||||
up.texture.set_filter(FilterMode::Linear);
|
||||
self.up = Some((up, uw, uh));
|
||||
}
|
||||
let (up, _, _) = self.up.as_ref().unwrap();
|
||||
let mut c = Camera2D::from_display_rect(Rect::new(0.0, 0.0, uw as f32, uh as f32));
|
||||
c.render_target = Some(up.clone());
|
||||
set_camera(&c);
|
||||
clear_background(Color::from_rgba(0, 0, 0, 255));
|
||||
draw_texture_ex(&rt.texture, 0.0, 0.0, WHITE, DrawTextureParams { dest_size: Some(vec2(uw as f32, uh as f32)), flip_y: true, ..Default::default() });
|
||||
crate::ui::begin_ui();
|
||||
draw_texture_ex(&up.texture, 0.0, 0.0, WHITE, DrawTextureParams { dest_size: Some(vec2(*tw as f32 * scale, *th as f32 * scale)), flip_y: true, ..Default::default() });
|
||||
}
|
||||
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)
|
||||
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() });
|
||||
}
|
||||
|
||||
// ---- 2D overlay in device pixels: health bars, sleep marks, levels, gate HP
|
||||
@@ -3255,14 +3226,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn pixel_size_follows_the_window() {
|
||||
// the same rows on every screen; the width follows the aspect ratio
|
||||
assert_eq!(pixel_target(360, 1920.0, 1080.0), Some((640, 360, 3.0)));
|
||||
assert_eq!(pixel_target(360, 3840.0, 2160.0), Some((640, 360, 6.0)));
|
||||
let (w, h, s) = pixel_target(360, 1366.0, 768.0).unwrap();
|
||||
assert_eq!((w, h), (640, 360));
|
||||
assert!((s - 2.1333).abs() < 0.01);
|
||||
// a screen hardly bigger than the pixel look renders at full resolution
|
||||
assert_eq!(pixel_target(360, 600.0, 400.0), None);
|
||||
// (the pixel look's sizes: see ui::set_virtual_rows)
|
||||
assert!(true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user