Implement Valleys mapgen heightmap
An unoptimized duplicate of the valleys code from Minetest. Does not implement the temperature and humidity adjustments.master
parent
84066f26ca
commit
a74766a36e
|
@ -94,8 +94,7 @@ public class DefaultVersionFeatures implements VersionFeaturesFactory {
|
|||
.init(commonLayers)
|
||||
.initExtend(
|
||||
LayerIds.MINETEST_OCEAN,
|
||||
LayerIds.MINETEST_OCEAN,
|
||||
LayerIds.MINETEST_MOUNTAIN
|
||||
LayerIds.MINETEST_RIVER
|
||||
).construct()
|
||||
);
|
||||
enabledLayers.put(WorldType.V7,
|
||||
|
@ -169,6 +168,10 @@ public class DefaultVersionFeatures implements VersionFeaturesFactory {
|
|||
WorldType.CARPATHIAN,
|
||||
(seed, mapgenParams, biomeProfile) -> new amidst.minetest.world.oracle.BiomeDataOracleCarpathian(mapgenParams, biomeProfile, seed)
|
||||
),
|
||||
new AbstractMap.SimpleEntry<WorldType, TriFunction<Long, MapgenParams, BiomeProfileSelection, IBiomeDataOracle>>(
|
||||
WorldType.VALLEYS,
|
||||
(seed, mapgenParams, biomeProfile) -> new amidst.minetest.world.oracle.BiomeDataOracleValleys(mapgenParams, biomeProfile, seed)
|
||||
),
|
||||
new AbstractMap.SimpleEntry<WorldType, TriFunction<Long, MapgenParams, BiomeProfileSelection, IBiomeDataOracle>>(
|
||||
WorldType.FLAT,
|
||||
(seed, mapgenParams, biomeProfile) -> new amidst.minetest.world.oracle.BiomeDataOracleFlat(mapgenParams, biomeProfile, seed)
|
||||
|
|
|
@ -8,8 +8,10 @@ import amidst.mojangapi.world.biome.BiomeColor;
|
|||
// TODO: be able to import these values from map_meta.txt files
|
||||
public class MapgenValleysParams extends MapgenParams {
|
||||
|
||||
public static final int FLAG_VALLEYS_ALT_CHILL = 0x01;
|
||||
public static final int FLAG_VALLEYS_HUMID_RIVERS = 0x02;
|
||||
public static final int FLAG_VALLEYS_ALT_CHILL = 0x01;
|
||||
public static final int FLAG_VALLEYS_HUMID_RIVERS = 0x02;
|
||||
public static final int FLAG_VALLEYS_VARY_RIVER_DEPTH = 0x04;
|
||||
public static final int FLAG_VALLEYS_ALT_DRY = 0x08;
|
||||
|
||||
public int spflags = FLAG_VALLEYS_ALT_CHILL | FLAG_VALLEYS_HUMID_RIVERS;
|
||||
|
||||
|
|
|
@ -31,7 +31,30 @@ public class BiomeDataOracleValleys extends MinetestBiomeDataOracle {
|
|||
|
||||
boolean humid_rivers;
|
||||
boolean use_altitude_chill;
|
||||
boolean use_altitude_dry;
|
||||
boolean vary_driver_depth;
|
||||
|
||||
float altitude_chill;
|
||||
float humidity_adjust;
|
||||
float river_depth_bed;
|
||||
float river_size_factor;
|
||||
|
||||
/**
|
||||
* Reusable instance of TerrainNoise, to save unnecessary construction/mem-fragmentation
|
||||
*/
|
||||
TerrainNoise tempTerrainNoise = new TerrainNoise();
|
||||
|
||||
class TerrainNoise {
|
||||
int x;
|
||||
int z;
|
||||
float terrain_height;
|
||||
float rivers;
|
||||
float valley;
|
||||
float valley_profile;
|
||||
float slope;
|
||||
float inter_valley_fill;
|
||||
boolean isRiver;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
@ -52,6 +75,7 @@ public class BiomeDataOracleValleys extends MinetestBiomeDataOracle {
|
|||
}
|
||||
|
||||
grad_wl = 1 - params.water_level;
|
||||
river_size_factor = valleysParams.river_size / 100.0f;
|
||||
|
||||
try {
|
||||
// 2D noise
|
||||
|
@ -77,27 +101,99 @@ public class BiomeDataOracleValleys extends MinetestBiomeDataOracle {
|
|||
|
||||
humid_rivers = (valleysParams.spflags & MapgenValleysParams.FLAG_VALLEYS_HUMID_RIVERS) > 0;
|
||||
use_altitude_chill = (valleysParams.spflags & MapgenValleysParams.FLAG_VALLEYS_ALT_CHILL) > 0;
|
||||
use_altitude_dry = (valleysParams.spflags & MapgenValleysParams.FLAG_VALLEYS_ALT_DRY) > 0;
|
||||
vary_driver_depth = (valleysParams.spflags & MapgenValleysParams.FLAG_VALLEYS_VARY_RIVER_DEPTH) > 0;
|
||||
}
|
||||
|
||||
float terrainLevelAtPoint(int x, int z)
|
||||
{
|
||||
TerrainNoise tn;
|
||||
tempTerrainNoise.x = x;
|
||||
tempTerrainNoise.z = z;
|
||||
tempTerrainNoise.terrain_height = Noise.NoisePerlin2D(noise_terrain_height.np, x, z, seed);
|
||||
tempTerrainNoise.rivers = Noise.NoisePerlin2D(noise_rivers.np, x, z, seed);
|
||||
tempTerrainNoise.valley = Noise.NoisePerlin2D(noise_valley_depth.np, x, z, seed);
|
||||
tempTerrainNoise.valley_profile = Noise.NoisePerlin2D(noise_valley_profile.np, x, z, seed);
|
||||
tempTerrainNoise.slope = Noise.NoisePerlin2D(noise_inter_valley_slope.np, x, z, seed);
|
||||
tempTerrainNoise.inter_valley_fill = 0.f;
|
||||
|
||||
float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed);
|
||||
float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed);
|
||||
float inter_valley_slope = NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed);
|
||||
return adjustedTerrainLevelFromNoise(tempTerrainNoise);
|
||||
}
|
||||
|
||||
// This avoids duplicating the code in terrainLevelFromNoise, adding
|
||||
// only the final step of terrain generation without a noise map.
|
||||
float adjustedTerrainLevelFromNoise(TerrainNoise tn)
|
||||
{
|
||||
float mount = terrainLevelFromNoise(tn);
|
||||
int y_start = (int)(mount < 0.f ? (mount - 0.5f) : (mount + 0.5f)); // was "myround(muount);", s32 myround(f32 f) { return (s32)(f < 0.f ? (f - 0.5f) : (f + 0.5f)); }
|
||||
|
||||
tn.x = x;
|
||||
tn.z = z;
|
||||
tn.terrain_height = NoisePerlin2D(&noise_terrain_height->np, x, z, seed);
|
||||
tn.rivers = &rivers;
|
||||
tn.valley = &valley;
|
||||
tn.valley_profile = NoisePerlin2D(&noise_valley_profile->np, x, z, seed);
|
||||
tn.slope = &inter_valley_slope;
|
||||
tn.inter_valley_fill = 0.f;
|
||||
for (int y = y_start; y <= y_start + 1000; y++) {
|
||||
float fill = Noise.NoisePerlin3D(noise_inter_valley_fill.np, tn.x, y, tn.z, seed);
|
||||
|
||||
return adjustedTerrainLevelFromNoise(&tn); }
|
||||
if (fill * tn.slope < y - mount) {
|
||||
mount = Math.max(y - 1, mount); // was using MYMAX(),, #define MYMAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mount;
|
||||
}
|
||||
|
||||
// This is in a separate function to save the code inside minetest from having
|
||||
// to maintain two similar sets of complicated code to determine ground level.
|
||||
float terrainLevelFromNoise(TerrainNoise tn)
|
||||
{
|
||||
// The square function changes the behaviour of this noise:
|
||||
// very often small, and sometimes very high.
|
||||
float valley_d = tn.valley * tn.valley; // was using MYSQUARE(), #define MYSQUARE(x) (x) * (x)
|
||||
|
||||
// valley_d is here because terrain is generally higher where valleys
|
||||
// are deep (mountains). base represents the height of the
|
||||
// rivers, most of the surface is above.
|
||||
float base = tn.terrain_height + valley_d;
|
||||
|
||||
// "river" represents the distance from the river
|
||||
float river = Math.abs(tn.rivers) - river_size_factor;
|
||||
|
||||
// Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
|
||||
// "valley" represents the height of the terrain, from the rivers.
|
||||
float tv = Math.max(river / tn.valley_profile, 0.0f);
|
||||
tn.valley = valley_d * (1.0f - (float)Math.exp(-(tv * tv)));
|
||||
|
||||
// Approximate height of the terrain at this point
|
||||
float mount = base + tn.valley;
|
||||
|
||||
tn.slope *= tn.valley;
|
||||
|
||||
// Base ground is returned as rivers since it's basically the water table.
|
||||
tn.rivers = base;
|
||||
|
||||
// Rivers are placed where "river" is negative, so where the original noise
|
||||
// value is close to zero.
|
||||
if (river < 0.0f) {
|
||||
tn.isRiver = true;
|
||||
|
||||
// Use the the function -sqrt(1-x^2) which models a circle
|
||||
float tr = river / river_size_factor + 1.0f;
|
||||
float depth = (float) (river_depth_bed *
|
||||
Math.sqrt(Math.max(0.0f, 1.0f - (tr * tr))));
|
||||
|
||||
// base - depth : height of the bottom of the river
|
||||
// water_level - 3 : don't make rivers below 3 nodes under the surface.
|
||||
// We use three because that's as low as the swamp biomes go.
|
||||
// There is no logical equivalent to this using rangelim.
|
||||
mount =
|
||||
Math.min(Math.max(base - depth, (float)(params.water_level - 3)), mount);
|
||||
|
||||
// Slope has no influence on rivers
|
||||
tn.slope = 0.0f;
|
||||
} else {
|
||||
tn.isRiver = false;
|
||||
}
|
||||
|
||||
return mount;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public short populateArray(CoordinatesInWorld corner, short[][] result, boolean useQuarterResolution) {
|
||||
|
||||
|
@ -134,7 +230,8 @@ public class BiomeDataOracleValleys extends MinetestBiomeDataOracle {
|
|||
// Add the ocean bitplane
|
||||
int surface_y = (int)terrainLevelAtPoint(world_x, world_z);
|
||||
if (surface_y < valleysParams.water_level) biomeValue |= BITPLANE_OCEAN;
|
||||
if (isMountains) biomeValue |= BITPLANE_MOUNTAIN;
|
||||
if (tempTerrainNoise.isRiver) biomeValue |= BITPLANE_RIVER;
|
||||
//if (isMountains) biomeValue |= BITPLANE_MOUNTAIN;
|
||||
|
||||
// add the biome index
|
||||
// (mask the bitplanes in case the biome returned is -1 (NONE)
|
||||
|
|
Loading…
Reference in New Issue