added start and end to exports

This commit is contained in:
grimsace
2026-04-14 11:21:49 -05:00
parent 0b7696031b
commit d90a3142ce
3 changed files with 202 additions and 175 deletions
+14
View File
@@ -341,11 +341,17 @@ fn export_composite_masks(
.ok_or_else(|| "Failed to allocate secret doors mask canvas".to_string())?;
let mut windows = Pixmap::new(g.width, g.height)
.ok_or_else(|| "Failed to allocate windows mask canvas".to_string())?;
let mut start_markers = Pixmap::new(g.width, g.height)
.ok_or_else(|| "Failed to allocate start markers mask canvas".to_string())?;
let mut end_markers = Pixmap::new(g.width, g.height)
.ok_or_else(|| "Failed to allocate end markers mask canvas".to_string())?;
fill_bg(&mut doors, BLACK);
fill_bg(&mut archways, BLACK);
fill_bg(&mut locked_doors, BLACK);
fill_bg(&mut secret_doors, BLACK);
fill_bg(&mut windows, BLACK);
fill_bg(&mut start_markers, BLACK);
fill_bg(&mut end_markers, BLACK);
for door in &layout.doors {
if door.secret {
draw_door(&mut secret_doors, &g, door, door_w, WHITE, DoorStyle::Solid);
@@ -360,6 +366,12 @@ fn export_composite_masks(
for window in &layout.windows {
draw_window(&mut windows, &g, window, door_w, WHITE, DoorStyle::Solid);
}
for marker in &layout.start_markers {
fill_rect_marker(&mut start_markers, &g, marker, WHITE);
}
for marker in &layout.end_markers {
fill_rect_marker(&mut end_markers, &g, marker, WHITE);
}
let composite = render_pixmap(layout, settings)?;
let composite_img = raster_image_from_pixmap(&composite, settings)?;
@@ -376,6 +388,8 @@ fn export_composite_masks(
save_mask_image(folder, "locked_doors_mask", &locked_doors, settings)?;
save_mask_image(folder, "secret_doors_mask", &secret_doors, settings)?;
save_mask_image(folder, "windows_mask", &windows, settings)?;
save_mask_image(folder, "start_markers_mask", &start_markers, settings)?;
save_mask_image(folder, "end_markers_mask", &end_markers, settings)?;
if settings.export_show_grid {
let mut grid = Pixmap::new(g.width, g.height)
.ok_or_else(|| "Failed to allocate grid mask canvas".to_string())?;
+3 -175
View File
@@ -2,6 +2,7 @@ mod exporter;
mod layout;
mod seed;
mod settings;
mod startend;
mod ui;
use std::collections::HashSet;
@@ -14,6 +15,7 @@ use layout::{
DoorSettings, DungeonLayout, WindowSettings, blocked_room_cells, corridor_cells,
shortest_path_cells,
};
use startend::{manual_marker_size, populate_random_markers};
use ui::{AddTool, UiSettings, draw_side_panel};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -848,7 +850,7 @@ impl DungeonApp {
return;
}
let size = manual_marker_size(&self.settings, kind);
let size = manual_marker_size(&self.settings, matches!(kind, MarkerKind::Start));
let origin = centered_marker_origin(cell, size, self.settings.cols, self.settings.rows);
let marker = layout::AreaMarker { cell: origin, size };
@@ -2004,180 +2006,6 @@ fn centered_marker_origin(
(cell.0.saturating_sub(half).min(max_x), cell.1.saturating_sub(half).min(max_y))
}
fn populate_random_markers(
mut layout: DungeonLayout,
settings: &UiSettings,
) -> DungeonLayout {
layout.start_markers.clear();
layout.end_markers.clear();
if layout.rooms.is_empty() {
return layout;
}
let start_count = random_range_inclusive(
settings.min_start_marker_count,
settings.max_start_marker_count,
seed::derive_seed(settings.seed, 10_001),
);
let end_count = random_range_inclusive(
settings.min_end_marker_count,
settings.max_end_marker_count,
seed::derive_seed(settings.seed, 10_002),
);
let pair_count = start_count.min(end_count);
let mut available_start_rooms: Vec<usize> = (0..layout.rooms.len()).collect();
let mut available_end_rooms: Vec<usize> = (0..layout.rooms.len()).collect();
for pair_idx in 0..pair_count {
let (start_room_idx, end_room_idx) =
farthest_room_pair(&layout.rooms, &available_start_rooms, &available_end_rooms);
let start_room = &layout.rooms[start_room_idx];
let end_room = &layout.rooms[end_room_idx];
layout.start_markers.push(marker_in_room(
start_room,
settings.min_start_marker_size,
settings.max_start_marker_size,
seed::derive_seed(settings.seed, 11_000 + pair_idx as u64),
));
layout.end_markers.push(marker_in_room(
end_room,
settings.min_end_marker_size,
settings.max_end_marker_size,
seed::derive_seed(settings.seed, 12_000 + pair_idx as u64),
));
consume_room(&mut available_start_rooms, start_room_idx);
consume_room(&mut available_end_rooms, end_room_idx);
}
for idx in pair_count..start_count {
let room_idx = pick_room_index(
&available_start_rooms,
layout.rooms.len(),
seed::derive_seed(settings.seed, 13_000 + idx as u64),
);
let room = &layout.rooms[room_idx];
layout.start_markers.push(marker_in_room(
room,
settings.min_start_marker_size,
settings.max_start_marker_size,
seed::derive_seed(settings.seed, 14_000 + idx as u64),
));
consume_room(&mut available_start_rooms, room_idx);
}
for idx in pair_count..end_count {
let room_idx = pick_room_index(
&available_end_rooms,
layout.rooms.len(),
seed::derive_seed(settings.seed, 15_000 + idx as u64),
);
let room = &layout.rooms[room_idx];
layout.end_markers.push(marker_in_room(
room,
settings.min_end_marker_size,
settings.max_end_marker_size,
seed::derive_seed(settings.seed, 16_000 + idx as u64),
));
consume_room(&mut available_end_rooms, room_idx);
}
layout
}
fn random_range_inclusive(min: usize, max: usize, seed_value: u64) -> usize {
let min = min.max(1);
let max = max.max(min);
let span = max - min + 1;
min + (seed_value as usize % span)
}
fn manual_marker_size(settings: &UiSettings, kind: MarkerKind) -> usize {
match kind {
MarkerKind::Start => settings.min_start_marker_size.min(settings.max_start_marker_size),
MarkerKind::End => settings.min_end_marker_size.min(settings.max_end_marker_size),
}
.clamp(1, 10)
}
fn marker_in_room(room: &layout::Room, min_size: usize, max_size: usize, seed_value: u64) -> layout::AreaMarker {
let room_limit = room.width.min(room.height).max(1);
let min_size = min_size.clamp(1, 10).min(room_limit);
let max_size = max_size.clamp(min_size, 10).min(room_limit);
let size = random_range_inclusive(min_size, max_size, seed_value.rotate_left(7));
let x_span = room.width.saturating_sub(size);
let y_span = room.height.saturating_sub(size);
let x = room.x
+ if x_span == 0 {
0
} else {
(seed_value as usize) % (x_span + 1)
};
let y = room.y
+ if y_span == 0 {
0
} else {
(seed_value.rotate_left(19) as usize) % (y_span + 1)
};
layout::AreaMarker { cell: (x, y), size }
}
fn farthest_room_pair(
rooms: &[layout::Room],
available_start_rooms: &[usize],
available_end_rooms: &[usize],
) -> (usize, usize) {
let start_rooms = if available_start_rooms.is_empty() {
(0..rooms.len()).collect::<Vec<_>>()
} else {
available_start_rooms.to_vec()
};
let end_rooms = if available_end_rooms.is_empty() {
(0..rooms.len()).collect::<Vec<_>>()
} else {
available_end_rooms.to_vec()
};
let mut best = (start_rooms[0], end_rooms[0]);
let mut best_dist = 0usize;
for &start_idx in &start_rooms {
for &end_idx in &end_rooms {
if rooms.len() > 1 && start_idx == end_idx {
continue;
}
let dist = room_distance_sq(&rooms[start_idx], &rooms[end_idx]);
if dist > best_dist {
best = (start_idx, end_idx);
best_dist = dist;
}
}
}
best
}
fn room_distance_sq(a: &layout::Room, b: &layout::Room) -> usize {
let ac = a.center_cell();
let bc = b.center_cell();
let dx = ac.0.abs_diff(bc.0);
let dy = ac.1.abs_diff(bc.1);
dx * dx + dy * dy
}
fn consume_room(available_rooms: &mut Vec<usize>, room_idx: usize) {
if let Some(pos) = available_rooms.iter().position(|&idx| idx == room_idx) {
available_rooms.remove(pos);
}
}
fn pick_room_index(available_rooms: &[usize], room_count: usize, seed_value: u64) -> usize {
if !available_rooms.is_empty() {
available_rooms[seed_value as usize % available_rooms.len()]
} else {
seed_value as usize % room_count.max(1)
}
}
fn draw_area_marker(
painter: &egui::Painter,
geometry: &GridGeometry,
+185
View File
@@ -0,0 +1,185 @@
use crate::layout::{self, DungeonLayout};
use crate::seed;
use crate::ui::UiSettings;
pub fn populate_random_markers(
mut layout: DungeonLayout,
settings: &UiSettings,
) -> DungeonLayout {
layout.start_markers.clear();
layout.end_markers.clear();
if layout.rooms.is_empty() {
return layout;
}
let start_count = random_range_inclusive(
settings.min_start_marker_count,
settings.max_start_marker_count,
seed::derive_seed(settings.seed, 10_001),
);
let end_count = random_range_inclusive(
settings.min_end_marker_count,
settings.max_end_marker_count,
seed::derive_seed(settings.seed, 10_002),
);
let pair_count = start_count.min(end_count);
let mut available_start_rooms: Vec<usize> = (0..layout.rooms.len()).collect();
let mut available_end_rooms: Vec<usize> = (0..layout.rooms.len()).collect();
for pair_idx in 0..pair_count {
let (start_room_idx, end_room_idx) =
farthest_room_pair(&layout.rooms, &available_start_rooms, &available_end_rooms);
let start_room = &layout.rooms[start_room_idx];
let end_room = &layout.rooms[end_room_idx];
layout.start_markers.push(marker_in_room(
start_room,
settings.min_start_marker_size,
settings.max_start_marker_size,
seed::derive_seed(settings.seed, 11_000 + pair_idx as u64),
));
layout.end_markers.push(marker_in_room(
end_room,
settings.min_end_marker_size,
settings.max_end_marker_size,
seed::derive_seed(settings.seed, 12_000 + pair_idx as u64),
));
consume_room(&mut available_start_rooms, start_room_idx);
consume_room(&mut available_end_rooms, end_room_idx);
}
for idx in pair_count..start_count {
let room_idx = pick_room_index(
&available_start_rooms,
layout.rooms.len(),
seed::derive_seed(settings.seed, 13_000 + idx as u64),
);
let room = &layout.rooms[room_idx];
layout.start_markers.push(marker_in_room(
room,
settings.min_start_marker_size,
settings.max_start_marker_size,
seed::derive_seed(settings.seed, 14_000 + idx as u64),
));
consume_room(&mut available_start_rooms, room_idx);
}
for idx in pair_count..end_count {
let room_idx = pick_room_index(
&available_end_rooms,
layout.rooms.len(),
seed::derive_seed(settings.seed, 15_000 + idx as u64),
);
let room = &layout.rooms[room_idx];
layout.end_markers.push(marker_in_room(
room,
settings.min_end_marker_size,
settings.max_end_marker_size,
seed::derive_seed(settings.seed, 16_000 + idx as u64),
));
consume_room(&mut available_end_rooms, room_idx);
}
layout
}
pub fn manual_marker_size(settings: &UiSettings, is_start: bool) -> usize {
if is_start {
settings
.min_start_marker_size
.min(settings.max_start_marker_size)
} else {
settings.min_end_marker_size.min(settings.max_end_marker_size)
}
.clamp(1, 10)
}
fn random_range_inclusive(min: usize, max: usize, seed_value: u64) -> usize {
let min = min.max(1);
let max = max.max(min);
let span = max - min + 1;
min + (seed_value as usize % span)
}
fn marker_in_room(
room: &layout::Room,
min_size: usize,
max_size: usize,
seed_value: u64,
) -> layout::AreaMarker {
let room_limit = room.width.min(room.height).max(1);
let min_size = min_size.clamp(1, 10).min(room_limit);
let max_size = max_size.clamp(min_size, 10).min(room_limit);
let size = random_range_inclusive(min_size, max_size, seed_value.rotate_left(7));
let x_span = room.width.saturating_sub(size);
let y_span = room.height.saturating_sub(size);
let x = room.x
+ if x_span == 0 {
0
} else {
(seed_value as usize) % (x_span + 1)
};
let y = room.y
+ if y_span == 0 {
0
} else {
(seed_value.rotate_left(19) as usize) % (y_span + 1)
};
layout::AreaMarker { cell: (x, y), size }
}
fn farthest_room_pair(
rooms: &[layout::Room],
available_start_rooms: &[usize],
available_end_rooms: &[usize],
) -> (usize, usize) {
let start_rooms = if available_start_rooms.is_empty() {
(0..rooms.len()).collect::<Vec<_>>()
} else {
available_start_rooms.to_vec()
};
let end_rooms = if available_end_rooms.is_empty() {
(0..rooms.len()).collect::<Vec<_>>()
} else {
available_end_rooms.to_vec()
};
let mut best = (start_rooms[0], end_rooms[0]);
let mut best_dist = 0usize;
for &start_idx in &start_rooms {
for &end_idx in &end_rooms {
if rooms.len() > 1 && start_idx == end_idx {
continue;
}
let dist = room_distance_sq(&rooms[start_idx], &rooms[end_idx]);
if dist > best_dist {
best = (start_idx, end_idx);
best_dist = dist;
}
}
}
best
}
fn room_distance_sq(a: &layout::Room, b: &layout::Room) -> usize {
let ac = a.center_cell();
let bc = b.center_cell();
let dx = ac.0.abs_diff(bc.0);
let dy = ac.1.abs_diff(bc.1);
dx * dx + dy * dy
}
fn consume_room(available_rooms: &mut Vec<usize>, room_idx: usize) {
if let Some(pos) = available_rooms.iter().position(|&idx| idx == room_idx) {
available_rooms.remove(pos);
}
}
fn pick_room_index(available_rooms: &[usize], room_count: usize, seed_value: u64) -> usize {
if !available_rooms.is_empty() {
available_rooms[seed_value as usize % available_rooms.len()]
} else {
seed_value as usize % room_count.max(1)
}
}