FireMaze — Shape Boundaries & Image Masking

Define the walkable area of your maze using geometric shape boundaries or a black-and-white image mask. Both systems produce a blocked[y][x] boolean grid that the generation algorithms respect.

← Back to FireMaze

1. Overview

Shape boundaries and image masks serve the same purpose — they mark cells as blocked (outside the shape/mask) or unblocked (inside). The two systems are merged during generation: a cell is blocked if either the shape mask or the image mask marks it as blocked.

Blocked cells are treated as solid walls by all generation algorithms. Rooms, entrances, exits, and stairs all respect the blocked mask.

2. Shape Boundaries

Maze Settings panel — Rectangular grids only

Available Shapes

ShapeDescriptionTest function
Rectangle (rect)Standard rectangular boundary. No masking applied.(always returns True)
Diamond (diamond)Manhattan-distance diamond: |u-0.5| + |v-0.5| ≤ 0.5_inside_diamond
Triangle (triangle)Equilateral triangle inscribed in the grid, pointing upward._inside_triangle (ray-casting polygon test)
Hexagon (hexagon)Regular flat-top hexagon inscribed in the grid._inside_hexagon (ray-casting polygon test)

Shape Rotation

shape_rotation — Enum: 0°, 90°, 180°, 270°

Rotates the shape boundary around the grid center. The rotation is implemented by transforming the test point backwards:

def _rotate_point(u, v, angle_rad):
    cu, cv = u - 0.5, v - 0.5
    ru = cu * cos(angle) - cv * sin(angle) + 0.5
    rv = cu * sin(angle) + cv * cos(angle) + 0.5
    return ru, rv

How It Works

  1. get_shape_mask(width, depth, shape, rotation) produces a blocked[y][x] grid.
  2. Each cell centre (x+0.5, y+0.5) is normalised to (u, v) in [0,1]×[0,1].
  3. The point is rotated backwards by the shape rotation angle.
  4. The appropriate shape test function determines if the point is inside.
  5. Cells outside the shape are marked blocked[y][x] = True.

Smooth Shape Edges

smooth_shape_edges — Toggle (default OFF)

When enabled, boundary cells at the shape contour receive additional geometry to create a smoother outline. Two methods are available:

Filler Triangles

smooth_boundary_method = 'filler'

Generates extra triangular faces at the shape contour to fill gaps between the square grid and the shape boundary.

  • Floor filler triangles (_build_smooth_floor_triangles): Adds triangles at floor height for boundary cells that intersect the shape contour. The contour polygon is built from cell corners that fall outside the shape, sorted by angle around the grid center. For each boundary edge segment, a triangular face is fan-triangulated from two contour vertices and the nearest inside-grid corner.
  • Roof filler triangles (_build_smooth_roof_triangles): Same logic at roof height.

