patterns — diffuse

generator verdict no votes yet
source — color/auto/e004_diffuse.g54_diffuse
def g54_diffuse(rng):
    """Diffuse — an error-diffusion quantiser; each cell's index is carried forward, not rounded in place.

    A continuous field is sampled once per cell. Instead of snapping each sample
    to its nearest ramp step, the leftover quantisation error is pushed into the
    cells ahead of it (a Floyd-Steinberg kernel, serpentine so it alternates
    direction row to row), so the field's true average survives as a diffused
    texture rather than a set of hard, banded steps.
    """
    N = rng.choice([20, 25, 30, 40, 50])
    steps = rng.randint(6, 12)
    palette = rng.choice(PALETTE_NAMES)
    c = Canvas(N, palette, steps, "diffuse", "mosaic", tiles=False)

    field = Field(rng, warp=rng.uniform(0.0, 0.35), steps=steps)
    field.calibrate(N)

    levels = steps - 1
    vals = [[field.raw((i + 0.5) / N, (j + 0.5) / N) * levels for i in range(N)]
            for j in range(N)]
    state = [[0] * N for _ in range(N)]

    for j in range(N):
        left_to_right = (j % 2 == 0)
        cols = range(N) if left_to_right else range(N - 1, -1, -1)
        ahead = 1 if left_to_right else -1
        for i in cols:
            v = vals[j][i]
            k = max(0, min(levels, int(round(v))))
            state[j][i] = k
            err = v - k
            ni = i + ahead
            if 0 <= ni < N:
                vals[j][ni] += err * (7 / 16)
            if j + 1 < N:
                bi = i - ahead
                if 0 <= bi < N:
                    vals[j + 1][bi] += err * (3 / 16)
                vals[j + 1][i] += err * (5 / 16)
                if 0 <= ni < N:
                    vals[j + 1][ni] += err * (1 / 16)

    c.ground(lambda i, j: state[j][i])

    return c
diffuse-mosaic-40-464e
diffuse-mosaic-40-464e
diffuse-mosaic-50-8247
diffuse-mosaic-50-8247
diffuse-mosaic-20-ef97
diffuse-mosaic-20-ef97

generator