High-res tiles also in 128x128 for close views
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8197b07ac5
commit
9df16607ed
24 files changed
+83
-41
No files matched your search
+48
-39
@@ -5,7 +5,7 @@ use crate::map::{Kind, Owner};
|
||||
use macroquad::prelude::*;
|
||||
|
||||
pub const CELL: f32 = 16.0;
|
||||
const ATLAS_COLS: u32 = 16;
|
||||
pub const ATLAS_COLS: u32 = 16;
|
||||
pub const ATLAS_ROWS: u32 = 14;
|
||||
|
||||
// atlas indices (4 variants each)
|
||||
@@ -99,7 +99,8 @@ pub struct Gfx {
|
||||
pub atlas: Texture2D,
|
||||
pub sprites: Texture2D,
|
||||
pub hd_sprites: Texture2D, // detailed sprites (see HD_SPRITES, hd_cell_view)
|
||||
pub atlas_hd: Texture2D, // the tile atlas of the high-res style (see HD_TILES)
|
||||
pub atlas_hd: Texture2D, // the tile atlas of the high-res style, 64x64 tiles (see HD_TILES)
|
||||
pub atlas_hd2: Texture2D, // the same with 128x128 tiles (close up)
|
||||
pub cursors: Texture2D, // mouse pointer frames, 16x16 each (see CURSOR_*)
|
||||
pub badges: Texture2D, // achievement badges, 32x32 each (see badges.rs)
|
||||
pub font: Texture2D, // Dinowyde (glyphs of 6x8 px ordered by Unicode, see font_slot) and DINOBYTE
|
||||
@@ -327,46 +328,49 @@ fn earth_px(x: i32, y: i32, v: u32) -> Color {
|
||||
}
|
||||
|
||||
// ---- high-res tiles
|
||||
// The high-res style's atlas: the same cells as the 16x16 atlas, HD_TILE x HD_TILE texels each.
|
||||
// Cells without an own texture are the 16x16 ones scaled up. HD_TILES: generated textures (see
|
||||
// art/generated/textures/), each a seamless 2x2 block of tiles for the four variants of a kind
|
||||
// (variant k = quarter k % 2, k / 2); the world lays the quarters out by the tiles' positions
|
||||
// (see hd_tile), so a floor repeats only every two tiles and has no seams.
|
||||
// The high-res style's atlases: the same cells as the 16x16 atlas, HD_TILE (64) or HD_TILE2 (128)
|
||||
// texels each; the world shows the 128 one close up, where a tile gets that many pixels (two
|
||||
// levels like the sprites: neither loses pixels nor flickers). Cells without an own texture are
|
||||
// the 16x16 ones scaled up. HD_TILES: generated textures (see art/generated/textures/), each a
|
||||
// seamless 2x2 block of tiles for the four variants of a kind (variant k = quarter k % 2, k / 2);
|
||||
// the world lays the quarters out by the tiles' positions (see hd_tile), so a floor repeats only
|
||||
// every two tiles and has no seams.
|
||||
pub const HD_TILE: u32 = 64;
|
||||
pub const ATLAS_HD_W: f32 = (ATLAS_COLS * HD_TILE) as f32;
|
||||
pub const ATLAS_HD_H: f32 = (ATLAS_ROWS * HD_TILE) as f32;
|
||||
const HD_TILES: [(u32, &[u8]); 7] = [
|
||||
(T_FLOOR, include_bytes!("../assets/textures/floor.png")),
|
||||
(T_CLAIM, include_bytes!("../assets/textures/claimed.png")),
|
||||
(T_EARTH, include_bytes!("../assets/textures/earth.png")),
|
||||
(T_ROCK, include_bytes!("../assets/textures/rock.png")),
|
||||
(T_GOLD, include_bytes!("../assets/textures/gold.png")),
|
||||
(T_WATER, include_bytes!("../assets/textures/water.png")),
|
||||
(T_LAVA, include_bytes!("../assets/textures/lava.png")),
|
||||
pub const HD_TILE2: u32 = 128;
|
||||
const HD_TILES: [(u32, &[u8], &[u8]); 7] = [
|
||||
(T_FLOOR, include_bytes!("../assets/textures/floor.png"), include_bytes!("../assets/textures/floor-256.png")),
|
||||
(T_CLAIM, include_bytes!("../assets/textures/claimed.png"), include_bytes!("../assets/textures/claimed-256.png")),
|
||||
(T_EARTH, include_bytes!("../assets/textures/earth.png"), include_bytes!("../assets/textures/earth-256.png")),
|
||||
(T_ROCK, include_bytes!("../assets/textures/rock.png"), include_bytes!("../assets/textures/rock-256.png")),
|
||||
(T_GOLD, include_bytes!("../assets/textures/gold.png"), include_bytes!("../assets/textures/gold-256.png")),
|
||||
(T_WATER, include_bytes!("../assets/textures/water.png"), include_bytes!("../assets/textures/water-256.png")),
|
||||
(T_LAVA, include_bytes!("../assets/textures/lava.png"), include_bytes!("../assets/textures/lava-256.png")),
|
||||
];
|
||||
|
||||
// whether a cell has a generated high-res texture (its variants are laid out by position)
|
||||
pub fn hd_tile(id: u32) -> bool {
|
||||
HD_TILES.iter().any(|&(base, _)| id / 4 * 4 == base)
|
||||
HD_TILES.iter().any(|&(base, _, _)| id / 4 * 4 == base)
|
||||
}
|
||||
|
||||
fn gen_hd_atlas() -> Image {
|
||||
// a high-res atlas with `tile` x `tile` texel cells (HD_TILE or HD_TILE2)
|
||||
fn gen_hd_atlas(tile: u32) -> Image {
|
||||
let small = gen_atlas();
|
||||
let k = HD_TILE / 16;
|
||||
let mut img = Image::gen_image_color(ATLAS_HD_W as u16, ATLAS_HD_H as u16, Color::new(0.0, 0.0, 0.0, 0.0));
|
||||
for y in 0..ATLAS_HD_H as u32 {
|
||||
for x in 0..ATLAS_HD_W as u32 {
|
||||
let k = tile / 16;
|
||||
let (w, h) = (ATLAS_COLS * tile, ATLAS_ROWS * tile);
|
||||
let mut img = Image::gen_image_color(w as u16, h as u16, Color::new(0.0, 0.0, 0.0, 0.0));
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
img.set_pixel(x, y, small.get_pixel(x / k, y / k));
|
||||
}
|
||||
}
|
||||
for &(base, png) in HD_TILES.iter() {
|
||||
let src = Image::from_file_with_format(png, Some(ImageFormat::Png)).expect("hd tile");
|
||||
for &(base, png, png2) in HD_TILES.iter() {
|
||||
let src = Image::from_file_with_format(if tile == HD_TILE2 { png2 } else { png }, Some(ImageFormat::Png)).expect("hd tile");
|
||||
for v in 0..4 {
|
||||
let (sx, sy) = ((v % 2) * HD_TILE, (v / 2) * HD_TILE);
|
||||
let (sx, sy) = ((v % 2) * tile, (v / 2) * tile);
|
||||
let id = base + v;
|
||||
let (ox, oy) = ((id % ATLAS_COLS) * HD_TILE, (id / ATLAS_COLS) * HD_TILE);
|
||||
for y in 0..HD_TILE {
|
||||
for x in 0..HD_TILE {
|
||||
let (ox, oy) = ((id % ATLAS_COLS) * tile, (id / ATLAS_COLS) * tile);
|
||||
for y in 0..tile {
|
||||
for x in 0..tile {
|
||||
img.set_pixel(ox + x, oy + y, src.get_pixel(sx + x, sy + y));
|
||||
}
|
||||
}
|
||||
@@ -2410,11 +2414,13 @@ impl Gfx {
|
||||
cursors.set_filter(FilterMode::Nearest);
|
||||
let badges = Texture2D::from_image(&crate::badges::gen_badges());
|
||||
badges.set_filter(FilterMode::Nearest);
|
||||
let atlas_hd = Texture2D::from_image(&gen_hd_atlas());
|
||||
let atlas_hd = Texture2D::from_image(&gen_hd_atlas(HD_TILE));
|
||||
atlas_hd.set_filter(FilterMode::Nearest);
|
||||
let atlas_hd2 = Texture2D::from_image(&gen_hd_atlas(HD_TILE2));
|
||||
atlas_hd2.set_filter(FilterMode::Nearest);
|
||||
let hd_sprites = Texture2D::from_image(&gen_hd_sprites());
|
||||
hd_sprites.set_filter(FilterMode::Nearest);
|
||||
Gfx { atlas, sprites, hd_sprites, atlas_hd, cursors, badges, font, font_map }
|
||||
Gfx { atlas, sprites, hd_sprites, atlas_hd, atlas_hd2, cursors, badges, font, font_map }
|
||||
}
|
||||
|
||||
pub fn cell(id: u32) -> Rect {
|
||||
@@ -2691,8 +2697,10 @@ mod hd_atlas_tests {
|
||||
#[test]
|
||||
fn high_res_atlas() {
|
||||
let small = gen_atlas();
|
||||
let hd = gen_hd_atlas();
|
||||
assert_eq!((hd.width as f32, hd.height as f32), (ATLAS_HD_W, ATLAS_HD_H));
|
||||
for tile in [HD_TILE, HD_TILE2] {
|
||||
let hd = gen_hd_atlas(tile);
|
||||
let k = tile / 16;
|
||||
assert_eq!((hd.width as u32, hd.height as u32), (ATLAS_COLS * tile, ATLAS_ROWS * tile));
|
||||
let px = |img: &Image, x: u32, y: u32| {
|
||||
let p = img.get_pixel(x, y);
|
||||
(p.r, p.g, p.b, p.a)
|
||||
@@ -2700,19 +2708,20 @@ mod hd_atlas_tests {
|
||||
// a cell without an own texture: the 16x16 one scaled up
|
||||
let (cx, cy) = ((T_TREASURY % ATLAS_COLS) * 16, (T_TREASURY / ATLAS_COLS) * 16);
|
||||
for (x, y) in [(0, 0), (5, 9), (15, 15)] {
|
||||
assert_eq!(px(&hd, (cx + x) * 4 + 2, (cy + y) * 4 + 1), px(&small, cx + x, cy + y));
|
||||
assert_eq!(px(&hd, (cx + x) * k + 2, (cy + y) * k + 1), px(&small, cx + x, cy + y));
|
||||
}
|
||||
// the generated ones: the quarters of their 2x2 sheet
|
||||
for &(base, png) in HD_TILES.iter() {
|
||||
let src = Image::from_file_with_format(png, Some(ImageFormat::Png)).unwrap();
|
||||
assert_eq!((src.width, src.height), (2 * HD_TILE as u16, 2 * HD_TILE as u16));
|
||||
for &(base, png, png2) in HD_TILES.iter() {
|
||||
let src = Image::from_file_with_format(if tile == HD_TILE2 { png2 } else { png }, Some(ImageFormat::Png)).unwrap();
|
||||
assert_eq!((src.width as u32, src.height as u32), (2 * tile, 2 * tile));
|
||||
for v in 0..4 {
|
||||
let id = base + v;
|
||||
assert!(hd_tile(id));
|
||||
let (ox, oy) = ((id % ATLAS_COLS) * HD_TILE, (id / ATLAS_COLS) * HD_TILE);
|
||||
assert_eq!(px(&hd, ox + 7, oy + 40), px(&src, (v % 2) * HD_TILE + 7, (v / 2) * HD_TILE + 40));
|
||||
let (ox, oy) = ((id % ATLAS_COLS) * tile, (id / ATLAS_COLS) * tile);
|
||||
assert_eq!(px(&hd, ox + 7, oy + 40), px(&src, (v % 2) * tile + 7, (v / 2) * tile + 40));
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(!hd_tile(T_TREASURY));
|
||||
}
|
||||
}
|
||||
|
||||
+24
-2
@@ -1587,9 +1587,31 @@ impl R3d {
|
||||
self.lit.set_uniform("LightCount", count);
|
||||
// wrapped so the shader keeps its precision (the flow speeds are whole tiles per period)
|
||||
self.lit.set_uniform("Time", (time % 1000.0) as f32);
|
||||
// high-res: the 128x128 tiles where a tile gets nearly that many pixels, else the 64x64
|
||||
// ones (same layout: the chunks keep their uvs, only the texture changes)
|
||||
let hd_tiles = self.chunks_hd;
|
||||
self.lit.set_uniform("AtlasSize", if hd_tiles { vec2(crate::gfx::ATLAS_HD_W, crate::gfx::ATLAS_HD_H) } else { vec2(ATLAS_W, ATLAS_H) });
|
||||
self.lit.set_uniform("CellSize", if hd_tiles { crate::gfx::HD_TILE as f32 } else { 16.0 });
|
||||
let rows = pix.map_or(screen_height() * screen_dpi_scale(), |(_, th, _)| th as f32);
|
||||
let tile = if !hd_tiles {
|
||||
16
|
||||
} else if rows / cam.view_h().max(0.1) >= crate::gfx::HD_TILE2 as f32 * 0.85 {
|
||||
crate::gfx::HD_TILE2
|
||||
} else {
|
||||
crate::gfx::HD_TILE
|
||||
};
|
||||
let atlas = match tile {
|
||||
16 => &gfx.atlas,
|
||||
crate::gfx::HD_TILE => &gfx.atlas_hd,
|
||||
_ => &gfx.atlas_hd2,
|
||||
};
|
||||
for ch in self.chunks.iter_mut() {
|
||||
for mesh in [&mut ch.mesh, &mut ch.overlay].into_iter().flatten() {
|
||||
if mesh.texture.as_ref() != Some(atlas) {
|
||||
mesh.texture = Some(atlas.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
self.lit.set_uniform("AtlasSize", vec2((crate::gfx::ATLAS_COLS * tile) as f32, (crate::gfx::ATLAS_ROWS * tile) as f32));
|
||||
self.lit.set_uniform("CellSize", tile as f32);
|
||||
self.lit.set_uniform("HdLiquid", if hd_tiles { 1.0f32 } else { 0.0 });
|
||||
gl_use_material(&self.lit);
|
||||
for cz in 0..self.ncz {
|
||||
|
||||
Reference in new issue
Block a user