Nooncraft/worldgen/tests.py

124 lines
3.2 KiB
Python
Executable File

#! /usr/bin/env python3
from PIL import Image
import random
import math
WIDTH = 128
HEIGHT = 128
BIOMES = 16
PERLIN_CELL_SIZE = 32
# Voronoi diagram by jump flooding
def voronoi(seeds):
world = [[-1] * WIDTH for i in range(HEIGHT)]
for i, (x, y) in enumerate(seeds):
world[y][x] = i
N = WIDTH // 2
while N > 0:
for py in range(HEIGHT):
for px in range(WIDTH):
for dy in [-N, 0, N]:
for dx in [-N, 0, N]:
qx, qy = px + dx, py + dy
if qx < 0 or qx >= WIDTH or qy < 0 or qy >= HEIGHT:
continue
if world[py][px] < 0 and world[qy][qx] >= 0:
world[py][px] = world[qy][qx]
elif world[py][px] >= 0 and world[qy][qx] >= 0:
spx, spy = seeds[world[py][px]]
sqx, sqy = seeds[world[qy][qx]]
dist_sp_2 = (py - spy) ** 2 + (px - spx) ** 2
dist_sq_2 = (py - sqy) ** 2 + (px - sqx) ** 2
if dist_sq_2 < dist_sp_2:
world[py][px] = world[qy][qx]
N //= 2
return world
# --== Generate a biome center map with the jump-flood algorithm ==--
def random_color():
r = random.randint(0, 256)
g = random.randint(0, 256)
b = random.randint(0, 256)
return (r, g, b)
def random_palette(N):
return [random_color() for i in range(N)]
seeds = [(random.randint(0, WIDTH-1), random.randint(0, HEIGHT-1))
for i in range(BIOMES)]
biomes = voronoi(seeds)
def show_biomes(biomes):
img = Image.new("RGBA", (WIDTH, HEIGHT))
px = img.load()
palette = random_palette(BIOMES)
for y in range(HEIGHT):
for x in range(WIDTH):
px[x,y] = palette[biomes[y][x]]
img.show()
# show_biomes(biomes)
# --== Generate some Perlin noise ==--
pregradients = []
for i in range(16):
alpha = 2 * math.pi * i / 16
pregradients.append((math.cos(alpha), math.sin(alpha)))
def random_grid(N):
N = WIDTH // PERLIN_CELL_SIZE + 1
return [[random.choice(pregradients) for x in range(N)] for y in range(N)]
def smooth(t):
return t * t * t * (t * (6 * t - 15) + 10)
def interp(x, y, t):
return y * t + x * (1.0 - t)
def dot(grid, ix, iy, fx, fy):
gx, gy = grid[iy][ix]
return (fx - ix) * gx + (fy - iy) * gy
def perlin_at(grid, fx, fy):
ix = int(fx)
iy = int(fy)
d0 = dot(grid, ix, iy, fx, fy)
d1 = dot(grid, ix+1, iy, fx, fy)
d2 = dot(grid, ix, iy+1, fx, fy)
d3 = dot(grid, ix+1, iy+1, fx, fy)
rx = smooth(fx - ix)
ry = smooth(fy - iy)
return interp(interp(d0, d1, rx), interp(d2, d3, rx), ry)
PERLIN_N = WIDTH // PERLIN_CELL_SIZE
grid = random_grid(PERLIN_N)
def show_perlin(grid):
img = Image.new("RGBA", (WIDTH, HEIGHT))
px = img.load()
for y in range(HEIGHT):
for x in range(WIDTH):
fx, fy = x / PERLIN_CELL_SIZE, y / PERLIN_CELL_SIZE
noise = perlin_at(grid, fx, fy)
gray = 128 + round(noise * 128)
px[x, y] = (gray, gray, gray)
img.show()
show_perlin(grid)