McRogueFace/docs/cookbook/procgen/20_noise_algorithms.py

125 lines
4 KiB
Python
Raw Permalink Normal View History

2026-01-13 19:42:37 -05:00
"""NoiseSource Algorithms Demo
Demonstrates: simplex, perlin, wavelet noise algorithms
Shows visual differences between noise types.
"""
import mcrfpy
from mcrfpy import automation
GRID_WIDTH, GRID_HEIGHT = 64, 48
CELL_SIZE = 16
def value_to_terrain(h):
"""Convert noise value (-1 to 1) to terrain color."""
# Normalize from -1..1 to 0..1
h = (h + 1) / 2
h = max(0.0, min(1.0, h))
if h < 0.3:
t = h / 0.3
return mcrfpy.Color(int(30 + t * 40), int(60 + t * 60), int(140 + t * 40))
elif h < 0.45:
t = (h - 0.3) / 0.15
return mcrfpy.Color(int(70 + t * 120), int(120 + t * 60), int(100 - t * 60))
elif h < 0.6:
t = (h - 0.45) / 0.15
return mcrfpy.Color(int(60 + t * 20), int(130 + t * 20), int(50 + t * 10))
elif h < 0.75:
t = (h - 0.6) / 0.15
return mcrfpy.Color(int(50 + t * 50), int(110 - t * 20), int(40 + t * 20))
elif h < 0.88:
t = (h - 0.75) / 0.13
return mcrfpy.Color(int(100 + t * 40), int(95 + t * 35), int(80 + t * 40))
else:
t = (h - 0.88) / 0.12
return mcrfpy.Color(int(180 + t * 70), int(180 + t * 70), int(190 + t * 60))
def run_demo(runtime):
panel_w = GRID_WIDTH // 3
panel_h = GRID_HEIGHT // 2
algorithms = [
('simplex', "SIMPLEX", "Fast, no visible artifacts"),
('perlin', "PERLIN", "Classic, slight grid bias"),
('wavelet', "WAVELET", "Smooth, no tiling"),
]
# Top row: FBM (natural terrain)
# Bottom row: Raw noise (single octave)
for col, (algo, name, desc) in enumerate(algorithms):
ox = col * panel_w
# Create noise source
noise = mcrfpy.NoiseSource(
dimensions=2,
algorithm=algo,
hurst=0.5,
lacunarity=2.0,
seed=42
)
# Top panel: FBM
for y in range(panel_h):
for x in range(panel_w):
# Sample at world coordinates
wx = x * 0.15
wy = y * 0.15
val = noise.fbm((wx, wy), octaves=5)
color_layer.set(((ox + x, y)), value_to_terrain(val))
# Bottom panel: Raw (flat)
for y in range(panel_h):
for x in range(panel_w):
wx = x * 0.15
wy = y * 0.15
val = noise.get((wx, wy))
color_layer.set(((ox + x, panel_h + y)), value_to_terrain(val))
# Labels
top_label = mcrfpy.Caption(text=f"{name} (FBM)", pos=(ox * CELL_SIZE + 5, 5))
top_label.fill_color = mcrfpy.Color(255, 255, 255)
top_label.outline = 1
top_label.outline_color = mcrfpy.Color(0, 0, 0)
scene.children.append(top_label)
bottom_label = mcrfpy.Caption(text=f"{name} (raw)", pos=(ox * CELL_SIZE + 5, panel_h * CELL_SIZE + 5))
bottom_label.fill_color = mcrfpy.Color(255, 255, 255)
bottom_label.outline = 1
bottom_label.outline_color = mcrfpy.Color(0, 0, 0)
scene.children.append(bottom_label)
desc_label = mcrfpy.Caption(text=desc, pos=(ox * CELL_SIZE + 5, 22))
desc_label.fill_color = mcrfpy.Color(200, 200, 200)
desc_label.outline = 1
desc_label.outline_color = mcrfpy.Color(0, 0, 0)
scene.children.append(desc_label)
# Grid lines
for y in range(GRID_HEIGHT):
color_layer.set(((panel_w - 1, y)), mcrfpy.Color(80, 80, 80))
color_layer.set(((panel_w * 2 - 1, y)), mcrfpy.Color(80, 80, 80))
for x in range(GRID_WIDTH):
color_layer.set(((x, panel_h - 1)), mcrfpy.Color(80, 80, 80))
# Setup
scene = mcrfpy.Scene("noise_algo_demo")
grid = mcrfpy.Grid(
grid_size=(GRID_WIDTH, GRID_HEIGHT),
pos=(0, 0),
size=(GRID_WIDTH * CELL_SIZE, GRID_HEIGHT * CELL_SIZE),
layers={}
)
grid.fill_color = mcrfpy.Color(0, 0, 0)
color_layer = grid.add_layer("color", z_index=-1)
scene.children.append(grid)
scene.activate()
# Run the demo
run_demo(0)
# Take screenshot
automation.screenshot("procgen_20_noise_algorithms.png")
print("Screenshot saved: procgen_20_noise_algorithms.png")