fixed masks on export and added option to have the grid or not
This commit is contained in:
+76
-33
@@ -171,10 +171,12 @@ fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap
|
|||||||
Pixmap::new(g.width, g.height).ok_or_else(|| "Failed to allocate canvas".to_string())?;
|
Pixmap::new(g.width, g.height).ok_or_else(|| "Failed to allocate canvas".to_string())?;
|
||||||
fill_bg(&mut pixmap, BG);
|
fill_bg(&mut pixmap, BG);
|
||||||
|
|
||||||
let wall_w = (g.cell / 5.0).max(1.0);
|
let wall_w = snap_even_width((g.cell / 5.0).max(1.0));
|
||||||
let door_w = (g.cell / 10.0).max(1.0);
|
let door_w = (g.cell / 10.0).max(1.0).round();
|
||||||
|
|
||||||
|
if settings.export_show_grid {
|
||||||
draw_grid(&mut pixmap, &g);
|
draw_grid(&mut pixmap, &g);
|
||||||
|
}
|
||||||
|
|
||||||
for &(x, y) in &scene.corridor_cells {
|
for &(x, y) in &scene.corridor_cells {
|
||||||
fill_rect_cell(&mut pixmap, &g, x, y, CORRIDOR);
|
fill_rect_cell(&mut pixmap, &g, x, y, CORRIDOR);
|
||||||
@@ -247,7 +249,7 @@ fn export_composite_masks(
|
|||||||
|
|
||||||
let mut floors = Pixmap::new(g.width, g.height)
|
let mut floors = Pixmap::new(g.width, g.height)
|
||||||
.ok_or_else(|| "Failed to allocate floors mask canvas".to_string())?;
|
.ok_or_else(|| "Failed to allocate floors mask canvas".to_string())?;
|
||||||
fill_bg(&mut floors, BG);
|
fill_bg(&mut floors, BLACK);
|
||||||
for &(x, y) in &scene.corridor_cells {
|
for &(x, y) in &scene.corridor_cells {
|
||||||
fill_rect_cell(&mut floors, &g, x, y, WHITE);
|
fill_rect_cell(&mut floors, &g, x, y, WHITE);
|
||||||
}
|
}
|
||||||
@@ -257,7 +259,7 @@ fn export_composite_masks(
|
|||||||
|
|
||||||
let mut walls = Pixmap::new(g.width, g.height)
|
let mut walls = Pixmap::new(g.width, g.height)
|
||||||
.ok_or_else(|| "Failed to allocate walls mask canvas".to_string())?;
|
.ok_or_else(|| "Failed to allocate walls mask canvas".to_string())?;
|
||||||
fill_bg(&mut walls, BG);
|
fill_bg(&mut walls, BLACK);
|
||||||
draw_cell_walls(
|
draw_cell_walls(
|
||||||
&mut walls,
|
&mut walls,
|
||||||
&g,
|
&g,
|
||||||
@@ -279,20 +281,21 @@ fn export_composite_masks(
|
|||||||
|
|
||||||
let mut doors = Pixmap::new(g.width, g.height)
|
let mut doors = Pixmap::new(g.width, g.height)
|
||||||
.ok_or_else(|| "Failed to allocate doors mask canvas".to_string())?;
|
.ok_or_else(|| "Failed to allocate doors mask canvas".to_string())?;
|
||||||
fill_bg(&mut doors, BG);
|
fill_bg(&mut doors, BLACK);
|
||||||
for door in &layout.doors {
|
for door in &layout.doors {
|
||||||
draw_door(&mut doors, &g, door, door_w, WHITE, DoorStyle::Solid);
|
draw_door(&mut doors, &g, door, door_w, WHITE, DoorStyle::Solid);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut grid = Pixmap::new(g.width, g.height)
|
|
||||||
.ok_or_else(|| "Failed to allocate grid mask canvas".to_string())?;
|
|
||||||
fill_bg(&mut grid, BG);
|
|
||||||
draw_grid_color(&mut grid, &g, WHITE);
|
|
||||||
|
|
||||||
save_mask_image(folder, "floors_mask", &floors, settings)?;
|
save_mask_image(folder, "floors_mask", &floors, settings)?;
|
||||||
save_mask_image(folder, "walls_mask", &walls, settings)?;
|
save_mask_image(folder, "walls_mask", &walls, settings)?;
|
||||||
save_mask_image(folder, "doors_mask", &doors, settings)?;
|
save_mask_image(folder, "doors_mask", &doors, 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())?;
|
||||||
|
fill_bg(&mut grid, BLACK);
|
||||||
|
draw_grid_color(&mut grid, &g, WHITE);
|
||||||
save_mask_image(folder, "grid_mask", &grid, settings)?;
|
save_mask_image(folder, "grid_mask", &grid, settings)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -305,7 +308,7 @@ fn save_mask_image(
|
|||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let ext = settings.mask_format.extension();
|
let ext = settings.mask_format.extension();
|
||||||
let path = folder.join(format!("{stem}.{ext}"));
|
let path = folder.join(format!("{stem}.{ext}"));
|
||||||
let img = raster_image_from_pixmap(pixmap, settings)?;
|
let img = raster_mask_image_from_pixmap(pixmap, settings)?;
|
||||||
img.save_with_format(&path, mask_image_format(settings.mask_format))
|
img.save_with_format(&path, mask_image_format(settings.mask_format))
|
||||||
.map_err(|e| format!("Failed writing {}: {e}", path.display()))?;
|
.map_err(|e| format!("Failed writing {}: {e}", path.display()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -335,6 +338,35 @@ fn raster_image_from_pixmap(
|
|||||||
Ok(img)
|
Ok(img)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn raster_mask_image_from_pixmap(
|
||||||
|
pixmap: &Pixmap,
|
||||||
|
settings: &UiSettings,
|
||||||
|
) -> Result<DynamicImage, String> {
|
||||||
|
let rgba = RgbaImage::from_raw(pixmap.width(), pixmap.height(), pixmap.data().to_vec())
|
||||||
|
.ok_or_else(|| "Failed to build image buffer".to_string())?;
|
||||||
|
let mut img = DynamicImage::ImageRgba8(rgba);
|
||||||
|
|
||||||
|
let target = raster_mask_target_size(settings, pixmap.width(), pixmap.height());
|
||||||
|
if img.width() != target.0 || img.height() != target.1 {
|
||||||
|
img = img.resize_exact(target.0, target.1, FilterType::Nearest);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut out = img.to_rgba8();
|
||||||
|
for pixel in out.pixels_mut() {
|
||||||
|
let on = pixel[0] > 127 || pixel[1] > 127 || pixel[2] > 127;
|
||||||
|
let v = if on { 255 } else { 0 };
|
||||||
|
*pixel = image::Rgba([v, v, v, 255]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(DynamicImage::ImageRgba8(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn raster_mask_target_size(settings: &UiSettings, src_w: u32, src_h: u32) -> (u32, u32) {
|
||||||
|
let (target_w, _target_h) = raster_target_size(settings);
|
||||||
|
let scale = ((target_w as f32) / (src_w as f32)).round().max(1.0) as u32;
|
||||||
|
(src_w.saturating_mul(scale), src_h.saturating_mul(scale))
|
||||||
|
}
|
||||||
|
|
||||||
fn raster_target_size(settings: &UiSettings) -> (u32, u32) {
|
fn raster_target_size(settings: &UiSettings) -> (u32, u32) {
|
||||||
let mut width = settings.export_width.clamp(1, 10_000);
|
let mut width = settings.export_width.clamp(1, 10_000);
|
||||||
let mut height = settings.export_height.clamp(1, 10_000);
|
let mut height = settings.export_height.clamp(1, 10_000);
|
||||||
@@ -374,6 +406,7 @@ fn build_svg(layout: &DungeonLayout, settings: &UiSettings) -> String {
|
|||||||
BG.0, BG.1, BG.2
|
BG.0, BG.1, BG.2
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if settings.export_show_grid {
|
||||||
for c in 0..=g.cols {
|
for c in 0..=g.cols {
|
||||||
let x = g.left() + c as f32 * g.cell;
|
let x = g.left() + c as f32 * g.cell;
|
||||||
let _ = writeln!(
|
let _ = writeln!(
|
||||||
@@ -398,6 +431,7 @@ fn build_svg(layout: &DungeonLayout, settings: &UiSettings) -> String {
|
|||||||
GRID.2
|
GRID.2
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let corridor_cells = corridor_cells(layout, settings.cols, settings.rows);
|
let corridor_cells = corridor_cells(layout, settings.cols, settings.rows);
|
||||||
let corridor_edges = corridor_edges_from_cells(&corridor_cells);
|
let corridor_edges = corridor_edges_from_cells(&corridor_cells);
|
||||||
@@ -540,31 +574,27 @@ fn draw_grid(pixmap: &mut Pixmap, g: &ExportGeometry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw_grid_color(pixmap: &mut Pixmap, g: &ExportGeometry, color: (u8, u8, u8, u8)) {
|
fn draw_grid_color(pixmap: &mut Pixmap, g: &ExportGeometry, color: (u8, u8, u8, u8)) {
|
||||||
|
let left = g.left();
|
||||||
|
let top = g.top();
|
||||||
|
let width = g.cols as f32 * g.cell;
|
||||||
|
let height = g.rows as f32 * g.cell;
|
||||||
|
|
||||||
|
let mut paint = Paint::default();
|
||||||
|
paint.set_color_rgba8(color.0, color.1, color.2, color.3);
|
||||||
|
|
||||||
for c in 0..=g.cols {
|
for c in 0..=g.cols {
|
||||||
let x = g.left() + c as f32 * g.cell;
|
let x = (left + c as f32 * g.cell).round();
|
||||||
draw_line(
|
let Some(rect) = Rect::from_xywh(x, top, 1.0, height) else {
|
||||||
pixmap,
|
continue;
|
||||||
x,
|
};
|
||||||
g.top(),
|
pixmap.fill_rect(rect, &paint, Transform::identity(), None);
|
||||||
x,
|
|
||||||
g.top() + g.rows as f32 * g.cell,
|
|
||||||
1.0,
|
|
||||||
color,
|
|
||||||
DoorStyle::Solid,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
for r in 0..=g.rows {
|
for r in 0..=g.rows {
|
||||||
let y = g.top() + r as f32 * g.cell;
|
let y = (top + r as f32 * g.cell).round();
|
||||||
draw_line(
|
let Some(rect) = Rect::from_xywh(left, y, width, 1.0) else {
|
||||||
pixmap,
|
continue;
|
||||||
g.left(),
|
};
|
||||||
y,
|
pixmap.fill_rect(rect, &paint, Transform::identity(), None);
|
||||||
g.left() + g.cols as f32 * g.cell,
|
|
||||||
y,
|
|
||||||
1.0,
|
|
||||||
color,
|
|
||||||
DoorStyle::Solid,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,7 +772,12 @@ fn draw_wall_segment(
|
|||||||
width: f32,
|
width: f32,
|
||||||
color: (u8, u8, u8, u8),
|
color: (u8, u8, u8, u8),
|
||||||
) {
|
) {
|
||||||
|
let width = width.round().max(1.0);
|
||||||
let half = width * 0.5;
|
let half = width * 0.5;
|
||||||
|
let x1 = x1.round();
|
||||||
|
let y1 = y1.round();
|
||||||
|
let x2 = x2.round();
|
||||||
|
let y2 = y2.round();
|
||||||
let rect = if (x1 - x2).abs() <= f32::EPSILON {
|
let rect = if (x1 - x2).abs() <= f32::EPSILON {
|
||||||
let x = x1.min(x2);
|
let x = x1.min(x2);
|
||||||
let y0 = y1.min(y2);
|
let y0 = y1.min(y2);
|
||||||
@@ -764,6 +799,14 @@ fn draw_wall_segment(
|
|||||||
pixmap.fill_rect(rect, &paint, Transform::identity(), None);
|
pixmap.fill_rect(rect, &paint, Transform::identity(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn snap_even_width(value: f32) -> f32 {
|
||||||
|
let mut w = value.round().max(1.0);
|
||||||
|
if (w as u32) % 2 == 1 {
|
||||||
|
w += 1.0;
|
||||||
|
}
|
||||||
|
w
|
||||||
|
}
|
||||||
|
|
||||||
fn append_svg_walls(
|
fn append_svg_walls(
|
||||||
out: &mut String,
|
out: &mut String,
|
||||||
g: &ExportGeometry,
|
g: &ExportGeometry,
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ pub struct UiSettings {
|
|||||||
pub export_width: u32,
|
pub export_width: u32,
|
||||||
pub export_height: u32,
|
pub export_height: u32,
|
||||||
pub allow_export_aspect_change: bool,
|
pub allow_export_aspect_change: bool,
|
||||||
|
pub export_show_grid: bool,
|
||||||
active_tab: Tab,
|
active_tab: Tab,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,6 +139,7 @@ impl Default for UiSettings {
|
|||||||
export_width: 1920,
|
export_width: 1920,
|
||||||
export_height: 1080,
|
export_height: 1080,
|
||||||
allow_export_aspect_change: false,
|
allow_export_aspect_change: false,
|
||||||
|
export_show_grid: true,
|
||||||
active_tab: Tab::Generate,
|
active_tab: Tab::Generate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,6 +275,11 @@ fn draw_generate_tab(ui: &mut egui::Ui, settings: &mut UiSettings, result: &mut
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui.add_space(6.0);
|
||||||
|
result.settings_changed |= ui
|
||||||
|
.checkbox(&mut settings.export_show_grid, "Include Grid In Export")
|
||||||
|
.changed();
|
||||||
|
|
||||||
if settings.export_format.supports_resolution() {
|
if settings.export_format.supports_resolution() {
|
||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
ui.checkbox(
|
ui.checkbox(
|
||||||
|
|||||||
Reference in New Issue
Block a user