added /find command & reworked some of the back-end stuff in Core

This commit is contained in:
dags- 2020-02-09 01:48:40 +00:00
parent e853f3d347
commit 446b036414
31 changed files with 498 additions and 307 deletions

View File

@ -58,13 +58,13 @@ public abstract class Renderer {
if (cell.tag == applet.getCache().getTerrain().coast) {
hue = 15;
}
float modifier = cell.mask;
float modifier = cell.mask(0.4F, 0.5F, 0F, 1F);
float modAlpha = 0.1F;
float mod = (1 - modAlpha) + (modifier * modAlpha);
float sat = 70;
float bri = 70;
applet.fill(hue, 65, 70);
return height * el;
return cell.regionEdge * el;
} else if(applet.controller.getColorMode() == Applet.EROSION) {
float change = cell.sediment + cell.erosion;
float value = Math.abs(cell.sediment * 250);

View File

@ -18,9 +18,13 @@ public class Cell<T extends Tag> {
public float continent;
public float continentEdge;
public float region;
public float regionEdge;
public float biome;
public float biomeEdge = 1F;
public float riverMask = 1F;
public float value;
public float biome;
public float biomeMoisture;
public float biomeTemperature;
public float moisture;
@ -28,49 +32,53 @@ public class Cell<T extends Tag> {
public float steepness;
public float erosion;
public float sediment;
public float mask = 1F;
public float biomeMask = 1F;
public float biomeTypeMask = 1F;
public float regionMask = 1F;
public float riverMask = 1F;
public BiomeType biomeType = BiomeType.GRASSLAND;
public T tag = null;
public void copy(Cell<T> other) {
value = other.value;
continent = other.continent;
continentEdge = other.continentEdge;
value = other.value;
biome = other.biome;
region = other.region;
regionEdge = other.regionEdge;
biome = other.biome;
biomeEdge = other.biomeEdge;
biomeMask = other.biomeMask;
riverMask = other.riverMask;
biomeMoisture = other.biomeMoisture;
biomeTemperature = other.biomeTemperature;
mask = other.mask;
regionMask = other.regionMask;
moisture = other.moisture;
temperature = other.temperature;
biomeMoisture = other.biomeMoisture;
biomeTemperature = other.biomeTemperature;
steepness = other.steepness;
erosion = other.erosion;
sediment = other.sediment;
biomeType = other.biomeType;
biomeTypeMask = other.biomeTypeMask;
tag = other.tag;
}
public float combinedMask(float clamp) {
return NoiseUtil.map(biomeMask * regionMask, 0, clamp, clamp);
public float continentMask(float min, float max) {
return NoiseUtil.map(continentEdge, min, max, max - min);
}
public float biomeMask(float clamp) {
return NoiseUtil.map(biomeMask, 0, clamp, clamp);
public float regionMask(float min, float max) {
return NoiseUtil.map(regionEdge, min, max, max - min);
}
public float regionMask(float clamp) {
return NoiseUtil.map(regionMask, 0, clamp, clamp);
public float biomeMask(float min, float max) {
return NoiseUtil.map(biomeEdge, min, max, max - min);
}
public float mask(float cmin, float cmax, float rmin, float rmax) {
return riverMask * continentMask(cmin, cmax) * regionMask(rmin, rmax);
}
public boolean isAbsent() {

View File

@ -5,5 +5,5 @@ import com.terraforged.core.world.terrain.Terrain;
public interface Decorator {
void apply(Cell<Terrain> cell, float x, float y);
boolean apply(Cell<Terrain> cell, float x, float y);
}

View File

@ -0,0 +1,53 @@
package com.terraforged.core.decorator;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.world.GeneratorContext;
import com.terraforged.core.world.heightmap.Levels;
import com.terraforged.core.world.terrain.Terrain;
import com.terraforged.core.world.terrain.Terrains;
import me.dags.noise.Module;
import me.dags.noise.Source;
import me.dags.noise.func.CellFunc;
public class DesertDunes implements Decorator {
private final Module module;
private final float climateMin;
private final float climateMax;
private final float climateRange;
private final Levels levels;
private final Terrains terrains;
private final Terrain dunes = new Terrain("dunes", 100);
public DesertDunes(GeneratorContext context) {
this.climateMin = 0.6F;
this.climateMax = 0.85F;
this.climateRange = climateMax - climateMin;
this.levels = context.levels;
this.terrains = context.terrain;
this.module = Source.cell(context.seed.next(), 80, CellFunc.DISTANCE)
.warp(context.seed.next(), 70, 1, 70)
.scale(30 / 255D);
}
@Override
public boolean apply(Cell<Terrain> cell, float x, float y) {
float temp = cell.temperature;
float moisture = 1 - cell.moisture;
float climate = temp * moisture;
if (climate < climateMin) {
return false;
}
float duneHeight = module.getValue(x, y);
float climateMask = climate > climateMax ? 1F : (climate - climateMin) / climateRange;
float regionMask = cell.mask(0.4F, 0.5F, 0,0.8F);
float height = duneHeight * climateMask * regionMask;
cell.value += height;
cell.tag = dunes;
return height >= levels.unit;
}
}

View File

@ -12,6 +12,7 @@ public class DesertStacks implements Decorator {
private final float minY;
private final float maxY;
private final Levels levels;
private final Module module;
public DesertStacks(Seed seed, Levels levels) {
@ -35,21 +36,24 @@ public class DesertStacks implements Decorator {
this.minY = levels.water(0);
this.maxY = levels.water(50);
this.levels = levels;
this.module = stack.scale(scale).mult(mask);
}
@Override
public void apply(Cell<Terrain> cell, float x, float y) {
public boolean apply(Cell<Terrain> cell, float x, float y) {
if (BiomeType.DESERT != cell.biomeType) {
return;
return false;
}
if (cell.value <= minY || cell.value > maxY) {
return;
return false;
}
float value = module.getValue(x, y);
value *= cell.biomeMask;
value *= cell.biomeEdge;
cell.value += value;
return value > levels.unit;
}
}

View File

@ -30,21 +30,21 @@ public class SwampPools implements Decorator {
}
@Override
public void apply(Cell<Terrain> cell, float x, float y) {
public boolean apply(Cell<Terrain> cell, float x, float y) {
if (cell.tag == terrains.ocean) {
return;
return false;
}
if (cell.moisture < 0.7 || cell.temperature < 0.3) {
return;
return false;
}
if (cell.value <= minY) {
return;
return false;
}
if (cell.value > blendY) {
return;
return false;
}
float alpha = module.getValue(x, y);
@ -55,5 +55,6 @@ public class SwampPools implements Decorator {
}
cell.value = NoiseUtil.lerp(cell.value, minY, alpha);
return true;
}
}

View File

@ -18,8 +18,6 @@ public class Blender extends Select implements Populator {
private final float midpoint;
private final float tagThreshold;
private boolean mask = false;
public Blender(Module control, Populator lower, Populator upper, float min, float max, float split) {
super(control);
this.lower = lower;
@ -42,11 +40,6 @@ public class Blender extends Select implements Populator {
this.tagThreshold = tagThreshold;
}
public Blender mask() {
mask = true;
return this;
}
@Override
public void apply(Cell<Terrain> cell, float x, float y) {
float select = getSelect(cell, x, y);
@ -74,10 +67,6 @@ public class Blender extends Select implements Populator {
if (select < midpoint) {
cell.tag = lowerType;
}
if (mask) {
cell.mask *= alpha;
}
}
@Override

View File

@ -1,29 +0,0 @@
package com.terraforged.core.module;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.cell.Populator;
import com.terraforged.core.world.heightmap.Heightmap;
import com.terraforged.core.world.terrain.Terrain;
public class CellLookup implements Populator {
private final int scale;
private final Heightmap heightmap;
public CellLookup(Heightmap heightmap, int scale) {
this.heightmap = heightmap;
this.scale = scale;
}
@Override
public void apply(Cell<Terrain> cell, float x, float y) {
float px = x * scale;
float pz = y * scale;
heightmap.getValue(px, pz);
}
@Override
public void tag(Cell<Terrain> cell, float x, float y) {
}
}

View File

@ -1,39 +0,0 @@
package com.terraforged.core.module;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.cell.Populator;
import com.terraforged.core.world.heightmap.Heightmap;
import com.terraforged.core.world.terrain.Terrain;
import me.dags.noise.Module;
import me.dags.noise.util.NoiseUtil;
public class CellLookupOffset implements Populator {
private final int scale;
private final Module direction;
private final Module strength;
private final Heightmap heightmap;
public CellLookupOffset(Heightmap heightmap, Module direction, Module strength, int scale) {
this.scale = scale;
this.heightmap = heightmap;
this.direction = direction;
this.strength = strength;
}
@Override
public void apply(Cell<Terrain> cell, float x, float y) {
float px = x * scale;
float pz = y * scale;
float str = strength.getValue(x, y);
float dir = direction.getValue(x, y) * NoiseUtil.PI2;
float dx = NoiseUtil.sin(dir) * str;
float dz = NoiseUtil.cos(dir) * str;
heightmap.visit(cell, px + dx, pz + dz);
}
@Override
public void tag(Cell<Terrain> cell, float x, float y) {
}
}

View File

@ -21,8 +21,6 @@ public class MultiBlender extends Select implements Populator {
private final float lowerRange;
private final float upperRange;
private boolean mask = false;
public MultiBlender(Climate climate, Populator control, Populator lower, Populator middle, Populator upper, float min, float mid, float max) {
super(control);
this.climate = climate;
@ -62,11 +60,6 @@ public class MultiBlender extends Select implements Populator {
float upperVal = cell.value;
cell.value = NoiseUtil.lerp(lowerVal, upperVal, alpha);
// cell.tag = lowerType;
if (mask) {
cell.mask *= alpha;
}
} else {
float alpha = Interpolation.CURVE3.apply((select - midpoint) / upperRange);
@ -75,10 +68,6 @@ public class MultiBlender extends Select implements Populator {
upper.apply(cell, x, y);
cell.value = NoiseUtil.lerp(lowerVal, cell.value, alpha);
if (mask) {
cell.mask *= alpha;
}
}
}

View File

@ -156,7 +156,9 @@ public class Region implements Extent {
int index = blockSize.indexOf(dx, dz);
GenCell cell = blocks[index];
for (Decorator decorator : decorators) {
decorator.apply(cell, getBlockX() + dx, getBlockZ() + dz);
if (decorator.apply(cell, getBlockX() + dx, getBlockZ() + dz)) {
break;
}
}
}
}

View File

@ -88,7 +88,7 @@ public class RegionGenerator implements RegionExtent {
if (filter) {
generator.getFilters().apply(region);
}
// region.decorateZoom(generator.getDecorators().getDecorators(), centerX, centerZ, zoom);
region.decorateZoom(generator.getDecorators().getDecorators(), centerX, centerZ, zoom);
}
public static Builder builder() {

View File

@ -80,11 +80,11 @@ public class GeneratorSettings {
@Range(min = 1, max = 200)
@Comment("Controls the scale of shape distortion for biomes")
public int biomeWarpScale = 30;
public int biomeWarpScale = 35;
@Range(min = 1, max = 200)
@Comment("Controls the strength of shape distortion for biomes")
public int biomeWarpStrength = 30;
public int biomeWarpStrength = 70;
}
@Serializable
@ -95,11 +95,11 @@ public class GeneratorSettings {
@Range(min = 1, max = 100)
@Comment("Controls the scale of the noise")
public int scale = 4;
public int scale = 8;
@Range(min = 1, max = 5)
@Comment("Controls the number of noise octaves")
public int octaves = 1;
public int octaves = 2;
@Range(min = 0F, max = 5.5F)
@Comment("Controls the gain subsequent noise octaves")
@ -107,11 +107,11 @@ public class GeneratorSettings {
@Range(min = 0F, max = 10.5F)
@Comment("Controls the lacunarity of subsequent noise octaves")
public float lacunarity = 2F;
public float lacunarity = 2.5F;
@Range(min = 1, max = 100)
@Comment("Controls the strength of the noise")
public int strength = 12;
public int strength = 24;
public Module build(int seed) {
return Source.build(seed, scale, octaves).gain(gain).lacunarity(lacunarity).build(type).bias(-0.5);

View File

@ -1,6 +1,7 @@
package com.terraforged.core.world;
import com.terraforged.core.decorator.Decorator;
import com.terraforged.core.decorator.DesertDunes;
import com.terraforged.core.decorator.DesertStacks;
import com.terraforged.core.decorator.SwampPools;

View File

@ -2,8 +2,6 @@ package com.terraforged.core.world.climate;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.world.GeneratorContext;
import com.terraforged.core.world.biome.BiomeType;
import com.terraforged.core.world.heightmap.WorldHeightmap;
import com.terraforged.core.world.terrain.Terrain;
import me.dags.noise.Module;
import me.dags.noise.Source;
@ -26,7 +24,7 @@ public class Climate {
private final ClimateModule biomeNoise;
public Climate(GeneratorContext context, WorldHeightmap heightmap) {
public Climate(GeneratorContext context) {
this.biomeNoise = new ClimateModule(context.seed, context.settings.generator);
this.treeLine = Source.perlin(context.seed.next(), context.settings.generator.biome.biomeSize * 2, 1)

View File

@ -104,10 +104,10 @@ public class ClimateModule {
}
if (mask) {
cell.biomeMask = edgeValue(edgeDistance, edgeDistance2);
cell.biomeEdge = edgeValue(edgeDistance, edgeDistance2);
} else {
cell.biome = cellValue(seed, cellX, cellY);
cell.biomeMask = edgeValue(edgeDistance, edgeDistance2);
cell.biomeEdge = edgeValue(edgeDistance, edgeDistance2);
cell.biomeMoisture = moisture.getValue(cellX + vec2f.x, cellY + vec2f.y);
cell.biomeTemperature = temperature.getValue(cellX + vec2f.x, cellY + vec2f.y);
cell.moisture = moisture.getValue(x, y);

View File

@ -1,21 +0,0 @@
package com.terraforged.core.world.continent;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.cell.Populator;
import com.terraforged.core.module.Blender;
import com.terraforged.core.world.terrain.Terrain;
public class ContinentBlender extends Blender {
private final Populator control;
public ContinentBlender(Populator continent, Populator lower, Populator upper, float min, float max, float split, float tagThreshold) {
super(continent, lower, upper, min, max, split, tagThreshold);
this.control = continent;
}
@Override
public float getSelect(Cell<Terrain> cell, float x, float z) {
return cell.continentEdge;
}
}

View File

@ -0,0 +1,78 @@
package com.terraforged.core.world.continent;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.cell.Populator;
import com.terraforged.core.world.terrain.Terrain;
import me.dags.noise.func.Interpolation;
import me.dags.noise.util.NoiseUtil;
public class ContinentLerper2 implements Populator {
private final Populator lower;
private final Populator upper;
private final float blendLower;
private final float blendUpper;
private final float blendRange;
private final float midpoint;
private final float tagThreshold;
public ContinentLerper2(Populator lower, Populator upper, float min, float max, float split, float tagThreshold) {
this.lower = lower;
this.upper = upper;
this.blendLower = min;
this.blendUpper = max;
this.blendRange = blendUpper - blendLower;
this.midpoint = blendLower + (blendRange * split);
this.tagThreshold = tagThreshold;
}
@Override
public void apply(Cell<Terrain> cell, float x, float y) {
float select = cell.continentEdge;
if (select < blendLower) {
lower.apply(cell, x, y);
return;
}
if (select > blendUpper) {
upper.apply(cell, x, y);
return;
}
float alpha = Interpolation.LINEAR.apply((select - blendLower) / blendRange);
lower.apply(cell, x, y);
float lowerVal = cell.value;
Terrain lowerType = cell.tag;
upper.apply(cell, x, y);
float upperVal = cell.value;
cell.value = NoiseUtil.lerp(lowerVal, upperVal, alpha);
if (select < midpoint) {
cell.tag = lowerType;
}
}
@Override
public void tag(Cell<Terrain> cell, float x, float y) {
float select = cell.continentEdge;
if (select < blendLower) {
lower.tag(cell, x, y);
return;
}
if (select > blendUpper) {
upper.tag(cell, x, y);
return;
}
if (select < tagThreshold) {
lower.tag(cell, x, y);
} else {
upper.tag(cell, x, y);
}
}
}

View File

@ -0,0 +1,96 @@
package com.terraforged.core.world.continent;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.cell.Populator;
import com.terraforged.core.module.MultiBlender;
import com.terraforged.core.world.climate.Climate;
import com.terraforged.core.world.terrain.Terrain;
import me.dags.noise.func.Interpolation;
import me.dags.noise.util.NoiseUtil;
public class ContinentLerper3 implements Populator {
private final Climate climate;
private final Populator lower;
private final Populator middle;
private final Populator upper;
private final float midpoint;
private final float blendLower;
private final float blendUpper;
private final float lowerRange;
private final float upperRange;
public ContinentLerper3(Climate climate, Populator lower, Populator middle, Populator upper, float min, float mid, float max) {
this.climate = climate;
this.lower = lower;
this.upper = upper;
this.middle = middle;
this.midpoint = mid;
this.blendLower = min;
this.blendUpper = max;
this.lowerRange = midpoint - blendLower;
this.upperRange = blendUpper - midpoint;
}
@Override
public void apply(Cell<Terrain> cell, float x, float y) {
float select = cell.continentEdge;
if (select < blendLower) {
lower.apply(cell, x, y);
return;
}
if (select > blendUpper) {
upper.apply(cell, x, y);
return;
}
if (select < midpoint) {
float alpha = Interpolation.CURVE3.apply((select - blendLower) / lowerRange);
lower.apply(cell, x, y);
float lowerVal = cell.value;
Terrain lowerType = cell.tag;
middle.apply(cell, x, y);
float upperVal = cell.value;
cell.value = NoiseUtil.lerp(lowerVal, upperVal, alpha);
} else {
float alpha = Interpolation.CURVE3.apply((select - midpoint) / upperRange);
middle.apply(cell, x, y);
float lowerVal = cell.value;
upper.apply(cell, x, y);
cell.value = NoiseUtil.lerp(lowerVal, cell.value, alpha);
}
}
@Override
public void tag(Cell<Terrain> cell, float x, float y) {
float select = cell.continentEdge;
if (select < blendLower) {
lower.tag(cell, x, y);
return;
}
if (select > blendUpper) {
upper.tag(cell, x, y);
return;
}
if (select < midpoint) {
lower.tag(cell, x, y);
if (cell.value > cell.tag.getMax(climate.getRand().getValue(x, y))) {
upper.tag(cell, x, y);
}
} else {
upper.tag(cell, x, y);
}
}
}

View File

@ -1,7 +1,141 @@
package com.terraforged.core.world.continent;
import me.dags.noise.Module;
import me.dags.noise.Source;
import me.dags.noise.domain.Domain;
import me.dags.noise.func.DistanceFunc;
import me.dags.noise.func.EdgeFunc;
import me.dags.noise.util.NoiseUtil;
import me.dags.noise.util.Vec2f;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.cell.Populator;
import com.terraforged.core.settings.GeneratorSettings;
import com.terraforged.core.util.Seed;
import com.terraforged.core.world.terrain.Terrain;
public interface ContinentModule extends Populator {
public class ContinentModule implements Populator {
private static final float edgeClampMin = 0.05F;
private static final float edgeClampMax = 0.50F;
private static final float edgeClampRange = edgeClampMax - edgeClampMin;
private final int seed;
private final float frequency;
private final float edgeMin;
private final float edgeMax;
private final float edgeRange;
private final Domain warp;
private final Module shape;
public ContinentModule(Seed seed, GeneratorSettings settings) {
int tectonicScale = settings.land.continentScale * 4;
int continentScale = settings.land.continentScale / 2;
double oceans = Math.min(Math.max(settings.world.oceanSize, 0.01), 0.99);
double shapeMin = 0.15 + (oceans * 0.35);
this.seed = seed.next();
this.frequency = 1F / tectonicScale;
this.edgeMin = edgeClampMin;
this.edgeMax = (float) oceans;
this.edgeRange = edgeMax - edgeMin;
this.warp = Domain.warp(Source.SIMPLEX, seed.next(), continentScale, 3, continentScale);
this.shape = Source.perlin(seed.next(), settings.land.continentScale, 2)
.clamp(shapeMin, 0.7)
.map(0, 1)
.warp(Source.SIMPLEX, seed.next(), continentScale / 2, 1, continentScale / 4D)
.warp(seed.next(), 50, 1, 20D);
}
@Override
public float getValue(float x, float y) {
if (true) {
throw new RuntimeException("no pls!");
} else {
Cell<Terrain> cell = new Cell<>();
apply(cell, x, y);
return cell.continentEdge;
}
}
@Override
public void apply(Cell<Terrain> cell, final float x, final float y) {
float ox = warp.getOffsetX(x, y);
float oz = warp.getOffsetY(x, y);
float px = x + ox;
float py = y + oz;
px *= frequency;
py *= frequency;
int cellX = 0;
int cellY = 0;
int xr = NoiseUtil.round(px);
int yr = NoiseUtil.round(py);
float edgeDistance = 999999.0F;
float edgeDistance2 = 999999.0F;
float valueDistance = 3.4028235E38F;
DistanceFunc dist = DistanceFunc.NATURAL;
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
int xi = xr + dx;
int yi = yr + dy;
Vec2f vec = NoiseUtil.CELL_2D[NoiseUtil.hash2D(seed, xi, yi) & 255];
float vecX = xi - px + vec.x;
float vecY = yi - py + vec.y;
float distance = dist.apply(vecX, vecY);
if (distance < valueDistance) {
valueDistance = distance;
cellX = xi;
cellY = yi;
}
if (distance < edgeDistance2) {
edgeDistance2 = Math.max(edgeDistance, distance);
} else {
edgeDistance2 = Math.max(edgeDistance, edgeDistance2);
}
edgeDistance = Math.min(edgeDistance, distance);
}
}
float shapeNoise = shape.getValue(x, y);
float continentNoise = edgeValue(edgeDistance, edgeDistance2);
cell.continent = cellValue(seed, cellX, cellY);
cell.continentEdge = shapeNoise * continentNoise;
}
@Override
public void tag(Cell<Terrain> cell, float x, float y) {
}
private float cellValue(int seed, int cellX, int cellY) {
float value = NoiseUtil.valCoord2D(seed, cellX, cellY);
return NoiseUtil.map(value, -1, 1, 2);
}
private float edgeValue(float distance, float distance2) {
EdgeFunc edge = EdgeFunc.DISTANCE_2_DIV;
float value = edge.apply(distance, distance2);
float edgeValue = 1 - NoiseUtil.map(value, edge.min(), edge.max(), edge.range());
if (edgeValue < edgeMin) {
return 0F;
}
if (edgeValue > edgeMax) {
return 1F;
}
return (edgeValue - edgeMin) / edgeRange;
}
}

View File

@ -1,22 +0,0 @@
package com.terraforged.core.world.continent;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.cell.Populator;
import com.terraforged.core.module.MultiBlender;
import com.terraforged.core.world.climate.Climate;
import com.terraforged.core.world.terrain.Terrain;
public class ContinentMultiBlender extends MultiBlender {
private final Populator control;
public ContinentMultiBlender(Climate climate, Populator continent, Populator lower, Populator middle, Populator upper, float min, float mid, float max) {
super(climate, continent, lower, middle, upper, min, mid, max);
this.control = continent;
}
@Override
public float getSelect(Cell<Terrain> cell, float x, float z) {
return cell.continentEdge;
}
}

View File

@ -7,6 +7,8 @@ public class Levels {
public final int worldHeight;
public final float unit;
// y index of the top-most water block
public final int waterY;
private final int groundY;
@ -23,6 +25,7 @@ public class Levels {
public Levels(GeneratorSettings settings) {
worldHeight = Math.max(1, settings.world.worldHeight);
unit = NoiseUtil.div(1, worldHeight);
waterLevel = settings.world.seaLevel;
groundLevel = waterLevel + 1;

View File

@ -3,17 +3,17 @@ package com.terraforged.core.world.heightmap;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.cell.Populator;
import com.terraforged.core.module.Blender;
import com.terraforged.core.module.Lerp;
import com.terraforged.core.module.MultiBlender;
import com.terraforged.core.module.Selector;
import com.terraforged.core.settings.GeneratorSettings;
import com.terraforged.core.settings.Settings;
import com.terraforged.core.util.Seed;
import com.terraforged.core.world.GeneratorContext;
import com.terraforged.core.world.climate.Climate;
import com.terraforged.core.world.continent.ContinentBlender;
import com.terraforged.core.world.continent.ContinentMultiBlender;
import com.terraforged.core.world.continent.VoronoiContinentModule;
import com.terraforged.core.world.continent.ContinentLerper2;
import com.terraforged.core.world.continent.ContinentLerper3;
import com.terraforged.core.world.continent.ContinentModule;
import com.terraforged.core.world.terrain.region.RegionLerper;
import com.terraforged.core.world.terrain.region.RegionModule;
import com.terraforged.core.world.terrain.region.RegionSelector;
import com.terraforged.core.world.river.RiverManager;
import com.terraforged.core.world.terrain.Terrain;
import com.terraforged.core.world.terrain.TerrainPopulator;
@ -36,9 +36,11 @@ public class WorldHeightmap implements Heightmap {
private final Terrains terrain;
private final Settings settings;
private final Populator continentModule;
private final Populator regionModule;
private final Climate climate;
private final Populator root;
private final Populator continent;
private final RiverManager riverManager;
private final TerrainProvider terrainProvider;
@ -48,7 +50,7 @@ public class WorldHeightmap implements Heightmap {
this.levels = context.levels;
this.terrain = context.terrain;
this.settings = context.settings;
this.climate = new Climate(context, this);
this.climate = new Climate(context);
Seed seed = context.seed;
Levels levels = context.levels;
@ -62,11 +64,13 @@ public class WorldHeightmap implements Heightmap {
RegionConfig regionConfig = new RegionConfig(
regionSeed.get(),
context.settings.generator.land.regionSize,
Source.simplex(regionWarp.next(), regionWarpScale, 2),
Source.simplex(regionWarp.next(), regionWarpScale, 2),
Source.simplex(regionWarp.next(), regionWarpScale, 1),
Source.simplex(regionWarp.next(), regionWarpScale, 1),
regionWarpStrength
);
regionModule = new RegionModule(regionConfig);
// controls where mountain chains form in the world
Module mountainShapeBase = Source.cellEdge(seed.next(), genSettings.land.mountainScale, EdgeFunc.DISTANCE_2_ADD)
.add(Source.cubic(seed.next(), genSettings.land.mountainScale, 1).scale(-0.05));
@ -77,36 +81,21 @@ public class WorldHeightmap implements Heightmap {
.clamp(0, 0.9)
.map(0, 1);
// controls the shape of terrain regions
Module regionShape = Source.cell(regionConfig.seed, regionConfig.scale)
.warp(regionConfig.warpX, regionConfig.warpZ, regionConfig.warpStrength);
// the corresponding edges of terrain regions so we can fade out towards borders
Module regionEdge = Source.cellEdge(regionConfig.seed, regionConfig.scale, EdgeFunc.DISTANCE_2_DIV).invert()
.warp(regionConfig.warpX, regionConfig.warpZ, regionConfig.warpStrength)
.pow(1.5)
.clamp(0, 0.75)
.map(0, 1);
this.terrainProvider = context.terrainFactory.create(context, regionConfig, this);
terrainProvider = context.terrainFactory.create(context, regionConfig, this);
// the voronoi controlled terrain regions
Populator terrainRegions = new Selector(regionShape, terrainProvider.getPopulators());
Populator terrainRegions = new RegionSelector(terrainProvider.getPopulators());
// the terrain type at region edges
Populator terrainRegionBorders = new TerrainPopulator(terrainProvider.getLandforms().plains(seed), context.terrain.steppe);
// transitions between the unique terrain regions and the common border terrain
Populator terrain = new Lerp(
regionEdge,
terrainRegionBorders,
terrainRegions
);
Populator terrain = new RegionLerper(terrainRegionBorders, terrainRegions);
// mountain populator
Populator mountains = register(terrainProvider.getLandforms().mountains(seed), context.terrain.mountains);
// controls what's ocean and what's land
this.continent = createContinent(context);
continentModule = new ContinentModule(seed, settings.generator);
// blends between normal terrain and mountain chains
Populator land = new Blender(
@ -119,9 +108,8 @@ public class WorldHeightmap implements Heightmap {
);
// uses the continent noise to blend between deep ocean, to ocean, to coast
MultiBlender oceans = new ContinentMultiBlender(
ContinentLerper3 oceans = new ContinentLerper3(
climate,
continent,
register(terrainProvider.getLandforms().deepOcean(seed.next()), context.terrain.deepOcean),
register(Source.constant(levels.water(-7)), context.terrain.ocean),
register(Source.constant(levels.water), context.terrain.coast),
@ -131,22 +119,23 @@ public class WorldHeightmap implements Heightmap {
);
// blends between the ocean/coast terrain and land terrains
root = new ContinentBlender(
continent,
root = new ContinentLerper2(
oceans,
land,
OCEAN_VALUE, // below == pure ocean
INLAND_VALUE, // above == pure land
COAST_VALUE, // split point
COAST_VALUE - 0.05F
).mask();
);
this.riverManager = new RiverManager(this, context);
riverManager = new RiverManager(this, context);
}
@Override
public void visit(Cell<Terrain> cell, float x, float z) {
continent.apply(cell, x, z);
continentModule.apply(cell, x, z);
regionModule.apply(cell, x, z);
root.apply(cell, x, z);
}
@ -155,8 +144,9 @@ public class WorldHeightmap implements Heightmap {
// initial type
cell.tag = terrain.steppe;
// apply continent value/edge noise
continent.apply(cell, x, z);
// basic shapes
continentModule.apply(cell, x, z);
regionModule.apply(cell, x, z);
// apply actuall heightmap
root.apply(cell, x, z);
@ -184,7 +174,8 @@ public class WorldHeightmap implements Heightmap {
@Override
public void tag(Cell<Terrain> cell, float x, float z) {
continent.apply(cell, x, z);
continentModule.apply(cell, x, z);
regionModule.apply(cell, x, z);
root.tag(cell, x, z);
}
@ -201,8 +192,4 @@ public class WorldHeightmap implements Heightmap {
terrainProvider.registerMixable(populator);
return populator;
}
private Populator createContinent(GeneratorContext context) {
return new VoronoiContinentModule(context.seed, context.settings.generator);
}
}

View File

@ -1,9 +1,9 @@
package com.terraforged.core.world.river;
import com.terraforged.core.world.heightmap.Heightmap;
import me.dags.noise.domain.Domain;
import me.dags.noise.util.Vec2i;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.world.heightmap.WorldHeightmap;
import com.terraforged.core.world.terrain.Terrain;
import java.util.Random;
@ -21,13 +21,13 @@ public class PosGenerator {
private final int padding;
private final Domain domain;
private final Cell<Terrain> lookup;
private final WorldHeightmap heightmap;
private final Heightmap heightmap;
private int i;
private int dx;
private int dz;
public PosGenerator(WorldHeightmap heightmap, Domain domain, Cell<Terrain> lookup, int size, int padding) {
public PosGenerator(Heightmap heightmap, Domain domain, Cell<Terrain> lookup, int size, int padding) {
this.domain = domain;
this.lookup = lookup;
this.padding = padding;

View File

@ -1,10 +1,10 @@
package com.terraforged.core.world.river;
import com.terraforged.core.world.heightmap.Heightmap;
import me.dags.noise.util.NoiseUtil;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.util.Cache;
import com.terraforged.core.world.GeneratorContext;
import com.terraforged.core.world.heightmap.WorldHeightmap;
import com.terraforged.core.world.terrain.Terrain;
import java.util.concurrent.ConcurrentHashMap;
@ -18,11 +18,11 @@ public class RiverManager {
private final RiverConfig primary;
private final RiverConfig secondary;
private final RiverConfig tertiary;
private final WorldHeightmap heightmap;
private final Heightmap heightmap;
private final GeneratorContext context;
private final Cache<Long, RiverRegion> cache = new Cache<>(60, 60, TimeUnit.SECONDS, () -> new ConcurrentHashMap<>());
public RiverManager(WorldHeightmap heightmap, GeneratorContext context) {
public RiverManager(Heightmap heightmap, GeneratorContext context) {
this.heightmap = heightmap;
this.context = context;
this.primary = RiverConfig.builder(context.levels)

View File

@ -1,5 +1,6 @@
package com.terraforged.core.world.river;
import com.terraforged.core.world.heightmap.Heightmap;
import me.dags.noise.domain.Domain;
import me.dags.noise.util.NoiseUtil;
import me.dags.noise.util.Vec2f;
@ -7,7 +8,6 @@ import me.dags.noise.util.Vec2i;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.util.concurrent.ObjectPool;
import com.terraforged.core.world.GeneratorContext;
import com.terraforged.core.world.heightmap.WorldHeightmap;
import com.terraforged.core.world.terrain.Terrain;
import com.terraforged.core.world.terrain.Terrains;
@ -35,7 +35,7 @@ public class RiverRegion {
private final List<River> rivers;
private final List<Lake> lakes = new LinkedList<>();
public RiverRegion(int regionX, int regionZ, WorldHeightmap heightmap, GeneratorContext context, RiverConfig primary, RiverConfig secondary, RiverConfig tertiary, LakeConfig lake) {
public RiverRegion(int regionX, int regionZ, Heightmap heightmap, GeneratorContext context, RiverConfig primary, RiverConfig secondary, RiverConfig tertiary, LakeConfig lake) {
int seed = new Random(NoiseUtil.seed(regionX, regionZ)).nextInt();
this.lake = lake;
this.primary = primary;

View File

@ -36,7 +36,7 @@ public class VolcanoPopulator extends TerrainPopulator {
this.cone = Source.cellEdge(region.seed, region.scale, EdgeFunc.DISTANCE_2_DIV).invert()
.warp(region.warpX, region.warpZ, region.warpStrength)
.powCurve(14)
.powCurve(10)
.clamp(0.475, 1)
.map(0, 1)
.grad(0, 0.5, 0.5)
@ -47,7 +47,7 @@ public class VolcanoPopulator extends TerrainPopulator {
.warp(seed.next(), 30, 1, 30)
.scale(0.1);
this.inversionPoint = 0.95F;
this.inversionPoint = 0.93F;
this.blendLower = midpoint - (range / 2F);
this.blendUpper = blendLower + range;
this.blendRange = blendUpper - blendLower;

View File

@ -1,28 +1,23 @@
package com.terraforged.core.module;
package com.terraforged.core.world.terrain.region;
import me.dags.noise.Module;
import me.dags.noise.util.NoiseUtil;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.cell.Populator;
import com.terraforged.core.world.terrain.Terrain;
import me.dags.noise.util.NoiseUtil;
public class Lerp implements Populator {
public class RegionLerper implements Populator {
private final Module control;
private final Populator lower;
private final Populator upper;
public Lerp(Module control, Populator lower, Populator upper) {
this.control = control;
public RegionLerper(Populator lower, Populator upper) {
this.lower = lower;
this.upper = upper;
}
@Override
public void apply(Cell<Terrain> cell, float x, float y) {
float alpha = control.getValue(x, y);
cell.regionMask = alpha;
float alpha = cell.regionEdge;
if (alpha == 0) {
lower.apply(cell, x, y);
return;
@ -44,8 +39,7 @@ public class Lerp implements Populator {
@Override
public void tag(Cell<Terrain> cell, float x, float y) {
float alpha = control.getValue(x, y);
if (alpha == 0) {
if (cell.regionEdge == 0) {
lower.tag(cell, x, y);
return;
}

View File

@ -1,23 +1,17 @@
package com.terraforged.core.world.continent;
package com.terraforged.core.world.terrain.region;
import me.dags.noise.Module;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.cell.Populator;
import com.terraforged.core.world.heightmap.RegionConfig;
import com.terraforged.core.world.terrain.Terrain;
import me.dags.noise.Source;
import me.dags.noise.domain.Domain;
import me.dags.noise.func.DistanceFunc;
import me.dags.noise.func.EdgeFunc;
import me.dags.noise.util.NoiseUtil;
import me.dags.noise.util.Vec2f;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.cell.Populator;
import com.terraforged.core.settings.GeneratorSettings;
import com.terraforged.core.util.Seed;
import com.terraforged.core.world.terrain.Terrain;
public class VoronoiContinentModule implements Populator {
private static final float edgeClampMin = 0.05F;
private static final float edgeClampMax = 0.50F;
private static final float edgeClampRange = edgeClampMax - edgeClampMin;
public class RegionModule implements Populator {
private final int seed;
private final float frequency;
@ -25,44 +19,19 @@ public class VoronoiContinentModule implements Populator {
private final float edgeMin;
private final float edgeMax;
private final float edgeRange;
private final Domain warp;
private final Module shape;
public VoronoiContinentModule(Seed seed, GeneratorSettings settings) {
int tectonicScale = settings.land.continentScale * 4;
int continentScale = settings.land.continentScale / 2;
double oceans = Math.min(Math.max(settings.world.oceanSize, 0.01), 0.99);
double shapeMin = 0.15 + (oceans * 0.35);
this.seed = seed.next();
this.frequency = 1F / tectonicScale;
this.edgeMin = edgeClampMin;
this.edgeMax = (float) oceans;
this.edgeRange = edgeMax - edgeMin;
this.warp = Domain.warp(Source.SIMPLEX, seed.next(), continentScale, 3, continentScale);
this.shape = Source.perlin(seed.next(), settings.land.continentScale, 2)
.clamp(shapeMin, 0.7)
.map(0, 1)
.warp(Source.SIMPLEX, seed.next(), continentScale / 2, 1, continentScale / 4D)
.warp(seed.next(), 50, 1, 20D);
public RegionModule(RegionConfig regionConfig) {
seed = regionConfig.seed;
edgeMin = 0F;
edgeMax = 0.5F;
edgeRange = edgeMax - edgeMin;
frequency = 1F / regionConfig.scale;
warp = Domain.warp(regionConfig.warpX, regionConfig.warpZ, Source.constant(regionConfig.warpStrength));
}
@Override
public float getValue(float x, float y) {
if (true) {
throw new RuntimeException("no pls!");
} else {
Cell<Terrain> cell = new Cell<>();
apply(cell, x, y);
return cell.continentEdge;
}
}
@Override
public void apply(Cell<Terrain> cell, final float x, final float y) {
public void apply(Cell<Terrain> cell, float x, float y) {
float ox = warp.getOffsetX(x, y);
float oz = warp.getOffsetY(x, y);
@ -108,12 +77,8 @@ public class VoronoiContinentModule implements Populator {
}
}
float shapeNoise = shape.getValue(x, y);
float continentNoise = edgeValue(edgeDistance, edgeDistance2);
cell.continent = cellValue(seed, cellX, cellY);
cell.continentEdge = shapeNoise * continentNoise;
cell.region = cellValue(seed, cellX, cellY);
cell.regionEdge = edgeValue(edgeDistance, edgeDistance2);
}
@Override
@ -130,12 +95,16 @@ public class VoronoiContinentModule implements Populator {
EdgeFunc edge = EdgeFunc.DISTANCE_2_DIV;
float value = edge.apply(distance, distance2);
float edgeValue = 1 - NoiseUtil.map(value, edge.min(), edge.max(), edge.range());
edgeValue = NoiseUtil.pow(edgeValue, 1.5F);
if (edgeValue < edgeMin) {
return 0F;
}
if (edgeValue > edgeMax) {
return 1F;
}
return (edgeValue - edgeMin) / edgeRange;
}
}

View File

@ -1,40 +1,36 @@
package com.terraforged.core.module;
package com.terraforged.core.world.terrain.region;
import me.dags.noise.Module;
import me.dags.noise.util.NoiseUtil;
import com.terraforged.core.cell.Cell;
import com.terraforged.core.cell.Populator;
import com.terraforged.core.world.terrain.Terrain;
import com.terraforged.core.world.terrain.TerrainPopulator;
import me.dags.noise.util.NoiseUtil;
import java.util.LinkedList;
import java.util.List;
public class Selector implements Populator {
public class RegionSelector implements Populator {
private final int maxIndex;
private final Module control;
private final Populator[] nodes;
public Selector(Module control, List<Populator> populators) {
this.control = control;
public RegionSelector(List<Populator> populators) {
this.nodes = getWeightedArray(populators);
this.maxIndex = nodes.length - 1;
}
@Override
public void apply(Cell<Terrain> cell, float x, float y) {
get(x, y).apply(cell, x, y);
get(cell.region).apply(cell, x, y);
}
@Override
public void tag(Cell<Terrain> cell, float x, float y) {
get(x, y).tag(cell, x, y);
get(cell.region).tag(cell, x, y);
}
public Populator get(float x, float y) {
float selector = control.getValue(x, y);
int index = NoiseUtil.round(selector * maxIndex);
public Populator get(float identity) {
int index = NoiseUtil.round(identity * maxIndex);
return nodes[index];
}

@ -1 +1 @@
Subproject commit 5f7d2c8ec864f6dcd1c977013c3c8377d33c4547
Subproject commit 5d1604ab29ae129f133c34fdd72bc207f21364aa