diff --git a/src/interact/mod.rs b/src/interact/mod.rs index eb2d9db..817af3e 100644 --- a/src/interact/mod.rs +++ b/src/interact/mod.rs @@ -5,6 +5,9 @@ */ use crate::app::DungeonApp; +pub use crate::exporter::types::{ + door_edges_for, door_render_width, norm_edge as normalized_edge, window_render_width, +}; use crate::layout; use crate::ui::AddTool; use eframe::egui; @@ -602,71 +605,6 @@ pub fn resize_hit_cells( cells } -// Computes edges for. -pub fn door_edges_for( - door: &layout::Door, - cols: usize, - rows: usize, -) -> Vec<((usize, usize), (usize, usize))> { - let mut edges = Vec::new(); - if door.from.0.abs_diff(door.to.0) + door.from.1.abs_diff(door.to.1) != 1 { - return edges; - } - - let width = door_render_width(door).max(1) as isize; - let min_offset = -((width - 1) / 2); - let max_offset = width / 2; - - if door.from.0 != door.to.0 { - let y = door.from.1 as isize; - for dy in min_offset..=max_offset { - let ny = y + dy; - if ny < 0 || ny >= rows as isize { - continue; - } - let a = (door.from.0, ny as usize); - let b = (door.to.0, ny as usize); - edges.push(normalized_edge(a, b)); - } - } else { - let x = door.from.0 as isize; - for dx in min_offset..=max_offset { - let nx = x + dx; - if nx < 0 || nx >= cols as isize { - continue; - } - let a = (nx as usize, door.from.1); - let b = (nx as usize, door.to.1); - edges.push(normalized_edge(a, b)); - } - } - - edges -} - -// Computes render width. -pub fn door_render_width(door: &layout::Door) -> usize { - if door.span_width { - door.width.max(1) - } else { - 1 - } -} - -// Computes render width. -pub fn window_render_width(window: &layout::Window) -> usize { - if window.span_width { - window.width.max(1) - } else { - 1 - } -} - -// Normalizes a cell edge so either endpoint order compares equal. -pub fn normalized_edge(a: (usize, usize), b: (usize, usize)) -> ((usize, usize), (usize, usize)) { - if a <= b { (a, b) } else { (b, a) } -} - // Returns the screen center point for a grid cell. pub fn cell_center(geometry: &GridGeometry, col: usize, row: usize) -> egui::Pos2 { egui::pos2( diff --git a/src/layout/generation/markers.rs b/src/layout/generation/markers.rs index 3f050a0..fffce91 100644 --- a/src/layout/generation/markers.rs +++ b/src/layout/generation/markers.rs @@ -5,7 +5,7 @@ */ use super::super::types::{AreaMarker, Corridor, DungeonLayout, Room, Staircase}; -use super::super::utils::room_index_at_cell; +use super::super::utils::{SimpleRng, room_index_at_cell, shuffle_items}; use crate::seed; use crate::ui::UiSettings; use std::collections::HashSet; @@ -600,29 +600,6 @@ pub fn random_stair_size(settings: &UiSettings, seed_value: u64) -> (usize, usiz } pub fn shuffle_with_seed(items: &mut [T], seed: u64) { - let mut rng = StairShuffleRng::new(seed); - for idx in (1..items.len()).rev() { - let swap_idx = rng.next_u32() as usize % (idx + 1); - items.swap(idx, swap_idx); - } -} - -pub struct StairShuffleRng { - pub state: u64, -} - -impl StairShuffleRng { - // Creates a new instance with the given inputs. - pub fn new(seed: u64) -> Self { - Self { state: seed } - } - - // Generates the next pseudo-random 32-bit value. - pub fn next_u32(&mut self) -> u32 { - self.state = self - .state - .wrapping_mul(6364136223846793005) - .wrapping_add(1442695040888963407); - (self.state >> 32) as u32 - } + let mut rng = SimpleRng::new(seed); + shuffle_items(items, &mut rng); } diff --git a/src/layout/utils.rs b/src/layout/utils.rs index 92b810f..7e0693e 100644 --- a/src/layout/utils.rs +++ b/src/layout/utils.rs @@ -468,13 +468,18 @@ pub fn noisy_path( path } -// Shuffle indices in place using the provided RNG. -pub fn shuffle_indices(indices: &mut [usize], rng: &mut SimpleRng) { - if indices.len() <= 1 { +// Shuffle any mutable slice in place using the provided RNG. +pub fn shuffle_items(items: &mut [T], rng: &mut SimpleRng) { + if items.len() <= 1 { return; } - for i in (1..indices.len()).rev() { + for i in (1..items.len()).rev() { let j = rng.range_inclusive(0, i); - indices.swap(i, j); + items.swap(i, j); } } + +// Shuffle indices in place using the provided RNG. +pub fn shuffle_indices(indices: &mut [usize], rng: &mut SimpleRng) { + shuffle_items(indices, rng); +} diff --git a/src/rendering.rs b/src/rendering.rs index 34007b4..f48ae07 100644 --- a/src/rendering.rs +++ b/src/rendering.rs @@ -4,6 +4,7 @@ * and various markers using egui's Painter API. */ +use crate::exporter::utils::{corridor_edges_from_cells, room_edges_from_rooms}; use crate::interact::{ GridGeometry, HoverMarker, MarkerKind, cell_center, cell_rect, door_edges_for, door_render_width, marker_rect, normalized_edge, window_render_width, @@ -496,46 +497,6 @@ pub fn draw_wall_segment( } } -// Computes edges from cells. -pub fn corridor_edges_from_cells( - corridor_cells: &HashSet<(usize, usize)>, -) -> HashSet<((usize, usize), (usize, usize))> { - let mut edges = HashSet::new(); - for &(col, row) in corridor_cells { - let right = (col + 1, row); - let bottom = (col, row + 1); - if corridor_cells.contains(&right) { - edges.insert(normalized_edge((col, row), right)); - } - if corridor_cells.contains(&bottom) { - edges.insert(normalized_edge((col, row), bottom)); - } - } - edges -} - -// Computes edges from rooms. -pub fn room_edges_from_rooms( - rooms: &[crate::layout::Room], -) -> HashSet<((usize, usize), (usize, usize))> { - let mut edges = HashSet::new(); - for room in rooms { - let x_end = room.x + room.width; - let y_end = room.y + room.height; - for x in room.x..x_end { - for y in room.y..y_end { - if x + 1 < x_end { - edges.insert(normalized_edge((x, y), (x + 1, y))); - } - if y + 1 < y_end { - edges.insert(normalized_edge((x, y), (x, y + 1))); - } - } - } - } - edges -} - #[derive(Debug, Clone, Copy)] pub enum DoorLineStyle { Solid, diff --git a/src/ui/widgets.rs b/src/ui/widgets.rs index 6dcc95a..6d62325 100644 --- a/src/ui/widgets.rs +++ b/src/ui/widgets.rs @@ -4,6 +4,9 @@ * and custom line styling (dashed, dotted, dash-dot patterns). */ +pub use crate::rendering::{ + draw_dash_dot_dot_line, draw_dash_dot_line, draw_dashed_line, draw_dotted_line, +}; use eframe::egui; use egui::{Color32, Stroke}; @@ -167,124 +170,3 @@ pub fn draw_legend_entry_colorblind(ui: &mut egui::Ui, label: &str, style: Legen }); ui.add_space(4.0); } - -// Draw a dashed line. -pub fn draw_dashed_line( - painter: &egui::Painter, - from: egui::Pos2, - to: egui::Pos2, - stroke: Stroke, - dash_len: f32, - gap_len: f32, -) { - let dx = to.x - from.x; - let dy = to.y - from.y; - let len = (dx * dx + dy * dy).sqrt(); - if len <= 0.0 { - return; - } - let ux = dx / len; - let uy = dy / len; - - let mut dist = 0.0_f32; - while dist < len { - let seg_start = dist; - let seg_end = (dist + dash_len).min(len); - let p0 = egui::pos2(from.x + ux * seg_start, from.y + uy * seg_start); - let p1 = egui::pos2(from.x + ux * seg_end, from.y + uy * seg_end); - painter.line_segment([p0, p1], stroke); - dist += dash_len + gap_len; - } -} - -// Draw a dotted line. -pub fn draw_dotted_line(painter: &egui::Painter, from: egui::Pos2, to: egui::Pos2, stroke: Stroke) { - let dx = to.x - from.x; - let dy = to.y - from.y; - let len = (dx * dx + dy * dy).sqrt(); - if len <= 0.0 { - return; - } - let ux = dx / len; - let uy = dy / len; - let step = 5.0_f32; - let radius = (stroke.width * 0.35).max(1.0); - - let mut dist = 0.0_f32; - while dist <= len { - let point = egui::pos2(from.x + ux * dist, from.y + uy * dist); - painter.circle_filled(point, radius, stroke.color); - dist += step; - } -} - -// Draws dash dot line. -pub fn draw_dash_dot_line( - painter: &egui::Painter, - from: egui::Pos2, - to: egui::Pos2, - stroke: Stroke, -) { - let dx = to.x - from.x; - let dy = to.y - from.y; - let len = (dx * dx + dy * dy).sqrt(); - if len <= 0.0 { - return; - } - - let ux = dx / len; - let uy = dy / len; - let mut dist = 0.0_f32; - while dist < len { - let dash_end = (dist + 7.0).min(len); - let p0 = egui::pos2(from.x + ux * dist, from.y + uy * dist); - let p1 = egui::pos2(from.x + ux * dash_end, from.y + uy * dash_end); - painter.line_segment([p0, p1], stroke); - dist = dash_end + 3.0; - if dist >= len { - break; - } - let dot = egui::pos2(from.x + ux * dist, from.y + uy * dist); - painter.circle_filled(dot, (stroke.width * 0.35).max(1.0), stroke.color); - dist += 4.0; - } -} - -// Draws dash dot dot line. -pub fn draw_dash_dot_dot_line( - painter: &egui::Painter, - from: egui::Pos2, - to: egui::Pos2, - stroke: Stroke, -) { - let dx = to.x - from.x; - let dy = to.y - from.y; - let len = (dx * dx + dy * dy).sqrt(); - if len <= 0.0 { - return; - } - - let ux = dx / len; - let uy = dy / len; - let radius = (stroke.width * 0.35).max(1.0); - let mut dist = 0.0_f32; - while dist < len { - let dash_end = (dist + 7.0).min(len); - let p0 = egui::pos2(from.x + ux * dist, from.y + uy * dist); - let p1 = egui::pos2(from.x + ux * dash_end, from.y + uy * dash_end); - painter.line_segment([p0, p1], stroke); - dist = dash_end + 3.0; - if dist >= len { - break; - } - let dot1 = egui::pos2(from.x + ux * dist, from.y + uy * dist); - painter.circle_filled(dot1, radius, stroke.color); - dist += 3.0; - if dist >= len { - break; - } - let dot2 = egui::pos2(from.x + ux * dist, from.y + uy * dist); - painter.circle_filled(dot2, radius, stroke.color); - dist += 4.0; - } -}