Skip to content

Commit

Permalink
can't stop messing with lakes and deposition. Also, filled background…
Browse files Browse the repository at this point in the history
…s and subaquatic streams
  • Loading branch information
jmdejong committed Oct 1, 2023
1 parent bed561a commit 4c26a01
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 38 deletions.
16 changes: 16 additions & 0 deletions display.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,20 @@ class Display {
this.ctx.arc(center.x, center.y, radius, 0, Math.PI * 2);
this.ctx.fill();
}

eachPixel(fn) {
let imgData = this.ctx.createImageData(this.canvas.width, this.canvas.height);
let data = imgData.data;
for (let x=0; x<this.canvas.width; ++x) {
for (let y=0; y<this.canvas.height; ++y) {
let [r, g, b] = fn(vec2(x, y));
let i = (x + y * this.canvas.width) * 4;
data[i] = r*255|0;
data[i+1] = g*255|0;
data[i+2] = b*255|0;
data[i+3] = 255;
}
}
this.ctx.putImageData(imgData, 0, 0);
}
}
32 changes: 22 additions & 10 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
</label>
<label>
size
<input type="number" name="size" value="1024" />
<input type="number" name="size" value="1024" min="1"/>
</label>
<label>
node size
<input type="number" name="nodeSize" value="8" />
<input type="number" name="nodeSize" value="8" min="1"/>
</label>
<label>
node randomness
Expand Down Expand Up @@ -86,6 +86,10 @@
lake size
<input type="number" name="lakeSize" value="50" min="1" />
</label>
<label>
lake depth
<input type="number" name="lakeDepth" value="0.1" min="0" step="0.01" />
</label>
<br />

<label>
Expand All @@ -99,16 +103,20 @@
<input type="number" name="erosion" value="16" />
</label>
<label>
subaquatic erosion
<input type="number" name="fjords" value="1" />
sea erosion
<input type="number" name="seaErosion" value="1" step="0.01" />
</label>
<label>
lake erosion
<input type="number" name="lakeErosion" value="1" step="0.01" />
</label>
<label>
stream deposition
<input type="number" name="deposition" value="0" step="0.001" min="0" max="1"/>
</label>
<label>
lake/sea deposition
<input type="number" name="lakeDeposition" value="0" step="0.001" min="0" max="1"/>
lake/sea deposition factor
<input type="number" name="lakeDeposition" value="0" step="0.1" min="0"/>
</label>
<br />

Expand All @@ -130,10 +138,18 @@
draw rivers
<input type="checkbox" name="drawRivers" checked />
</label>
<label>
draw underwater streams
<input type="checkbox" name="drawUnderwaterStreams" />
</label>
<label>
draw circles
<input type="checkbox" name="drawCircles" checked />
</label>
<label>
draw area
<input type="checkbox" name="drawArea" checked />
</label>
<label>
height of max color
<input type="number" name="colorMax" value="2" step="0.1" min="0"/>
Expand All @@ -142,10 +158,6 @@
draw pre-erosion result
<input type="checkbox" name="drawPartial" />
</label>
<label>
draw lakes deeper than
<input type="number" name="minLakeDepth" value="0.01" step="0.001" min="0"/>
</label>
<br />

<input type="submit" value="Generate" />
Expand Down
95 changes: 67 additions & 28 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,35 @@ class NodeGraph {
}
}

nearest(pos) {
let vy = pos.y / this.ns / TRIHEIGHT;
let vx = pos.x / this.ns - vy / 2;
let xf = Math.floor(vx);
let yf = Math.floor(vy);
let xc = Math.ceil(vx);
let yc = Math.ceil(vy);
let candidates = [vec2(xf, yc), vec2(xc, yf)];
// if (vx + vy >1) {
candidates.push(vec2(xc, yc));
// } else {
candidates.push(vec2(xf, yf));
// }
let bestDist = Infinity;
let best = null;
for (let candidate of candidates) {
let node = this.getNode(candidate);
if (!node) {
continue;
}
let distance = node.pos.sub(pos).length()
if (distance < bestDist) {
bestDist = distance
best = node;
}
}
return best;
}