The filler triangles:

  • Are generated per-floor (multilevel mazes get filler on each level).
  • Use the same material offsets as regular tiles.
  • Respect dirty-cell tracking during incremental rebuilds.
  • Skip edges where the associated cells are not all wall cells (open cells don't get filler geometry).

Clipped Tiles

smooth_boundary_method = 'clip'

Clips floor and roof tiles to the shape boundary contour instead of generating extra filler triangles. The clipping is handled by clip_cell in shape_boundaries.py, which:

  1. Identifies cells with mixed inside/outside corner status.
  2. Finds the exact boundary crossing point via binary search (_intersect_segment).
  3. Constructs a clipped polygon from the inside corners and crossing points.
  4. Fan-triangulates the polygon and returns world-space vertices and triangle indices.

Shape Boundary Vertices

get_shape_boundary_verts(width, depth, shape, tile_size, rotation) returns the world-space polygon vertices of the shape contour. Used for debug visualization and future mesh-clipping features.

Boundary Candidates for Entrances/Exits

_get_shape_boundary_candidates(blocked, width, depth) finds cells on the shape boundary — unblocked cells adjacent to blocked or out-of-bounds cells — and returns them with their outward-facing direction (N/S/E/W). This ensures entrances and exits can be placed on the actual shape contour rather than the grid rectangle.

3. Image Masking

Session & Image Management panel — Rectangular grids only

Use a black-and-white image to define the walkable shape of the maze. White pixels = walkable (path), black pixels = blocked (wall).

Loading a Mask

  • Load Mask from DiskMAZE_OT_load_mask_image (ImportHelper). Supports PNG, JPG, BMP, and TGA files. Loads the image as a Blender Image datablock and assigns it to mask_image.
  • Selected Maskmask_image (Image pointer). Manually pick an existing Blender Image datablock.

How Sampling Works

_get_image_mask_data(mask_image, invert, width, depth):

  1. For each cell (x, y):
    • Compute the pixel coordinate at the cell centre:
    px = int(((x + 0.5) / width) * img_w)
    py = int(((y + 0.5) / depth) * img_h)
    • Sample the pixel's RGB channels.
    • Compute luminance: brightness = 0.299R + 0.587G + 0.114B
    • If brightness < 0.5, the cell is blocked.
  2. Returns a blocked[y][x] boolean grid matching the maze dimensions.

Invert Mask

mask_invert — Toggle (default OFF)

When enabled, the luminance is inverted before the threshold test:

if invert:
    brightness = 1.0 - brightness

This swaps the interpretation: black pixels become walkable, white pixels become blocked.

Restrictions

  • Image masking is only available for Rectangular grids.
  • Image masking is automatically disabled when floors > 1 — a warning label appears in the UI: "Mask disabled when floors > 1". The mask is silently ignored during generation if floors > 1.
  • The mask image is not packed into session files — pointer references are stored by name and must exist in the current .blend file on load.

4. Mask Merging

During generation, the shape mask and image mask are merged into a single blocked grid via _merge_shape_mask:

blocked = _get_image_mask_data(mask_image, mask_invert, width, depth)
if shape_blocked is not None:
    blocked = _merge_shape_mask(blocked, shape_blocked)

A cell is blocked if either the image mask or the shape mask marks it as blocked (logical OR). The merge function handles dimension mismatches (e.g., when the maze uses doubled internal resolution) by mapping coordinates appropriately.

5. Integration with Generation

Algorithm Handling

All generation algorithms accept a blocked grid and use it to:

  • DFS, Kruskal's, Prim's, Wilson's, Growing Tree: Initialize visited with blocked cells so they are never traversed. Start cell selection uses _get_start_cell, which scans for the first unblocked cell near the grid center.
  • Eller's: Skips blocked rows/cells during row processing. Horizontal runs only merge across unblocked cells. Vertical connections only go to unblocked cells in the next row.
  • Binary Tree / Sidewinder: Checks blocked neighbors before carving passages in the biased direction.
  • Recursive Division: Excludes blocked regions from subdivision. Only subdivides non-blocked rectangular areas.

Room Placement

Rooms respect the blocked mask. If a room's placement overlaps any blocked cell, the room is skipped entirely, ensuring image-masked and shape-masked layouts remain intact.

Entrance & Exit Placement

Entrances and exits are placed on the outer boundary. When shape boundaries are active, _get_shape_boundary_candidates provides the actual contour cells for placement. The generation code validates that entrance and exit cells are not blocked and raises errors if all candidates are blocked.

Stair Placement

Stairs are filtered after placement to remove any stair that landed on a masked cell (for thin wall mode rectangular grids).

6. Shape Boundary Edges (Smooth Mode)

When smooth_shape_edges is enabled, the smooth floor/roof triangle generation uses get_boundary_edges and get_segmented_boundary_polygon from shape_boundaries.py:

  • get_segmented_boundary_polygon: Computes and caches the boundary polygon by finding cell corners that fall outside the shape, adjacent to inside cells, sorted by angle around the grid center.
  • get_boundary_edges: Returns world-space edge segments representing the shape boundary contour inside a given cell. Used for wall clipping at the shape contour.

7. UI Reference

Maze Settings Panel

ControlPropertyShown when
Shapemaze_shapeRectangular grid
Rotationshape_rotationShape is not Rectangle
Smooth Shape Edgessmooth_shape_edgesShape is not Rectangle
Boundary Methodsmooth_boundary_methodSmooth Shape Edges is ON

Session & Image Management Panel

ControlPropertyShown when
Load Mask from Disk(operator)Rectangular grid
Selected Maskmask_imageRectangular grid
Invert Mask Colorsmask_invertA mask is assigned

Limitations

  • Shape boundaries and image masking are rectangular grid only.
  • Image masking is disabled when floors > 1.
  • When both shape and image masks are active, the blocked area is the union of both (a cell is blocked if either mask blocks it).