[Proc Gen] HeightMap - Direct source sampling (add_noise, add_bsp) #209

Open
opened 2026-01-12 00:11:35 +00:00 by john · 0 comments
Owner

Parent Issue: #192
Depends On: #193 (HeightMap core), #202 (BSP core), #207 (NoiseSource core)

Overview

Add methods to HeightMap for directly sampling from NoiseSource and BSP without creating intermediate objects. This is the efficient path for large maps.

Specification

Noise Sampling

def add_noise(self,
              source: NoiseSource,
              world_origin: tuple[float, float] = (0.0, 0.0),
              world_size: tuple[float, float] = None,
              mode: str = "fbm",
              octaves: int = 4,
              scale: float = 1.0) -> HeightMap

Sample noise and add to current values.

def multiply_noise(self, source: NoiseSource, **kwargs) -> HeightMap

Sample noise and multiply with current values.

Parameter Type Description
source NoiseSource The noise generator to sample from.
world_origin (float, float) World coordinates of top-left. Default: (0, 0).
world_size (float, float) World area to sample. Default: HeightMap size.
mode str "flat", "fbm", or "turbulence". Default: "fbm".
octaves int Octaves for fbm/turbulence. Default: 4.
scale float Multiplier for sampled values. Default: 1.0.

BSP Sampling

def add_bsp(self,
            bsp: BSP,
            select: str = "leaves",
            nodes: list[BSPNode] = None,
            shrink: int = 0,
            value: float = 1.0) -> HeightMap

Add BSP node regions to heightmap.

def multiply_bsp(self, bsp: BSP, **kwargs) -> HeightMap

Multiply by BSP regions (masking).

Parameter Type Description
bsp BSP The BSP tree to sample from.
select str "leaves", "all", or "internal". Default: "leaves".
nodes list[BSPNode] Override: specific nodes only.
shrink int Pixels to shrink from node bounds. Default: 0.
value float Value to add/multiply inside regions. Default: 1.0.

Example

# Efficient terrain generation for large map
terrain = mcrfpy.HeightMap(size=(1000, 1000))

# Add base noise directly (no NoiseSample allocation)
terrain.add_noise(noise, mode="fbm", octaves=6)
terrain.normalize()

# Mask to BSP rooms directly (no BSPMap allocation)
terrain.multiply_bsp(bsp, select="leaves", shrink=1)

Implementation Notes

  • These are more efficient than creating NoiseSample/BSPMap for large maps
  • No intermediate HeightMap allocation - writes directly to target
  • Same coordinate conventions as NoiseSample: (origin, size) format
  • multiply_bsp effectively masks the heightmap to room interiors

Performance Comparison

For a 1000×1000 heightmap:

Approach Allocations Notes
noise.sample() then hmap.add() 2 × 4MB Creates intermediate
hmap.add_noise() 0 Direct write
bsp.to_heightmap() then hmap.multiply() 2 × 4MB Creates intermediate
hmap.multiply_bsp() 0 Direct write

Acceptance Criteria

  • add_noise and multiply_noise work correctly
  • add_bsp and multiply_bsp work correctly
  • Results match equivalent NoiseSample/BSPMap approach
  • Performance measurably better for large maps
  • Unit tests verify correctness
**Parent Issue:** #192 **Depends On:** #193 (HeightMap core), #202 (BSP core), #207 (NoiseSource core) ## Overview Add methods to HeightMap for directly sampling from NoiseSource and BSP without creating intermediate objects. This is the efficient path for large maps. ## Specification ### Noise Sampling ```python def add_noise(self, source: NoiseSource, world_origin: tuple[float, float] = (0.0, 0.0), world_size: tuple[float, float] = None, mode: str = "fbm", octaves: int = 4, scale: float = 1.0) -> HeightMap ``` Sample noise and add to current values. ```python def multiply_noise(self, source: NoiseSource, **kwargs) -> HeightMap ``` Sample noise and multiply with current values. | Parameter | Type | Description | |-----------|------|-------------| | `source` | `NoiseSource` | The noise generator to sample from. | | `world_origin` | `(float, float)` | World coordinates of top-left. Default: (0, 0). | | `world_size` | `(float, float)` | World area to sample. Default: HeightMap size. | | `mode` | `str` | `"flat"`, `"fbm"`, or `"turbulence"`. Default: `"fbm"`. | | `octaves` | `int` | Octaves for fbm/turbulence. Default: 4. | | `scale` | `float` | Multiplier for sampled values. Default: 1.0. | ### BSP Sampling ```python def add_bsp(self, bsp: BSP, select: str = "leaves", nodes: list[BSPNode] = None, shrink: int = 0, value: float = 1.0) -> HeightMap ``` Add BSP node regions to heightmap. ```python def multiply_bsp(self, bsp: BSP, **kwargs) -> HeightMap ``` Multiply by BSP regions (masking). | Parameter | Type | Description | |-----------|------|-------------| | `bsp` | `BSP` | The BSP tree to sample from. | | `select` | `str` | `"leaves"`, `"all"`, or `"internal"`. Default: `"leaves"`. | | `nodes` | `list[BSPNode]` | Override: specific nodes only. | | `shrink` | `int` | Pixels to shrink from node bounds. Default: 0. | | `value` | `float` | Value to add/multiply inside regions. Default: 1.0. | ### Example ```python # Efficient terrain generation for large map terrain = mcrfpy.HeightMap(size=(1000, 1000)) # Add base noise directly (no NoiseSample allocation) terrain.add_noise(noise, mode="fbm", octaves=6) terrain.normalize() # Mask to BSP rooms directly (no BSPMap allocation) terrain.multiply_bsp(bsp, select="leaves", shrink=1) ``` ## Implementation Notes - These are **more efficient** than creating NoiseSample/BSPMap for large maps - No intermediate HeightMap allocation - writes directly to target - Same coordinate conventions as NoiseSample: `(origin, size)` format - `multiply_bsp` effectively masks the heightmap to room interiors ## Performance Comparison For a 1000×1000 heightmap: | Approach | Allocations | Notes | |----------|-------------|-------| | `noise.sample()` then `hmap.add()` | 2 × 4MB | Creates intermediate | | `hmap.add_noise()` | 0 | Direct write | | `bsp.to_heightmap()` then `hmap.multiply()` | 2 × 4MB | Creates intermediate | | `hmap.multiply_bsp()` | 0 | Direct write | ## Acceptance Criteria - [ ] `add_noise` and `multiply_noise` work correctly - [ ] `add_bsp` and `multiply_bsp` work correctly - [ ] Results match equivalent NoiseSample/BSPMap approach - [ ] Performance measurably better for large maps - [ ] Unit tests verify correctness
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
john/McRogueFace#209
No description provided.