made exporting a pool of images for maximum parrellelism
This commit is contained in:
+289
-172
@@ -109,6 +109,38 @@ struct SceneData {
|
|||||||
door_edges: HashSet<((usize, usize), (usize, usize))>,
|
door_edges: HashSet<((usize, usize), (usize, usize))>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum MaskTask {
|
||||||
|
Floors,
|
||||||
|
Walls,
|
||||||
|
Doors,
|
||||||
|
Archways,
|
||||||
|
LockedDoors,
|
||||||
|
SecretDoors,
|
||||||
|
Windows,
|
||||||
|
StartMarkers,
|
||||||
|
EndMarkers,
|
||||||
|
TrapMarkers,
|
||||||
|
MonsterMarkers,
|
||||||
|
Stairs,
|
||||||
|
Grid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum CompositeTask {
|
||||||
|
Mask(MaskTask),
|
||||||
|
Composite,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CompositeExportContext<'a> {
|
||||||
|
layout: &'a DungeonLayout,
|
||||||
|
folder: PathBuf,
|
||||||
|
geometry: ExportGeometry,
|
||||||
|
scene: SceneData,
|
||||||
|
wall_width: f32,
|
||||||
|
door_width: f32,
|
||||||
|
}
|
||||||
|
|
||||||
// Collect precomputed cell and edge sets needed for rendering.
|
// Collect precomputed cell and edge sets needed for rendering.
|
||||||
fn collect_scene_data(layout: &DungeonLayout, settings: &UiSettings) -> SceneData {
|
fn collect_scene_data(layout: &DungeonLayout, settings: &UiSettings) -> SceneData {
|
||||||
let mut scene = SceneData::default();
|
let mut scene = SceneData::default();
|
||||||
@@ -193,21 +225,10 @@ pub fn export_to_target(
|
|||||||
|
|
||||||
match target {
|
match target {
|
||||||
ExportTarget::Folder(folder) => {
|
ExportTarget::Folder(folder) => {
|
||||||
for &idx in &export_indices {
|
if settings.export_format == ExportFormat::Folder {
|
||||||
let layout = &layouts[idx];
|
export_composite_masks_for_levels(layouts, settings, &folder, &export_indices)?;
|
||||||
if settings.export_format == ExportFormat::Folder {
|
} else {
|
||||||
let subfolder = if settings.export_level_index == 999 {
|
export_level_images_to_folder(layouts, settings, &folder, &export_indices)?;
|
||||||
folder.join(format!("level {}", idx + 1))
|
|
||||||
} else {
|
|
||||||
folder.clone()
|
|
||||||
};
|
|
||||||
export_composite_masks(layout, settings, &subfolder)?;
|
|
||||||
} else {
|
|
||||||
let ext = settings.export_format.extension();
|
|
||||||
let filename = format!("level{}.{ext}", idx + 1);
|
|
||||||
let path = folder.join(filename);
|
|
||||||
save_layout_to_file(layout, settings, &path)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(folder)
|
Ok(folder)
|
||||||
}
|
}
|
||||||
@@ -219,6 +240,22 @@ pub fn export_to_target(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn export_level_images_to_folder(
|
||||||
|
layouts: &[DungeonLayout],
|
||||||
|
settings: &UiSettings,
|
||||||
|
folder: &std::path::Path,
|
||||||
|
export_indices: &[usize],
|
||||||
|
) -> Result<(), String> {
|
||||||
|
std::fs::create_dir_all(folder).map_err(|err| format!("Failed creating folder: {err}"))?;
|
||||||
|
|
||||||
|
let ext = settings.export_format.extension();
|
||||||
|
export_indices.par_iter().try_for_each(|&idx| {
|
||||||
|
let filename = format!("level{}.{ext}", idx + 1);
|
||||||
|
let path = folder.join(filename);
|
||||||
|
save_layout_to_file(&layouts[idx], settings, &path)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn save_layout_to_file(
|
fn save_layout_to_file(
|
||||||
layout: &DungeonLayout,
|
layout: &DungeonLayout,
|
||||||
settings: &UiSettings,
|
settings: &UiSettings,
|
||||||
@@ -250,6 +287,15 @@ fn save_layout_to_file(
|
|||||||
fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap, String> {
|
fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap, String> {
|
||||||
let g = ExportGeometry::new(settings.cols, settings.rows);
|
let g = ExportGeometry::new(settings.cols, settings.rows);
|
||||||
let scene = collect_scene_data(layout, settings);
|
let scene = collect_scene_data(layout, settings);
|
||||||
|
render_pixmap_with_scene(layout, settings, &g, &scene)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_pixmap_with_scene(
|
||||||
|
layout: &DungeonLayout,
|
||||||
|
settings: &UiSettings,
|
||||||
|
g: &ExportGeometry,
|
||||||
|
scene: &SceneData,
|
||||||
|
) -> Result<Pixmap, String> {
|
||||||
let mut pixmap =
|
let mut 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);
|
||||||
@@ -258,11 +304,11 @@ fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap
|
|||||||
let door_w = (g.cell / 5.0).max(1.0).round();
|
let door_w = (g.cell / 5.0).max(1.0).round();
|
||||||
|
|
||||||
if settings.export_show_grid {
|
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);
|
||||||
if settings.colorblind_mode {
|
if settings.colorblind_mode {
|
||||||
let (cx, cy) = g.cell_center(x, y);
|
let (cx, cy) = g.cell_center(x, y);
|
||||||
draw_dot(&mut pixmap, cx, cy, g.cell * 0.14, BLACK);
|
draw_dot(&mut pixmap, cx, cy, g.cell * 0.14, BLACK);
|
||||||
@@ -270,15 +316,15 @@ fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap
|
|||||||
}
|
}
|
||||||
|
|
||||||
for room in &layout.rooms {
|
for room in &layout.rooms {
|
||||||
fill_rect_room(&mut pixmap, &g, room, ROOM);
|
fill_rect_room(&mut pixmap, g, room, ROOM);
|
||||||
if settings.colorblind_mode {
|
if settings.colorblind_mode {
|
||||||
draw_room_crosshatch(&mut pixmap, &g, room, 1.5, BLACK);
|
draw_room_crosshatch(&mut pixmap, g, room, 1.5, BLACK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_cell_walls(
|
draw_cell_walls(
|
||||||
&mut pixmap,
|
&mut pixmap,
|
||||||
&g,
|
g,
|
||||||
&scene.corridor_cells,
|
&scene.corridor_cells,
|
||||||
Some(&scene.corridor_edges),
|
Some(&scene.corridor_edges),
|
||||||
&scene.door_edges,
|
&scene.door_edges,
|
||||||
@@ -287,7 +333,7 @@ fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap
|
|||||||
);
|
);
|
||||||
draw_cell_walls(
|
draw_cell_walls(
|
||||||
&mut pixmap,
|
&mut pixmap,
|
||||||
&g,
|
g,
|
||||||
&scene.room_cells,
|
&scene.room_cells,
|
||||||
Some(&scene.room_edges),
|
Some(&scene.room_edges),
|
||||||
&scene.door_edges,
|
&scene.door_edges,
|
||||||
@@ -316,7 +362,7 @@ fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap
|
|||||||
} else {
|
} else {
|
||||||
(OPEN_DOOR, DoorStyle::Solid)
|
(OPEN_DOOR, DoorStyle::Solid)
|
||||||
};
|
};
|
||||||
draw_door(&mut pixmap, &g, door, door_w, color, style);
|
draw_door(&mut pixmap, g, door, door_w, color, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
for window in &layout.windows {
|
for window in &layout.windows {
|
||||||
@@ -325,12 +371,12 @@ fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap
|
|||||||
} else {
|
} else {
|
||||||
DoorStyle::Solid
|
DoorStyle::Solid
|
||||||
};
|
};
|
||||||
draw_window(&mut pixmap, &g, window, door_w, WINDOW, style);
|
draw_window(&mut pixmap, g, window, door_w, WINDOW, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_area_marker_group(
|
draw_area_marker_group(
|
||||||
&mut pixmap,
|
&mut pixmap,
|
||||||
&g,
|
g,
|
||||||
&layout.start_markers,
|
&layout.start_markers,
|
||||||
"S",
|
"S",
|
||||||
START_MARKER,
|
START_MARKER,
|
||||||
@@ -338,7 +384,7 @@ fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap
|
|||||||
);
|
);
|
||||||
draw_area_marker_group(
|
draw_area_marker_group(
|
||||||
&mut pixmap,
|
&mut pixmap,
|
||||||
&g,
|
g,
|
||||||
&layout.end_markers,
|
&layout.end_markers,
|
||||||
"E",
|
"E",
|
||||||
END_MARKER,
|
END_MARKER,
|
||||||
@@ -346,7 +392,7 @@ fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap
|
|||||||
);
|
);
|
||||||
draw_area_marker_group(
|
draw_area_marker_group(
|
||||||
&mut pixmap,
|
&mut pixmap,
|
||||||
&g,
|
g,
|
||||||
&layout.trap_markers,
|
&layout.trap_markers,
|
||||||
"T",
|
"T",
|
||||||
TRAP_MARKER,
|
TRAP_MARKER,
|
||||||
@@ -354,7 +400,7 @@ fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap
|
|||||||
);
|
);
|
||||||
draw_area_marker_group(
|
draw_area_marker_group(
|
||||||
&mut pixmap,
|
&mut pixmap,
|
||||||
&g,
|
g,
|
||||||
&layout.monster_markers,
|
&layout.monster_markers,
|
||||||
"M",
|
"M",
|
||||||
MONSTER_MARKER,
|
MONSTER_MARKER,
|
||||||
@@ -363,7 +409,7 @@ fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap
|
|||||||
|
|
||||||
draw_staircase_group(
|
draw_staircase_group(
|
||||||
&mut pixmap,
|
&mut pixmap,
|
||||||
&g,
|
g,
|
||||||
&layout.stairs,
|
&layout.stairs,
|
||||||
STAIRS,
|
STAIRS,
|
||||||
settings.colorblind_mode,
|
settings.colorblind_mode,
|
||||||
@@ -372,35 +418,36 @@ fn render_pixmap(layout: &DungeonLayout, settings: &UiSettings) -> Result<Pixmap
|
|||||||
Ok(pixmap)
|
Ok(pixmap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export composite image plus mask layers into a folder.
|
// Export composite images and masks using one global task queue.
|
||||||
fn export_composite_masks(
|
fn export_composite_masks_for_levels(
|
||||||
layout: &DungeonLayout,
|
layouts: &[DungeonLayout],
|
||||||
settings: &UiSettings,
|
settings: &UiSettings,
|
||||||
folder: &std::path::Path,
|
folder: &std::path::Path,
|
||||||
|
export_indices: &[usize],
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
std::fs::create_dir_all(folder).map_err(|e| format!("Failed creating folder: {e}"))?;
|
let contexts = export_indices
|
||||||
|
.iter()
|
||||||
|
.map(|&idx| {
|
||||||
|
let subfolder = if settings.export_level_index == 999 {
|
||||||
|
folder.join(format!("level {}", idx + 1))
|
||||||
|
} else {
|
||||||
|
folder.to_path_buf()
|
||||||
|
};
|
||||||
|
std::fs::create_dir_all(&subfolder)
|
||||||
|
.map_err(|err| format!("Failed creating folder: {err}"))?;
|
||||||
|
|
||||||
let g = ExportGeometry::new(settings.cols, settings.rows);
|
let geometry = ExportGeometry::new(settings.cols, settings.rows);
|
||||||
let scene = collect_scene_data(layout, settings);
|
let scene = collect_scene_data(&layouts[idx], settings);
|
||||||
let wall_w = (g.cell / 2.5).max(1.0);
|
Ok(CompositeExportContext {
|
||||||
let door_w = (g.cell / 5.0).max(1.0);
|
layout: &layouts[idx],
|
||||||
|
folder: subfolder,
|
||||||
// List of tasks to perform in parallel
|
geometry,
|
||||||
enum MaskTask {
|
scene,
|
||||||
Floors,
|
wall_width: (geometry.cell / 2.5).max(1.0),
|
||||||
Walls,
|
door_width: (geometry.cell / 5.0).max(1.0),
|
||||||
Doors,
|
})
|
||||||
Archways,
|
})
|
||||||
LockedDoors,
|
.collect::<Result<Vec<_>, String>>()?;
|
||||||
SecretDoors,
|
|
||||||
Windows,
|
|
||||||
StartMarkers,
|
|
||||||
EndMarkers,
|
|
||||||
TrapMarkers,
|
|
||||||
MonsterMarkers,
|
|
||||||
Stairs,
|
|
||||||
Grid,
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tasks = vec![
|
let mut tasks = vec![
|
||||||
MaskTask::Floors,
|
MaskTask::Floors,
|
||||||
@@ -421,129 +468,43 @@ fn export_composite_masks(
|
|||||||
tasks.push(MaskTask::Grid);
|
tasks.push(MaskTask::Grid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process masks in parallel
|
let export_tasks = contexts
|
||||||
tasks.into_par_iter().try_for_each(|task| {
|
.iter()
|
||||||
let (stem, pixmap) = match task {
|
.enumerate()
|
||||||
MaskTask::Floors => {
|
.flat_map(|(context_idx, _)| {
|
||||||
let mut pixmap = Pixmap::new(g.width, g.height).unwrap();
|
tasks
|
||||||
fill_bg(&mut pixmap, BLACK);
|
.iter()
|
||||||
for &(x, y) in &scene.corridor_cells {
|
.copied()
|
||||||
fill_rect_cell(&mut pixmap, &g, x, y, WHITE);
|
.map(move |task| (context_idx, CompositeTask::Mask(task)))
|
||||||
}
|
.chain(std::iter::once((context_idx, CompositeTask::Composite)))
|
||||||
for room in &layout.rooms {
|
})
|
||||||
fill_rect_room(&mut pixmap, &g, room, WHITE);
|
.collect::<Vec<_>>();
|
||||||
}
|
|
||||||
("floors_mask", pixmap)
|
|
||||||
}
|
|
||||||
MaskTask::Walls => {
|
|
||||||
let mut pixmap = Pixmap::new(g.width, g.height).unwrap();
|
|
||||||
fill_bg(&mut pixmap, BLACK);
|
|
||||||
draw_cell_walls(
|
|
||||||
&mut pixmap,
|
|
||||||
&g,
|
|
||||||
&scene.corridor_cells,
|
|
||||||
Some(&scene.corridor_edges),
|
|
||||||
&scene.door_edges,
|
|
||||||
wall_w,
|
|
||||||
WHITE,
|
|
||||||
);
|
|
||||||
draw_cell_walls(
|
|
||||||
&mut pixmap,
|
|
||||||
&g,
|
|
||||||
&scene.room_cells,
|
|
||||||
Some(&scene.room_edges),
|
|
||||||
&scene.door_edges,
|
|
||||||
wall_w,
|
|
||||||
WHITE,
|
|
||||||
);
|
|
||||||
("walls_mask", pixmap)
|
|
||||||
}
|
|
||||||
MaskTask::Doors => {
|
|
||||||
let mut pixmap = blank_mask(&g, "doors").unwrap();
|
|
||||||
for door in &layout.doors {
|
|
||||||
if !door.secret && !door.archway && !door.locked {
|
|
||||||
draw_door(&mut pixmap, &g, door, door_w, WHITE, DoorStyle::Solid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
("doors_mask", pixmap)
|
|
||||||
}
|
|
||||||
MaskTask::Archways => {
|
|
||||||
let mut pixmap = blank_mask(&g, "archways").unwrap();
|
|
||||||
for door in &layout.doors {
|
|
||||||
if door.archway {
|
|
||||||
draw_door(&mut pixmap, &g, door, door_w, WHITE, DoorStyle::Solid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
("archways_mask", pixmap)
|
|
||||||
}
|
|
||||||
MaskTask::LockedDoors => {
|
|
||||||
let mut pixmap = blank_mask(&g, "locked doors").unwrap();
|
|
||||||
for door in &layout.doors {
|
|
||||||
if door.locked {
|
|
||||||
draw_door(&mut pixmap, &g, door, door_w, WHITE, DoorStyle::Solid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
("locked_doors_mask", pixmap)
|
|
||||||
}
|
|
||||||
MaskTask::SecretDoors => {
|
|
||||||
let mut pixmap = blank_mask(&g, "secret doors").unwrap();
|
|
||||||
for door in &layout.doors {
|
|
||||||
if door.secret {
|
|
||||||
draw_door(&mut pixmap, &g, door, door_w, WHITE, DoorStyle::Solid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
("secret_doors_mask", pixmap)
|
|
||||||
}
|
|
||||||
MaskTask::Windows => {
|
|
||||||
let mut pixmap = blank_mask(&g, "windows").unwrap();
|
|
||||||
for window in &layout.windows {
|
|
||||||
draw_window(&mut pixmap, &g, window, door_w, WHITE, DoorStyle::Solid);
|
|
||||||
}
|
|
||||||
("windows_mask", pixmap)
|
|
||||||
}
|
|
||||||
MaskTask::StartMarkers => {
|
|
||||||
let mut pixmap = blank_mask(&g, "start markers").unwrap();
|
|
||||||
fill_marker_mask(&mut pixmap, &g, &layout.start_markers);
|
|
||||||
("start_markers_mask", pixmap)
|
|
||||||
}
|
|
||||||
MaskTask::EndMarkers => {
|
|
||||||
let mut pixmap = blank_mask(&g, "end markers").unwrap();
|
|
||||||
fill_marker_mask(&mut pixmap, &g, &layout.end_markers);
|
|
||||||
("end_markers_mask", pixmap)
|
|
||||||
}
|
|
||||||
MaskTask::TrapMarkers => {
|
|
||||||
let mut pixmap = blank_mask(&g, "trap markers").unwrap();
|
|
||||||
fill_marker_mask(&mut pixmap, &g, &layout.trap_markers);
|
|
||||||
("trap_markers_mask", pixmap)
|
|
||||||
}
|
|
||||||
MaskTask::MonsterMarkers => {
|
|
||||||
let mut pixmap = blank_mask(&g, "monster markers").unwrap();
|
|
||||||
fill_marker_mask(&mut pixmap, &g, &layout.monster_markers);
|
|
||||||
("monster_markers_mask", pixmap)
|
|
||||||
}
|
|
||||||
MaskTask::Stairs => {
|
|
||||||
let mut pixmap = blank_mask(&g, "stairs").unwrap();
|
|
||||||
for staircase in &layout.stairs {
|
|
||||||
fill_rect_staircase(&mut pixmap, &g, staircase, WHITE);
|
|
||||||
}
|
|
||||||
("stairs_mask", pixmap)
|
|
||||||
}
|
|
||||||
MaskTask::Grid => {
|
|
||||||
let mut pixmap = Pixmap::new(g.width, g.height).unwrap();
|
|
||||||
fill_bg(&mut pixmap, BLACK);
|
|
||||||
draw_grid_color(&mut pixmap, &g, WHITE);
|
|
||||||
("grid_mask", pixmap)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
save_mask_image(folder, stem, &pixmap, settings)
|
export_tasks
|
||||||
})?;
|
.into_par_iter()
|
||||||
|
.try_for_each(|(context_idx, task)| {
|
||||||
|
let context = &contexts[context_idx];
|
||||||
|
match task {
|
||||||
|
CompositeTask::Mask(mask_task) => {
|
||||||
|
let (stem, pixmap) = render_mask_pixmap(context, mask_task)?;
|
||||||
|
save_mask_image(&context.folder, stem, &pixmap, settings)
|
||||||
|
}
|
||||||
|
CompositeTask::Composite => save_composite_image(context, settings),
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
// Also export the composite image
|
Ok(())
|
||||||
let composite = render_pixmap(layout, settings)?;
|
}
|
||||||
|
|
||||||
|
fn save_composite_image(
|
||||||
|
context: &CompositeExportContext<'_>,
|
||||||
|
settings: &UiSettings,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let composite =
|
||||||
|
render_pixmap_with_scene(context.layout, settings, &context.geometry, &context.scene)?;
|
||||||
let composite_img = raster_image_from_pixmap(&composite, settings)?;
|
let composite_img = raster_image_from_pixmap(&composite, settings)?;
|
||||||
let composite_ext = settings.export_format.extension();
|
let composite_ext = settings.export_format.extension();
|
||||||
let composite_path = folder.join(format!("composite.{composite_ext}"));
|
let composite_path = context.folder.join(format!("composite.{composite_ext}"));
|
||||||
composite_img
|
composite_img
|
||||||
.save_with_format(&composite_path, export_image_format(settings.export_format))
|
.save_with_format(&composite_path, export_image_format(settings.export_format))
|
||||||
.map_err(|e| format!("Failed writing {}: {e}", composite_path.display()))?;
|
.map_err(|e| format!("Failed writing {}: {e}", composite_path.display()))?;
|
||||||
@@ -551,6 +512,162 @@ fn export_composite_masks(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_mask_pixmap(
|
||||||
|
context: &CompositeExportContext<'_>,
|
||||||
|
task: MaskTask,
|
||||||
|
) -> Result<(&'static str, Pixmap), String> {
|
||||||
|
let g = &context.geometry;
|
||||||
|
let scene = &context.scene;
|
||||||
|
let layout = context.layout;
|
||||||
|
|
||||||
|
let result = match task {
|
||||||
|
MaskTask::Floors => {
|
||||||
|
let mut pixmap = blank_mask(g, "floors")?;
|
||||||
|
for &(x, y) in &scene.corridor_cells {
|
||||||
|
fill_rect_cell(&mut pixmap, g, x, y, WHITE);
|
||||||
|
}
|
||||||
|
for room in &layout.rooms {
|
||||||
|
fill_rect_room(&mut pixmap, g, room, WHITE);
|
||||||
|
}
|
||||||
|
("floors_mask", pixmap)
|
||||||
|
}
|
||||||
|
MaskTask::Walls => {
|
||||||
|
let mut pixmap = blank_mask(g, "walls")?;
|
||||||
|
draw_cell_walls(
|
||||||
|
&mut pixmap,
|
||||||
|
g,
|
||||||
|
&scene.corridor_cells,
|
||||||
|
Some(&scene.corridor_edges),
|
||||||
|
&scene.door_edges,
|
||||||
|
context.wall_width,
|
||||||
|
WHITE,
|
||||||
|
);
|
||||||
|
draw_cell_walls(
|
||||||
|
&mut pixmap,
|
||||||
|
g,
|
||||||
|
&scene.room_cells,
|
||||||
|
Some(&scene.room_edges),
|
||||||
|
&scene.door_edges,
|
||||||
|
context.wall_width,
|
||||||
|
WHITE,
|
||||||
|
);
|
||||||
|
("walls_mask", pixmap)
|
||||||
|
}
|
||||||
|
MaskTask::Doors => {
|
||||||
|
let mut pixmap = blank_mask(g, "doors")?;
|
||||||
|
for door in &layout.doors {
|
||||||
|
if !door.secret && !door.archway && !door.locked {
|
||||||
|
draw_door(
|
||||||
|
&mut pixmap,
|
||||||
|
g,
|
||||||
|
door,
|
||||||
|
context.door_width,
|
||||||
|
WHITE,
|
||||||
|
DoorStyle::Solid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
("doors_mask", pixmap)
|
||||||
|
}
|
||||||
|
MaskTask::Archways => {
|
||||||
|
let mut pixmap = blank_mask(g, "archways")?;
|
||||||
|
for door in &layout.doors {
|
||||||
|
if door.archway {
|
||||||
|
draw_door(
|
||||||
|
&mut pixmap,
|
||||||
|
g,
|
||||||
|
door,
|
||||||
|
context.door_width,
|
||||||
|
WHITE,
|
||||||
|
DoorStyle::Solid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
("archways_mask", pixmap)
|
||||||
|
}
|
||||||
|
MaskTask::LockedDoors => {
|
||||||
|
let mut pixmap = blank_mask(g, "locked doors")?;
|
||||||
|
for door in &layout.doors {
|
||||||
|
if door.locked {
|
||||||
|
draw_door(
|
||||||
|
&mut pixmap,
|
||||||
|
g,
|
||||||
|
door,
|
||||||
|
context.door_width,
|
||||||
|
WHITE,
|
||||||
|
DoorStyle::Solid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
("locked_doors_mask", pixmap)
|
||||||
|
}
|
||||||
|
MaskTask::SecretDoors => {
|
||||||
|
let mut pixmap = blank_mask(g, "secret doors")?;
|
||||||
|
for door in &layout.doors {
|
||||||
|
if door.secret {
|
||||||
|
draw_door(
|
||||||
|
&mut pixmap,
|
||||||
|
g,
|
||||||
|
door,
|
||||||
|
context.door_width,
|
||||||
|
WHITE,
|
||||||
|
DoorStyle::Solid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
("secret_doors_mask", pixmap)
|
||||||
|
}
|
||||||
|
MaskTask::Windows => {
|
||||||
|
let mut pixmap = blank_mask(g, "windows")?;
|
||||||
|
for window in &layout.windows {
|
||||||
|
draw_window(
|
||||||
|
&mut pixmap,
|
||||||
|
g,
|
||||||
|
window,
|
||||||
|
context.door_width,
|
||||||
|
WHITE,
|
||||||
|
DoorStyle::Solid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
("windows_mask", pixmap)
|
||||||
|
}
|
||||||
|
MaskTask::StartMarkers => {
|
||||||
|
let mut pixmap = blank_mask(g, "start markers")?;
|
||||||
|
fill_marker_mask(&mut pixmap, g, &layout.start_markers);
|
||||||
|
("start_markers_mask", pixmap)
|
||||||
|
}
|
||||||
|
MaskTask::EndMarkers => {
|
||||||
|
let mut pixmap = blank_mask(g, "end markers")?;
|
||||||
|
fill_marker_mask(&mut pixmap, g, &layout.end_markers);
|
||||||
|
("end_markers_mask", pixmap)
|
||||||
|
}
|
||||||
|
MaskTask::TrapMarkers => {
|
||||||
|
let mut pixmap = blank_mask(g, "trap markers")?;
|
||||||
|
fill_marker_mask(&mut pixmap, g, &layout.trap_markers);
|
||||||
|
("trap_markers_mask", pixmap)
|
||||||
|
}
|
||||||
|
MaskTask::MonsterMarkers => {
|
||||||
|
let mut pixmap = blank_mask(g, "monster markers")?;
|
||||||
|
fill_marker_mask(&mut pixmap, g, &layout.monster_markers);
|
||||||
|
("monster_markers_mask", pixmap)
|
||||||
|
}
|
||||||
|
MaskTask::Stairs => {
|
||||||
|
let mut pixmap = blank_mask(g, "stairs")?;
|
||||||
|
for staircase in &layout.stairs {
|
||||||
|
fill_rect_staircase(&mut pixmap, g, staircase, WHITE);
|
||||||
|
}
|
||||||
|
("stairs_mask", pixmap)
|
||||||
|
}
|
||||||
|
MaskTask::Grid => {
|
||||||
|
let mut pixmap = blank_mask(g, "grid")?;
|
||||||
|
draw_grid_color(&mut pixmap, g, WHITE);
|
||||||
|
("grid_mask", pixmap)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
fn blank_mask(g: &ExportGeometry, name: &str) -> Result<Pixmap, String> {
|
fn blank_mask(g: &ExportGeometry, name: &str) -> Result<Pixmap, String> {
|
||||||
let mut pixmap = Pixmap::new(g.width, g.height)
|
let mut pixmap = Pixmap::new(g.width, g.height)
|
||||||
.ok_or_else(|| format!("Failed to allocate {name} mask canvas"))?;
|
.ok_or_else(|| format!("Failed to allocate {name} mask canvas"))?;
|
||||||
|
|||||||
Reference in New Issue
Block a user