From 88d6014dfa631c5680cf09a573c8097b78311c3d Mon Sep 17 00:00:00 2001 From: Misode Date: Fri, 7 Aug 2020 00:45:31 +0200 Subject: [PATCH] Implement BiomeNoiseVisualizer --- src/app/visualization/BiomeNoiseVisualizer.ts | 61 ++++++++++++++++--- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/src/app/visualization/BiomeNoiseVisualizer.ts b/src/app/visualization/BiomeNoiseVisualizer.ts index 616ad3aa..ce092ca3 100644 --- a/src/app/visualization/BiomeNoiseVisualizer.ts +++ b/src/app/visualization/BiomeNoiseVisualizer.ts @@ -2,11 +2,14 @@ import SimplexNoise from 'simplex-noise' import { DataModel, Path } from "@mcschema/core"; import { Visualizer } from './VisualizerView'; + export class BiomeNoiseVisualizer implements Visualizer { - private noise: SimplexNoise + static readonly noiseMaps = ['altitude', 'temperature', 'humidity', 'weirdness'] + private noise: SimplexNoise[] + private biomeSource: any constructor() { - this.noise = new SimplexNoise() + this.noise = BiomeNoiseVisualizer.noiseMaps.map(e => new SimplexNoise()) } path() { @@ -20,17 +23,61 @@ export class BiomeNoiseVisualizer implements Visualizer { } draw(model: DataModel, img: ImageData) { - const biomeSource = model.get(new Path(['generator', 'biome_source'])) + this.biomeSource = model.get(new Path(['generator', 'biome_source'])) const data = img.data for (let x = 0; x < 200; x += 1) { for (let y = 0; y < 100; y += 1) { const i = (y * (img.width * 4)) + (x * 4) - const b = (this.noise.noise2D(x/50, y/50) > 0) ? 0 : 255 - data[i] = b - data[i + 1] = b - data[i + 2] = b + const b = this.closestBiome(x, y) + const color = this.colorFromBiome(b) + data[i] = color[0] + data[i + 1] = color[1] + data[i + 2] = color[2] data[i + 3] = 255 } } } + + private closestBiome(x: number, y: number): string { + const noise = this.getNoise(x, y) + if (!this.biomeSource.biomes) return '' + + return this.biomeSource.biomes + .map((b: any) => ({ + biome: b.biome ?? '', + distance: this.distance([...noise, 0], [...BiomeNoiseVisualizer.noiseMaps.map(s => b.parameters[s]), b.parameters.offset]) + })) + .sort((a: any, b: any) => a.distance - b.distance) + [0].biome + } + + private distance(a: number[], b: number[]) { + let d = 0 + for (let i = 0; i < a.length; i ++) { + d += (a[i]-b[i]) * (a[i]-b[i]) + } + return d + } + + private getNoise(x: number, y: number): number[] { + return BiomeNoiseVisualizer.noiseMaps.map((id, index) => { + const config = this.biomeSource[`${id}_noise`] + let n = 0 + let scale = 2**config.firstOctave + for (let i = 0; i < config.amplitudes.length; i++) { + n += this.noise[index].noise2D(x*scale, y*scale + i) * config.amplitudes[i] * 128 / scale + scale *= 2 + } + return n + }) + } + + private colorFromBiome(biome: string): number[] { + const h = Math.abs(this.hash(biome)) + return [h % 256, (h >> 8) % 256, (h >> 16) % 256] + } + + private hash(s: string) { + return s.split('').reduce((a,b)=>{a=((a<<5)-a)+b.charCodeAt(0);return a&a},0) + } }