zoom factor
This commit is contained in:
@@ -320,6 +320,8 @@ pub struct Board {
|
||||
pub portals: Vec<PortalDef>,
|
||||
/// Optional font override for this board. When `None`, the app default is used.
|
||||
pub font: Option<FontSpec>,
|
||||
/// Integer scale factor applied to tiles when rendering this board. 1 = natural size.
|
||||
pub zoom: u32,
|
||||
/// Named Rhai scripts available on this board: script name → source text.
|
||||
///
|
||||
/// All script source lives here; [`ObjectDef`]s and [`Board::board_script_name`]
|
||||
|
||||
@@ -50,6 +50,9 @@ pub struct MapHeader {
|
||||
/// Name of the board-level script in the `[scripts]` table, if any.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub board_script_name: Option<String>,
|
||||
/// Integer tile scale factor. 1 = natural size. Omitted from files when 1 (the default).
|
||||
#[serde(default = "default_zoom", skip_serializing_if = "is_zoom_default")]
|
||||
pub zoom: u32,
|
||||
}
|
||||
|
||||
/// The `[font]` section of a map file, specifying a bitmap font for this board.
|
||||
@@ -150,6 +153,8 @@ pub(crate) struct MapFileObjectEntry {
|
||||
}
|
||||
|
||||
fn default_true() -> bool { true }
|
||||
fn default_zoom() -> u32 { 1 }
|
||||
fn is_zoom_default(z: &u32) -> bool { *z == 1 }
|
||||
|
||||
/// Parses an `"#RRGGBB"` hex color string into an [`Rgba8`].
|
||||
/// Returns opaque black on any parse failure.
|
||||
@@ -282,6 +287,7 @@ impl TryFrom<MapFile> for Board {
|
||||
objects,
|
||||
portals: mf.portals,
|
||||
font,
|
||||
zoom: mf.map.zoom,
|
||||
scripts: mf.scripts,
|
||||
board_script_name: mf.map.board_script_name,
|
||||
})
|
||||
@@ -399,6 +405,7 @@ impl From<&Board> for MapFile {
|
||||
height: board.height,
|
||||
player_start: [board.player.x, board.player.y],
|
||||
board_script_name: board.board_script_name.clone(),
|
||||
zoom: board.zoom,
|
||||
},
|
||||
palette,
|
||||
grid: GridData { content },
|
||||
|
||||
@@ -227,6 +227,10 @@ pub(crate) fn show_editor_panel(
|
||||
FontDialogState::from_spec(board.font.as_ref());
|
||||
editor.font_dialog_open = true;
|
||||
}
|
||||
|
||||
ui.separator();
|
||||
ui.label("Zoom");
|
||||
ui.add(egui::Slider::new(&mut board.zoom, 1..=8).text("×"));
|
||||
}
|
||||
|
||||
EditorTab::Scripts => {
|
||||
|
||||
@@ -197,8 +197,9 @@ impl eframe::App for App {
|
||||
// Snapshot the active font for this frame so all rendering uses the same one.
|
||||
// We re-borrow active_font here since apply_font_spec may have changed board_font.
|
||||
let font = self.board_font.as_ref().unwrap_or(&self.default_font);
|
||||
let tw = font.tile_w as f32;
|
||||
let th = font.tile_h as f32;
|
||||
let zoom = self.state.board.zoom;
|
||||
let tw = font.tile_w as f32 * zoom as f32;
|
||||
let th = font.tile_h as f32 * zoom as f32;
|
||||
|
||||
// --- Board rendering ---
|
||||
// The board is drawn using the egui Painter API (direct 2D drawing).
|
||||
@@ -211,7 +212,7 @@ impl eframe::App for App {
|
||||
// Edit mode: ScrollArea lets the user scroll when the board overflows.
|
||||
egui::ScrollArea::new([true, true]).show(ui, |ui| {
|
||||
let (rect, response) = ui.allocate_exact_size(board_px, Sense::click());
|
||||
draw_board(ui.painter(), rect.min, &self.state.board, font);
|
||||
draw_board(ui.painter(), rect.min, &self.state.board, font, zoom);
|
||||
|
||||
// When the Objects tab is active, overlay the object highlights.
|
||||
if self.editor.tab == EditorTab::Objects {
|
||||
@@ -221,6 +222,7 @@ impl eframe::App for App {
|
||||
&self.state.board,
|
||||
font,
|
||||
self.editor.selected_object,
|
||||
zoom,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -264,8 +266,8 @@ impl eframe::App for App {
|
||||
// Play mode: player-centered viewport, no scroll bars.
|
||||
let available = ui.available_rect_before_wrap();
|
||||
let player = self.state.board.player;
|
||||
let origin = board_origin(available, board_w, board_h, player, font);
|
||||
draw_board(ui.painter(), origin, &self.state.board, font);
|
||||
let origin = board_origin(available, board_w, board_h, player, font, zoom);
|
||||
draw_board(ui.painter(), origin, &self.state.board, font, zoom);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+24
-12
@@ -65,7 +65,7 @@ pub(crate) fn paint_glyph(painter: &egui::Painter, rect: Rect, glyph: &Glyph, fo
|
||||
///
|
||||
/// `origin` is the pixel position of cell `(0, 0)` — the top-left corner of
|
||||
/// the board within the panel. Cell positions are computed from `origin` using
|
||||
/// the font's tile dimensions.
|
||||
/// the font's tile dimensions multiplied by `zoom`.
|
||||
pub(crate) fn draw_glyph(
|
||||
painter: &egui::Painter,
|
||||
origin: Pos2,
|
||||
@@ -73,9 +73,10 @@ pub(crate) fn draw_glyph(
|
||||
y: usize,
|
||||
glyph: &Glyph,
|
||||
font: &BitmapFont,
|
||||
zoom: u32,
|
||||
) {
|
||||
let tw = font.tile_w as f32;
|
||||
let th = font.tile_h as f32;
|
||||
let tw = font.tile_w as f32 * zoom as f32;
|
||||
let th = font.tile_h as f32 * zoom as f32;
|
||||
let tl = origin + vec2(x as f32 * tw, y as f32 * th);
|
||||
let rect = Rect::from_min_size(tl, vec2(tw, th));
|
||||
paint_glyph(painter, rect, glyph, font);
|
||||
@@ -85,17 +86,24 @@ pub(crate) fn draw_glyph(
|
||||
///
|
||||
/// Rendering order: grid (floor) → objects → player. Objects are drawn on top
|
||||
/// of their grid cell's background, which is revealed if the object moves away.
|
||||
pub(crate) fn draw_board(painter: &egui::Painter, origin: Pos2, board: &Board, font: &BitmapFont) {
|
||||
/// `zoom` scales each tile by an integer factor.
|
||||
pub(crate) fn draw_board(
|
||||
painter: &egui::Painter,
|
||||
origin: Pos2,
|
||||
board: &Board,
|
||||
font: &BitmapFont,
|
||||
zoom: u32,
|
||||
) {
|
||||
// Pass 1: grid floor.
|
||||
for y in 0..board.height {
|
||||
for x in 0..board.width {
|
||||
let (glyph, _) = board.get(x, y);
|
||||
draw_glyph(painter, origin, x, y, glyph, font);
|
||||
draw_glyph(painter, origin, x, y, glyph, font, zoom);
|
||||
}
|
||||
}
|
||||
// Pass 2: objects drawn on top of the floor.
|
||||
for obj in &board.objects {
|
||||
draw_glyph(painter, origin, obj.x, obj.y, &obj.glyph, font);
|
||||
draw_glyph(painter, origin, obj.x, obj.y, &obj.glyph, font, zoom);
|
||||
}
|
||||
// Pass 3: player overlay. Will be removed once the player becomes a scripted object.
|
||||
let player_glyph = Glyph::player();
|
||||
@@ -106,6 +114,7 @@ pub(crate) fn draw_board(painter: &egui::Painter, origin: Pos2, board: &Board, f
|
||||
board.player.y as usize,
|
||||
&player_glyph,
|
||||
font,
|
||||
zoom,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -114,16 +123,18 @@ pub(crate) fn draw_board(painter: &egui::Painter, origin: Pos2, board: &Board, f
|
||||
/// Dims the entire board with a semi-transparent fill, then for each
|
||||
/// [`ObjectDef`](crate::game::ObjectDef) redraws that cell at full brightness
|
||||
/// and outlines it in white. The selected object (by index into
|
||||
/// `board.objects`) gets a yellow outline instead.
|
||||
/// `board.objects`) gets a yellow outline instead. `zoom` must match the zoom
|
||||
/// used to draw the board.
|
||||
pub(crate) fn draw_object_overlays(
|
||||
painter: &egui::Painter,
|
||||
origin: Pos2,
|
||||
board: &Board,
|
||||
font: &BitmapFont,
|
||||
selected: Option<usize>,
|
||||
zoom: u32,
|
||||
) {
|
||||
let tw = font.tile_w as f32;
|
||||
let th = font.tile_h as f32;
|
||||
let tw = font.tile_w as f32 * zoom as f32;
|
||||
let th = font.tile_h as f32 * zoom as f32;
|
||||
|
||||
// Dim the whole board so non-object cells recede visually.
|
||||
let board_rect = Rect::from_min_size(
|
||||
@@ -166,16 +177,17 @@ pub(crate) fn pos_to_cell(origin: Pos2, pos: Pos2, tile_w: f32, tile_h: f32) ->
|
||||
///
|
||||
/// If the board fits along an axis, it is centered. If it overflows, the
|
||||
/// viewport is centered on the player and clamped so no empty space appears
|
||||
/// at the board edges.
|
||||
/// at the board edges. `zoom` scales tile dimensions before computing pixel sizes.
|
||||
pub(crate) fn board_origin(
|
||||
available: Rect,
|
||||
board_w: usize,
|
||||
board_h: usize,
|
||||
player: Player,
|
||||
font: &BitmapFont,
|
||||
zoom: u32,
|
||||
) -> Pos2 {
|
||||
let tw = font.tile_w as f32;
|
||||
let th = font.tile_h as f32;
|
||||
let tw = font.tile_w as f32 * zoom as f32;
|
||||
let th = font.tile_h as f32 * zoom as f32;
|
||||
let board_px_w = board_w as f32 * tw;
|
||||
let board_px_h = board_h as f32 * th;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user