draw(id, settings) {
let colors = [[0, 0.5, 0], [0.0, 0.9, 0.0], [0.5, 0.9, 0.1], [0.9, 0.85, 0.2], [0.8, 0.6, 0.0], [0.9, 0.2, 0], [1, 0, 0], [0.75, 0, 0], [0.5, 0, 0], [0.25, 0, 0], [0, 0, 0]];
let colorscale = colors.length / settings.colorMax;
Expand All @@ -154,12 +183,24 @@ class NodeGraph {
canvas.width = this.size.x;
canvas.height = this.size.y;
let display = new Display(canvas)
if (settings.drawArea) {
display.eachPixel(p => {
let n = this.nearest(p);
if (n.isSea()) {
return [0, 0, 0.9];
} else if (n.isWaterBody()) {
return [0.3, 0.3, 1];
} else {
return color(n.height());
}
});
}
if (settings.drawCircles) {
for (let node of this.nodes.values()) {
if (node.isSea() || node.waterHeight > settings.minLakeDepth) {
display.circle(node.pos, this.ns *0.65, "#00a");
} else if (node.lake) {
display.circle(node.pos, this.ns *0.65, "#00f");
if (node.isSea()) {
display.circle(node.pos, this.ns *0.65, "#00c");
} else if (node.isWaterBody()) {
display.circle(node.pos, this.ns *0.65, "#44f");
} else {
let [r, g, b] = color(node.height()).map(c => c*255);
let col = `rgb(${r}, ${g}, ${b})`;
Expand All @@ -169,17 +210,10 @@ class NodeGraph {
}
if (settings.drawRivers) {
for (let node of this.nodes.values()) {
if (node.isWaterBody()) {/*
for (let neighbour of this.neighbours(node)) {
if (neighbour && neighbour.isSea()) {
display.line(node.pos, neighbour.pos, "#008", this.ns/2);
}
}*/
} else {
if (node.water < 1.1) {
continue;
}
let drain = this.drain(node);
if (node.isSink() || node.water < 1.1 || !settings.drawUnderwaterStreams && node.isWaterBody()) {
continue;
}
for (let drain of this.drains(node)) {
display.line(node.pos, drain.pos, "#22f", clamp(Math.sqrt(node.water)/5, 0.5, 5));
}
}
Expand Down Expand Up @@ -221,12 +255,12 @@ class World {
}
}

land(plainsSlope, lakeAmount, lakeSize) {
land(settings) {
let noise = new FastNoiseLite(hash(this.graph.seed^23790));
noise.SetNoiseType(FastNoiseLite.NoiseType.OpenSimplex2);
noise.SetFractalType(FastNoiseLite.FractalType.FBm);
noise.SetFractalOctaves(8);
noise.SetFrequency(1/lakeSize);
noise.SetFrequency(1/settings.lakeSize);
let fringe = new PriorityFringe(node => node.height());
let visited = new Set();
let processed = new Set();
Expand All @@ -247,13 +281,13 @@ class World {
neighbour.waterHeight = node.height() - neighbour.baseHeight + 1e-6 * randf(neighbour.id, this.graph.seed ^ 4890);
neighbour.sea = true;
} else {
let l = clamp(noise.GetNoise(neighbour.pos.x, neighbour.pos.y) + lakeAmount * 2 - 1, -1, 1);
let l = clamp(noise.GetNoise(neighbour.pos.x, neighbour.pos.y) + settings.lakeAmount * 2 - 1, -1, 1);
if (l > 0) {
neighbour.waterHeight = l * (node.height() - neighbour.height());
neighbour.waterHeight = l * (node.height() - neighbour.height()) * settings.lakeDepth;
let totalHeight = node.height() + 1e-6 * randf(neighbour.id, this.graph.seed ^ 8429);
neighbour.baseHeight = totalHeight - neighbour.waterHeight;
} else {
neighbour.baseHeight = node.height() + randf(neighbour.id, this.graph.seed ^ 3627) * plainsSlope / (node.height() - neighbour.height() + 1);
neighbour.baseHeight = node.height() + randf(neighbour.id, this.graph.seed ^ 3627) * settings.plainsSlope / (node.height() - neighbour.height() + 1);
}
}
}
Expand Down Expand Up @@ -284,7 +318,7 @@ class World {
}
}

erode(nodes, amount, fjords) {
erode(nodes, amount, settings) {
for (let node of nodes) {
if (node.isSink()) {
continue;
Expand All @@ -297,7 +331,9 @@ class World {
let water = drain.isSink() ? 1 : drain.water;
let erosion = Math.sqrt(water) * amount / this.graph.ns;
if (node.isSea()) {
erosion = fjords;
erosion *= settings.seaErosion;
} else if (node.isWaterBody()) {
erosion *= settings.lakeErosion;
}
let newHeight = Math.min(drain.baseHeight + dh / Math.max(1,erosion), node.baseHeight);
let eroded = node.baseHeight - newHeight;
Expand All @@ -307,7 +343,7 @@ class World {
}
}

depose(nodes, amount, lakeAmount) {
depose(nodes, amount, lakeDepose) {
if (amount <= 0) {
return;
}
Expand All @@ -317,13 +353,16 @@ class World {
this.sediment.lost += node.sediment;
continue;
}
let deposited = node.sediment * (node.isWaterBody() ? lakeAmount : amount) / node.water;
let drains = this.graph.drains(node);
let deposited = node.sediment * amount / node.water;
if (node.isWaterBody() && drains.every(n => n.isWaterBody())) {
deposited *= lakeDepose;
}
node.sediment -= deposited;
node.changeGround(deposited);
this.sediment.deposited += deposited;

let sediment = node.sediment;
let drains = this.graph.drains(node);
for (let drain of drains) {
drain.sediment += sediment / drains.length;
}
Expand All @@ -341,7 +380,7 @@ function generate(settings) {
let world = new World(graph);
time("heighten", () => world.heighten(settings.amplitude, settings.featureSize, settings.baseHeight));
time("cut edge", () => world.cutEdge(settings.edgeHeight, size * 0.005 * settings.edgePercentage, settings.edgeMode == "add", settings.edgeShape == "parabole"));
let sorted = time("land", () => world.land(settings.plainsSlope, settings.lakeAmount, settings.lakeSize));
let sorted = time("land", () => world.land(settings));
time("drain", () => world.drain(sorted, settings.rainfall));
if (settings.drawPartial) {
time("draw partial", () => graph.draw("partial", settings));
Expand All @@ -351,12 +390,12 @@ function generate(settings) {
let erosionScale = scaleExp(settings.iterations, settings.erosionStep);
for (let i=0; i<settings.iterations; ++i) {
let erosion = settings.erosion * Math.pow(settings.erosionStep, i) * erosionScale;
time("erode", () => world.erode(sorted, erosion, settings.fjords));
time("erode", () => world.erode(sorted, erosion, settings));
if (!(settings.skipFinalDepose &&i === settings.iterations - 1)) {
time("depose", () => world.depose(sorted, settings.deposition, settings.lakeDeposition));
}
graph.reset();
sorted = time("land", () => world.land(settings.plainsSlope, settings.lakeAmount, settings.lakeSize));
sorted = time("land", () => world.land(settings));
time("drain", () => world.drain(sorted, settings.rainfall));
}
time("draw", () => graph.draw(null, settings));
Expand Down
6 changes: 6 additions & 0 deletions vec2.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ class Vec2 {
return vec2(this.x + v.x, this.y + v.y);
}

sub(v) {
return vec2(this.x - v.x, this.y - v.y);
}

toUint() {
return this.x | (this.y << 16);
}
Expand All @@ -40,6 +44,8 @@ class Vec2 {
return vec2(this.x, this.y);
}



diamond() {
if (Math.abs(this.x) + Math.abs(this.y) > 1) {
let v = this.clone();
Expand Down

0 comments on commit 4c26a01

Please sign in to comment.