mirror of
https://github.com/misode/misode.github.io.git
synced 2026-04-23 07:10:41 +00:00
103 lines
2.6 KiB
TypeScript
103 lines
2.6 KiB
TypeScript
import SimplexNoise from 'simplex-noise'
|
|
import { DataModel, Path, ModelPath } from "@mcschema/core"
|
|
import { Visualizer } from './Visualizer'
|
|
|
|
const debug = false
|
|
|
|
export class NoiseSettingsVisualizer extends Visualizer {
|
|
private noise: SimplexNoise
|
|
private offsetX: number
|
|
|
|
constructor() {
|
|
super()
|
|
this.noise = new SimplexNoise()
|
|
this.offsetX = 0
|
|
}
|
|
|
|
getName() {
|
|
return 'noise-settings'
|
|
}
|
|
|
|
active(path: ModelPath) {
|
|
return path.endsWith(new Path(['noise']))
|
|
}
|
|
|
|
draw(model: DataModel, img: ImageData) {
|
|
const data = img.data
|
|
for (let x = 0; x < 200; x += 1) {
|
|
const densities = this.fillNoiseColumn(x - this.offsetX).reverse()
|
|
for (let y = 0; y < 100; y += 1) {
|
|
const i = (y * (img.width * 4)) + (x * 4)
|
|
const color = this.getColor(densities, y)
|
|
data[i] = (debug && densities[y] > 0) ? 255 : color
|
|
data[i + 1] = color
|
|
data[i + 2] = color
|
|
data[i + 3] = 255
|
|
}
|
|
}
|
|
}
|
|
|
|
onDrag(fromX: number, fromY: number, toX: number, toY: number) {
|
|
this.offsetX += toX - fromX
|
|
}
|
|
|
|
private getColor(densities: number[], y: number): number {
|
|
if (debug) {
|
|
return -densities[y] * 128 + 128
|
|
}
|
|
if (densities[y] > 0) {
|
|
return 0
|
|
}
|
|
if (densities[y+1] > 0) {
|
|
return 150
|
|
}
|
|
return 255
|
|
}
|
|
|
|
private fillNoiseColumn(x: number) {
|
|
const data = Array(100)
|
|
for (let y = 0; y < 100; y += 1) {
|
|
let density = this.getNoise(x, y)
|
|
density = density < -1 ? -1 : density > 1 ? 1 : density
|
|
|
|
const heightFactor = (1 - y / 50) * this.state.density_factor + this.state.density_offset
|
|
density += heightFactor * (heightFactor > 0 ? 16 : 4)
|
|
|
|
if (this.state.top_slide.size > 0) {
|
|
density = this.clampedLerp(
|
|
this.state.top_slide.target / 100,
|
|
density,
|
|
(100 - y - (this.state.top_slide.offset * 4)) / (this.state.top_slide.size * 4)
|
|
)
|
|
}
|
|
|
|
if (this.state.bottom_slide.size > 0) {
|
|
density = this.clampedLerp(
|
|
this.state.bottom_slide.target / 100,
|
|
density,
|
|
(y - (this.state.bottom_slide.offset * 4)) / (this.state.bottom_slide.size * 4)
|
|
)
|
|
}
|
|
data[y] = density
|
|
}
|
|
return data
|
|
}
|
|
|
|
private getNoise(x: number, y: number) {
|
|
const octaves = [ [64, 1], [32, 2], [16, 4], [8, 8], [4, 16] ]
|
|
return octaves
|
|
.map(o => this.noise.noise2D(x / o[0], y / o[0]) / o[1])
|
|
.reduce((prev, acc) => prev + acc)
|
|
}
|
|
|
|
private clampedLerp(a: number, b: number, c: number): number {
|
|
if (c < 0) {
|
|
return a;
|
|
} else if (c > 1) {
|
|
return b
|
|
} else {
|
|
return a + c * (b - a);
|
|
}
|
|
}
|
|
}
|