This commit is contained in:
Aria 2025-03-21 22:23:30 +11:00
commit 9c94d113d3
Signed by untrusted user who does not match committer: aria
GPG key ID: 19AB7AA462B8AB3B
10260 changed files with 1237388 additions and 0 deletions

View file

@ -0,0 +1,26 @@
#include "StarCacheSelector.hpp"
namespace Star {
char const* const CacheSelector::Name = "cache";
CacheSelector::CacheSelector(
Json const& config, TerrainSelectorParameters const& parameters, TerrainDatabase const* database)
: TerrainSelector(Name, config, parameters) {
auto sourceConfig = config.get("source");
String sourceType = sourceConfig.getString("type");
uint64_t seedBias = sourceConfig.getUInt("seedBias", 0);
TerrainSelectorParameters sourceParameters = parameters;
sourceParameters.seed += seedBias;
m_source = database->createSelectorType(type, sourceConfig, sourceParameters);
m_cache.setMaxSize(config.getUInt("lruCacheSize", 20000));
}
float CacheSelector::get(int x, int y) const {
return m_cache.get(Vec2I(x, y), [this](Vec2I const& key) {
return m_source->get(key[0], key[1]);
});
}
}

View file

@ -0,0 +1,23 @@
#ifndef STAR_CACHE_SELECTOR_HPP
#define STAR_CACHE_SELECTOR_HPP
#include "StarTerrainDatabase.hpp"
#include "StarLruCache.hpp"
#include "StarVector.hpp"
namespace Star {
struct CacheSelector : TerrainSelector {
static char const* const Name;
CacheSelector(Json const& config, TerrainSelectorParameters const& parameters, TerrainDatabase const* database);
float get(int x, int y) const override;
TerrainSelectorConstPtr m_source;
mutable HashLruCache<Vec2I, float> m_cache;
};
}
#endif

View file

@ -0,0 +1,16 @@
#include "StarConstantSelector.hpp"
namespace Star {
char const* const ConstantSelector::Name = "constant";
ConstantSelector::ConstantSelector(Json const& config, TerrainSelectorParameters const& parameters)
: TerrainSelector(Name, config, parameters) {
m_value = config.getFloat("value");
}
float ConstantSelector::get(int, int) const {
return m_value;
}
}

View file

@ -0,0 +1,20 @@
#ifndef STAR_SOLID_SELECTOR_HPP
#define STAR_SOLID_SELECTOR_HPP
#include "StarTerrainDatabase.hpp"
namespace Star {
struct ConstantSelector : TerrainSelector {
static char const* const Name;
ConstantSelector(Json const& config, TerrainSelectorParameters const& parameters);
float get(int x, int y) const override;
float m_value;
};
}
#endif

View file

@ -0,0 +1,69 @@
#include "StarDisplacementSelector.hpp"
#include "StarRandom.hpp"
#include "StarJsonExtra.hpp"
namespace Star {
char const* const DisplacementSelector::Name = "displacement";
DisplacementSelector::DisplacementSelector(
Json const& config, TerrainSelectorParameters const& parameters, TerrainDatabase const* database)
: TerrainSelector(Name, config, parameters) {
RandomSource random(parameters.seed);
auto xType = PerlinTypeNames.getLeft(config.getString("xType"));
auto xOctaves = config.getFloat("xOctaves");
auto xFreq = config.getFloat("xFreq");
auto xAmp = config.getFloat("xAmp");
auto xBias = config.getFloat("xBias", 0.0f);
auto xAlpha = config.getFloat("xAlpha", 2.0f);
auto xBeta = config.getFloat("xBeta", 2.0f);
xDisplacementFunction = PerlinF(xType, xOctaves, xFreq, xAmp, xBias, xAlpha, xBeta, random.randu64());
auto yType = PerlinTypeNames.getLeft(config.getString("yType"));
auto yOctaves = config.getFloat("yOctaves");
auto yFreq = config.getFloat("yFreq");
auto yAmp = config.getFloat("yAmp");
auto yBias = config.getFloat("yBias", 0.0f);
auto yAlpha = config.getFloat("yAlpha", 2.0f);
auto yBeta = config.getFloat("yBeta", 2.0f);
yDisplacementFunction = PerlinF(yType, yOctaves, yFreq, yAmp, yBias, yAlpha, yBeta, random.randu64());
xXInfluence = config.getFloat("xXInfluence", 1.0f);
xYInfluence = config.getFloat("xYInfluence", 1.0f);
yXInfluence = config.getFloat("yXInfluence", 1.0f);
yYInfluence = config.getFloat("yYInfluence", 1.0f);
yClamp = config.contains("yClamp");
if (yClamp) {
yClampRange = jsonToVec2F(config.get("yClamp"));
yClampSmoothing = config.getFloat("yClampSmoothing", 0);
}
auto sourceConfig = config.get("source");
String sourceType = sourceConfig.getString("type");
m_source = database->createSelectorType(sourceType, sourceConfig, parameters);
}
float DisplacementSelector::get(int x, int y) const {
auto x_ = x + xDisplacementFunction.get(x * xXInfluence, y * xYInfluence);
auto y_ = y + clampY(yDisplacementFunction.get(x * yXInfluence, y * yYInfluence));
return m_source->get(x_, y_);
}
float DisplacementSelector::clampY(float v) const {
if (!yClamp)
return v;
if (yClampSmoothing == 0)
return clamp(v, yClampRange[0], yClampRange[1]);
return 0.2f * (clamp(v - yClampSmoothing, yClampRange[0], yClampRange[1])
+ clamp(v - 0.5f * yClampSmoothing, yClampRange[0], yClampRange[1])
+ clamp(v, yClampRange[0], yClampRange[1])
+ clamp(v + 0.5f * yClampSmoothing, yClampRange[0], yClampRange[1])
+ clamp(v + yClampSmoothing, yClampRange[0], yClampRange[1]));
}
}

View file

@ -0,0 +1,37 @@
#ifndef STAR_DISPLACEMENT_SELECTOR_HPP
#define STAR_DISPLACEMENT_SELECTOR_HPP
#include "StarTerrainDatabase.hpp"
#include "StarPerlin.hpp"
#include "StarVector.hpp"
namespace Star {
struct DisplacementSelector : TerrainSelector {
static char const* const Name;
DisplacementSelector(
Json const& config, TerrainSelectorParameters const& parameters, TerrainDatabase const* database);
float get(int x, int y) const override;
PerlinF xDisplacementFunction;
PerlinF yDisplacementFunction;
float xXInfluence;
float xYInfluence;
float yXInfluence;
float yYInfluence;
bool yClamp;
Vec2F yClampRange;
float yClampSmoothing;
float clampY(float v) const;
TerrainSelectorConstPtr m_source;
};
}
#endif

View file

@ -0,0 +1,18 @@
#include "StarFlatSurfaceSelector.hpp"
namespace Star {
char const* const FlatSurfaceSelector::Name = "flatSurface";
FlatSurfaceSelector::FlatSurfaceSelector(Json const& config, TerrainSelectorParameters const& parameters)
: TerrainSelector(Name, config, parameters) {
surfaceLevel = parameters.baseHeight;
adjustment = config.getFloat("adjustment", 0);
flip = config.getBool("flip", false) ? -1 : 1;
}
float FlatSurfaceSelector::get(int, int y) const {
return flip * (surfaceLevel - (y - adjustment));
}
}

View file

@ -0,0 +1,22 @@
#ifndef STAR_FLAT_SURFACE_SELECTOR_HPP
#define STAR_FLAT_SURFACE_SELECTOR_HPP
#include "StarTerrainDatabase.hpp"
namespace Star {
struct FlatSurfaceSelector : TerrainSelector {
static char const* const Name;
FlatSurfaceSelector(Json const& config, TerrainSelectorParameters const& parameters);
float get(int x, int y) const override;
float surfaceLevel;
float adjustment;
float flip;
};
}
#endif

View file

@ -0,0 +1,50 @@
#include "StarIslandSurfaceSelector.hpp"
#include "StarGameTypes.hpp"
#include "StarRandom.hpp"
#include "StarJsonExtra.hpp"
namespace Star {
char const* const IslandSurfaceSelector::Name = "islandSurface";
IslandSurfaceSelector::IslandSurfaceSelector(Json const& config, TerrainSelectorParameters const& parameters)
: TerrainSelector(Name, config, parameters) {
layerBaseHeight = parameters.baseHeight;
worldWidth = parameters.worldWidth;
islandElevation = config.getFloat("islandElevation");
islandTaperPoint = config.getFloat("islandTaperPoint");
islandHeight = PerlinF(config.getObject("islandHeight"), staticRandomU64(parameters.seed, parameters.baseHeight, "islandHeight"));
islandDepth = PerlinF(config.getObject("islandDepth"), staticRandomU64(parameters.seed, parameters.baseHeight, "islandDepth"));
islandDecision = PerlinF(config.getObject("islandDecision"), staticRandomU64(parameters.seed, parameters.baseHeight, "islandDecision"));
}
IslandColumn IslandSurfaceSelector::generateColumn(int x) const {
float noiseAngle = 2 * Constants::pi * x / worldWidth;
float noiseX = (std::cos(noiseAngle) * worldWidth) / (2 * Constants::pi);
float noiseY = (std::sin(noiseAngle) * worldWidth) / (2 * Constants::pi);
IslandColumn newCol;
float thisIslandDecision = islandDecision.get(noiseX, noiseY);
if (thisIslandDecision > 0) {
float taperFactor = thisIslandDecision < islandTaperPoint ? std::sin((0.5 * Constants::pi * thisIslandDecision) / islandTaperPoint) : 1.0f;
newCol.topLevel = islandElevation + layerBaseHeight + taperFactor * islandHeight.get(noiseX, noiseY);
newCol.bottomLevel = islandElevation + layerBaseHeight - taperFactor * islandDepth.get(noiseX, noiseY);
} else {
newCol.topLevel = layerBaseHeight;
newCol.bottomLevel = layerBaseHeight;
}
return newCol;
}
float IslandSurfaceSelector::get(int x, int y) const {
auto col = columnCache.get(x, [=](int x) {
return IslandSurfaceSelector::generateColumn(x);
});
return (col.topLevel - col.bottomLevel) / 2 - abs((col.topLevel + col.bottomLevel) / 2 - y);
}
}

View file

@ -0,0 +1,39 @@
#ifndef STAR_ISLAND_SURFACE_SELECTOR_HPP
#define STAR_ISLAND_SURFACE_SELECTOR_HPP
#include "StarLruCache.hpp"
#include "StarPerlin.hpp"
#include "StarTerrainDatabase.hpp"
namespace Star {
struct IslandColumn {
float topLevel;
float bottomLevel;
};
struct IslandSurfaceSelector : TerrainSelector {
static char const* const Name;
IslandSurfaceSelector(Json const& config, TerrainSelectorParameters const& parameters);
float get(int x, int y) const override;
IslandColumn generateColumn(int x) const;
mutable HashLruCache<int, IslandColumn> columnCache;
PerlinF islandHeight;
PerlinF islandDepth;
PerlinF islandDecision;
float islandTaperPoint;
float islandElevation;
float layerBaseHeight;
int worldWidth;
};
}
#endif

View file

@ -0,0 +1,114 @@
#include "StarKarstCave.hpp"
#include "StarJsonExtra.hpp"
#include "StarRandom.hpp"
#include "StarInterpolation.hpp"
#include "StarGameTypes.hpp"
#include "StarLogging.hpp"
namespace Star {
char const* const KarstCaveSelector::Name = "karstcave";
KarstCaveSelector::KarstCaveSelector(Json const& config, TerrainSelectorParameters const& parameters)
: TerrainSelector(Name, config, parameters) {
m_sectorSize = config.getUInt("sectorSize", 64);
m_layerResolution = config.getInt("layerResolution");
m_layerDensity = config.getFloat("layerDensity");
m_bufferHeight = config.getInt("bufferHeight");
m_caveTaperPoint = config.getFloat("caveTaperPoint");
m_caveDecisionPerlinConfig = config.get("caveDecision");
m_layerHeightVariationPerlinConfig = config.get("layerHeightVariation");
m_caveHeightVariationPerlinConfig = config.get("caveHeightVariation");
m_caveFloorVariationPerlinConfig = config.get("caveFloorVariation");
m_worldWidth = parameters.worldWidth;
m_seed = parameters.seed;
m_layerPerlinsCache.setMaxSize(config.getUInt("layerPerlinsCacheSize", 16));
m_sectorCache.setMaxSize(config.getUInt("sectorCacheSize", 16));
}
float KarstCaveSelector::get(int x, int y) const {
Vec2I key = Vec2I(x - pmod(x, m_sectorSize), y - pmod(y, m_sectorSize));
return m_sectorCache.get(key, [=](Vec2I const& key) {
return Sector(this, key);
}).get(x, y);
}
KarstCaveSelector::Sector::Sector(KarstCaveSelector const* parent, Vec2I sector)
: parent(parent), sector(sector), values(square(parent->m_sectorSize)) {
m_maxValue = 0;
for (int y = sector[1] - parent->m_bufferHeight; y < sector[1] + parent->m_sectorSize + parent->m_bufferHeight; y++) {
float layerChance = parent->m_layerDensity * parent->m_layerResolution;
// determine whether this layer has caves
if (y % parent->m_layerResolution == 0 && staticRandomFloat(parent->m_seed, y) <= layerChance) {
LayerPerlins const& layerPerlins = parent->layerPerlins(y);
// carve out cave layer
for (int x = sector[0]; x < sector[0] + parent->m_sectorSize; x++) {
// use wrapping noise
float noiseAngle = 2 * Constants::pi * x / parent->m_worldWidth;
float noiseX = (std::cos(noiseAngle) * parent->m_worldWidth) / (2 * Constants::pi);
float noiseY = (std::sin(noiseAngle) * parent->m_worldWidth) / (2 * Constants::pi);
// determine where caves be at
float isThereACaveHere = layerPerlins.caveDecision.get(noiseX, noiseY);
if (isThereACaveHere > 0) {
float taperFactor = isThereACaveHere < parent->m_caveTaperPoint
? std::sin((0.5 * Constants::pi * isThereACaveHere) / parent->m_caveTaperPoint)
: 1.0f;
int baseY = y + layerPerlins.layerHeightVariation.get(noiseX, noiseY);
int ceilingY = baseY + layerPerlins.caveHeightVariation.get(noiseX, noiseY) * taperFactor;
int floorY = baseY + layerPerlins.caveFloorVariation.get(noiseX, noiseY) * taperFactor;
float halfHeight = abs(ceilingY - floorY + 1) / 2.0f;
float midpointY = (floorY + ceilingY) / 2.0f;
m_maxValue = max(m_maxValue, halfHeight);
for (int pointY = floorY; pointY < ceilingY; pointY++)
if (inside(x, pointY))
set(x, pointY, max(get(x, pointY), halfHeight - abs(midpointY - pointY)));
}
}
}
}
}
float KarstCaveSelector::Sector::get(int x, int y) {
auto val = values[(x - sector[0]) + parent->m_sectorSize * (y - sector[1])];
if (val > 0)
return val;
else
return -m_maxValue;
}
bool KarstCaveSelector::Sector::inside(int x, int y) {
int x_ = x - sector[0];
if (x_ < 0 || x_ >= parent->m_sectorSize)
return false;
int y_ = y - sector[1];
if (y_ < 0 || y_ >= parent->m_sectorSize)
return false;
return true;
}
void KarstCaveSelector::Sector::set(int x, int y, float value) {
values[(x - sector[0]) + parent->m_sectorSize * (y - sector[1])] = value;
}
KarstCaveSelector::LayerPerlins const& KarstCaveSelector::layerPerlins(int y) const {
return m_layerPerlinsCache.get(y, [this](int y) {
return LayerPerlins{
PerlinF(m_caveDecisionPerlinConfig, staticRandomU64(y, m_seed, "CaveDecision")),
PerlinF(m_layerHeightVariationPerlinConfig, staticRandomU64(y, m_seed, "LayerHeightVariation")),
PerlinF(m_caveHeightVariationPerlinConfig, staticRandomU64(y, m_seed, "CaveHeightVariation")),
PerlinF(m_caveFloorVariationPerlinConfig, staticRandomU64(y, m_seed, "CaveFloorVariation"))
};
});
}
}

View file

@ -0,0 +1,64 @@
#ifndef STAR_KARST_CAVE_HPP
#define STAR_KARST_CAVE_HPP
#include "StarTerrainDatabase.hpp"
#include "StarLruCache.hpp"
#include "StarVector.hpp"
#include "StarPerlin.hpp"
namespace Star {
class KarstCaveSelector : public TerrainSelector {
public:
static char const* const Name;
KarstCaveSelector(Json const& config, TerrainSelectorParameters const& parameters);
float get(int x, int y) const override;
private:
struct LayerPerlins {
PerlinF caveDecision;
PerlinF layerHeightVariation;
PerlinF caveHeightVariation;
PerlinF caveFloorVariation;
};
struct Sector {
Sector(KarstCaveSelector const* parent, Vec2I sector);
float get(int x, int y);
bool inside(int x, int y);
void set(int x, int y, float value);
KarstCaveSelector const* parent;
Vec2I sector;
List<float> values;
float m_maxValue;
};
LayerPerlins const& layerPerlins(int y) const;
int m_sectorSize;
int m_layerResolution;
float m_layerDensity;
int m_bufferHeight;
float m_caveTaperPoint;
Json m_caveDecisionPerlinConfig;
Json m_layerHeightVariationPerlinConfig;
Json m_caveHeightVariationPerlinConfig;
Json m_caveFloorVariationPerlinConfig;
int m_worldWidth;
uint64_t m_seed;
mutable HashLruCache<int, LayerPerlins> m_layerPerlinsCache;
mutable HashLruCache<Vec2I, Sector> m_sectorCache;
};
}
#endif

View file

@ -0,0 +1,27 @@
#include "StarMaxSelector.hpp"
#include "StarMathCommon.hpp"
namespace Star {
char const* const MaxSelector::Name = "max";
MaxSelector::MaxSelector(
Json const& config, TerrainSelectorParameters const& parameters, TerrainDatabase const* database)
: TerrainSelector(Name, config, parameters) {
for (auto const& sourceConfig : config.getArray("sources")) {
String sourceType = sourceConfig.getString("type");
uint64_t seedBias = sourceConfig.getUInt("seedBias", 0);
TerrainSelectorParameters sourceParameters = parameters;
sourceParameters.seed += seedBias;
m_sources.append(database->createSelectorType(sourceType, sourceConfig, sourceParameters));
}
}
float MaxSelector::get(int x, int y) const {
float value = lowest<float>();
for (auto const& source : m_sources)
value = max(value, source->get(x, y));
return value;
}
}

View file

@ -0,0 +1,20 @@
#ifndef STAR_MAX_SELECTOR_HPP
#define STAR_MAX_SELECTOR_HPP
#include "StarTerrainDatabase.hpp"
namespace Star {
struct MaxSelector : TerrainSelector {
static char const* const Name;
MaxSelector(Json const& config, TerrainSelectorParameters const& parameters, TerrainDatabase const* database);
float get(int x, int y) const override;
List<TerrainSelectorConstPtr> m_sources;
};
}
#endif

View file

@ -0,0 +1,32 @@
#include "StarMinMaxSelector.hpp"
#include "StarMathCommon.hpp"
namespace Star {
char const* const MinMaxSelector::Name = "minmax";
MinMaxSelector::MinMaxSelector(
Json const& config, TerrainSelectorParameters const& parameters, TerrainDatabase const* database)
: TerrainSelector(Name, config, parameters) {
for (auto const& sourceConfig : config.getArray("sources")) {
String sourceType = sourceConfig.getString("type");
uint64_t seedBias = sourceConfig.getUInt("seedBias", 0);
TerrainSelectorParameters sourceParameters = parameters;
sourceParameters.seed += seedBias;
m_sources.append(database->createSelectorType(sourceType, sourceConfig, sourceParameters));
}
}
float MinMaxSelector::get(int x, int y) const {
float value = 0.0f;
for (auto const& source : m_sources) {
float srcVal = source->get(x, y);
if (value > 0 || srcVal > 0)
value = max(value, srcVal);
else
value = min(value, srcVal);
}
return value;
}
}

View file

@ -0,0 +1,20 @@
#ifndef STAR_MIN_MAX_SELECTOR_HPP
#define STAR_MIN_MAX_SELECTOR_HPP
#include "StarTerrainDatabase.hpp"
namespace Star {
struct MinMaxSelector : TerrainSelector {
static char const* const Name;
MinMaxSelector(Json const& config, TerrainSelectorParameters const& parameters, TerrainDatabase const* database);
float get(int x, int y) const override;
List<TerrainSelectorConstPtr> m_sources;
};
}
#endif

View file

@ -0,0 +1,29 @@
#include "StarMixSelector.hpp"
#include "StarInterpolation.hpp"
namespace Star {
char const* const MixSelector::Name = "mix";
MixSelector::MixSelector(Json const& config, TerrainSelectorParameters const& parameters, TerrainDatabase const* database)
: TerrainSelector(Name, config, parameters) {
auto readSource = [&](Json const& sourceConfig) {
String type = sourceConfig.getString("type");
return database->createSelectorType(type, sourceConfig, parameters);
};
m_mixSource = readSource(config.get("mixSource"));
m_aSource = readSource(config.get("aSource"));
m_bSource = readSource(config.get("bSource"));
}
float MixSelector::get(int x, int y) const {
auto f = clamp(m_mixSource->get(x, y), -1.0f, 1.0f);
if (f == -1)
return m_aSource->get(x, y);
if (f == 1)
return m_bSource->get(x, y);
return lerp(f * 0.5f + 0.5f, m_aSource->get(x, y), m_bSource->get(x, y));
}
}

View file

@ -0,0 +1,22 @@
#ifndef STAR_MIX_SELECTOR_HPP
#define STAR_MIX_SELECTOR_HPP
#include "StarTerrainDatabase.hpp"
namespace Star {
struct MixSelector : TerrainSelector {
static char const* const Name;
MixSelector(Json const& config, TerrainSelectorParameters const& parameters, TerrainDatabase const* database);
float get(int x, int y) const override;
TerrainSelectorConstPtr m_mixSource;
TerrainSelectorConstPtr m_aSource;
TerrainSelectorConstPtr m_bSource;
};
}
#endif

View file

@ -0,0 +1,30 @@
#include "StarPerlinSelector.hpp"
#include "StarRandom.hpp"
namespace Star {
char const* const PerlinSelector::Name = "perlin";
PerlinSelector::PerlinSelector(Json const& config, TerrainSelectorParameters const& parameters)
: TerrainSelector(Name, config, parameters) {
RandomSource random(parameters.seed);
auto type = PerlinTypeNames.getLeft(config.getString("function"));
auto octaves = config.getFloat("octaves");
auto freq = config.getFloat("freq");
auto amp = config.getFloat("amp");
auto bias = config.getFloat("bias", 0.0f);
auto alpha = config.getFloat("alpha", 2.0f);
auto beta = config.getFloat("beta", 2.0f);
function = PerlinF(type, octaves, freq, amp, bias, alpha, beta, random.randu64());
xInfluence = config.getFloat("xInfluence", 1.0f);
yInfluence = config.getFloat("yInfluence", 1.0f);
}
float PerlinSelector::get(int x, int y) const {
return function.get(x * xInfluence, y * yInfluence);
}
}

View file

@ -0,0 +1,24 @@
#ifndef STAR_PERLIN_SELECTOR_HPP
#define STAR_PERLIN_SELECTOR_HPP
#include "StarTerrainDatabase.hpp"
#include "StarPerlin.hpp"
namespace Star {
struct PerlinSelector : TerrainSelector {
static char const* const Name;
PerlinSelector(Json const& config, TerrainSelectorParameters const& parameters);
float get(int x, int y) const override;
PerlinF function;
float xInfluence;
float yInfluence;
};
}
#endif

View file

@ -0,0 +1,35 @@
#include "StarRidgeBlocksSelector.hpp"
#include "StarRandom.hpp"
namespace Star {
char const* const RidgeBlocksSelector::Name = "ridgeblocks";
RidgeBlocksSelector::RidgeBlocksSelector(Json const& config, TerrainSelectorParameters const& parameters)
: TerrainSelector(Name, config, parameters) {
commonality = parameters.commonality;
amplitude = config.getFloat("amplitude");
frequency = config.getFloat("frequency");
bias = config.getFloat("bias");
noiseAmplitude = config.getFloat("noiseAmplitude");
noiseFrequency = config.getFloat("noiseFrequency");
RandomSource random(parameters.seed);
ridgePerlin1 = PerlinF(PerlinType::RidgedMulti, 2, frequency, amplitude, 0, 2.0f, 2.0f, random.randu64());
ridgePerlin2 = PerlinF(PerlinType::RidgedMulti, 2, frequency, amplitude, 0, 2.0f, 2.0f, random.randu64());
noisePerlin = PerlinF(1, noiseFrequency, noiseAmplitude, 0, 1.0f, 2.0f, random.randu64());
}
float RidgeBlocksSelector::get(int x, int y) const {
if (commonality <= 0.0f) {
return 0.0f;
} else {
x += noisePerlin.get(x, y);
y += noisePerlin.get(y, x);
return (ridgePerlin1.get(x, y) - ridgePerlin2.get(x, y)) * commonality + bias;
}
}
}

View file

@ -0,0 +1,32 @@
#ifndef STAR_RIDGE_BLOCKS_SELECTOR_HPP
#define STAR_RIDGE_BLOCKS_SELECTOR_HPP
#include "StarTerrainDatabase.hpp"
#include "StarPerlin.hpp"
namespace Star {
struct RidgeBlocksSelector : TerrainSelector {
static char const* const Name;
RidgeBlocksSelector(Json const& config, TerrainSelectorParameters const& parameters);
float get(int x, int y) const override;
float commonality;
float amplitude;
float frequency;
float bias;
float noiseAmplitude;
float noiseFrequency;
PerlinF ridgePerlin1;
PerlinF ridgePerlin2;
PerlinF noisePerlin;
};
}
#endif

View file

@ -0,0 +1,27 @@
#include "StarRotateSelector.hpp"
#include "StarRandom.hpp"
#include "StarJsonExtra.hpp"
namespace Star {
char const* const RotateSelector::Name = "rotate";
RotateSelector::RotateSelector(
Json const& config, TerrainSelectorParameters const& parameters, TerrainDatabase const* database)
: TerrainSelector(Name, config, parameters) {
RandomSource random(parameters.seed);
rotation = config.getFloat("rotation");
rotationCenter = Vec2F(parameters.worldWidth / 2, 0);
auto sourceConfig = config.get("source");
String sourceType = sourceConfig.getString("type");
m_source = database->createSelectorType(sourceType, sourceConfig, parameters);
}
float RotateSelector::get(int x, int y) const {
auto pos = (Vec2F(x, y) - rotationCenter).rotate(rotation) + rotationCenter;
return m_source->get(pos[0], pos[1]);
}
}

View file

@ -0,0 +1,24 @@
#ifndef STAR_ROTATE_SELECTOR_HPP
#define STAR_ROTATE_SELECTOR_HPP
#include "StarTerrainDatabase.hpp"
#include "StarVector.hpp"
namespace Star {
struct RotateSelector : TerrainSelector {
static char const* const Name;
RotateSelector(Json const& config, TerrainSelectorParameters const& parameters, TerrainDatabase const* database);
float get(int x, int y) const override;
float rotation;
Vec2F rotationCenter;
TerrainSelectorConstPtr m_source;
};
}
#endif

View file

@ -0,0 +1,157 @@
#include "StarWormCave.hpp"
#include "StarJsonExtra.hpp"
#include "StarRandom.hpp"
#include "StarInterpolation.hpp"
namespace Star {
char const* const WormCaveSelector::Name = "wormcave";
WormCaveSector::WormCaveSector(int sectorSize, Vec2I sector, Json const& config, size_t seed, float commonality)
: m_sectorSize(sectorSize), m_sector(sector), m_values(sectorSize * sectorSize) {
struct Worm {
Vec2F pos;
float angle;
float goalAngle;
float size;
float length;
float goalLength;
};
List<Worm> worms;
Vec2F numberOfWormsPerSectorRange = jsonToVec2F(config.get("numberOfWormsPerSectorRange"));
Vec2F wormSizeRange = jsonToVec2F(config.get("wormSizeRange"));
Vec2F wormLengthRange = jsonToVec2F(config.get("wormLengthRange"));
float wormTaperDistance = config.getFloat("wormTaperDistance");
Vec2F wormAngleRange = jsonToVec2F(config.get("wormAngleRange"));
float wormTurnChance = config.getFloat("wormTurnChance");
float wormTurnRate = config.getFloat("wormTurnRate");
float wormSpeed = config.getFloat("wormSpeed", 1);
float twoPi = Constants::pi * 2;
m_maxValue = wormSizeRange[1] / 2;
// determine worms for the neighbouring sectors
int sectorRadius = m_sectorSize * config.getInt("sectorRadius");
for (int x = sector[0] - sectorRadius; x <= sector[0] + sectorRadius; x += m_sectorSize)
for (int y = sector[1] - sectorRadius; y <= sector[1] + sectorRadius; y += m_sectorSize) {
RandomSource rs(staticRandomU64(x, y, seed));
float numberOfWorms = rs.randf(numberOfWormsPerSectorRange[0], numberOfWormsPerSectorRange[1]) * commonality;
int intNumberOfWorms = (int)numberOfWorms;
if (rs.randf() < (numberOfWorms - intNumberOfWorms))
intNumberOfWorms++;
for (int n = 0; n < intNumberOfWorms; ++n) {
Worm worm;
worm.pos = Vec2F(x, y) + Vec2F(rs.randf(0, m_sectorSize), rs.randf(0, m_sectorSize));
worm.angle = rs.randf(wormAngleRange[0], wormAngleRange[1]);
worm.goalAngle = rs.randf(wormAngleRange[0], wormAngleRange[1]);
worm.size = rs.randf(wormSizeRange[0], wormSizeRange[1]) * commonality;
worm.length = 0;
worm.goalLength = rs.randf(wormLengthRange[0], wormLengthRange[1]) * commonality;
worms.append(worm);
}
}
while (true) {
bool idle = true;
for (auto& worm : worms) {
if (worm.length >= worm.goalLength)
continue;
idle = false;
// taper size
float wormRadius = worm.size / 2;
float taperFactor = 1.0f;
if (worm.length < wormTaperDistance)
taperFactor = std::sin(0.5 * Constants::pi * worm.length / wormTaperDistance);
else if (worm.goalLength - worm.length < wormTaperDistance)
taperFactor = std::sin(0.5 * Constants::pi * (worm.goalLength - worm.length) / wormTaperDistance);
wormRadius *= taperFactor;
// carve out worm area
int size = ceil(wormRadius);
for (float dx = -size; dx <= size; dx += 1)
for (float dy = -size; dy <= size; dy += 1) {
float m = sqrt((dx * dx) + (dy * dy));
if (m <= wormRadius) {
int x = floor(dx + worm.pos[0]);
int y = floor(dy + worm.pos[1]);
if (inside(x, y)) {
float v = get(x, y);
set(x, y, max(v, wormRadius - m));
}
}
}
// move the worm, slowing down a bit as we reach the ends to reduce
// stutter
float thisSpeed = max(0.75f, wormSpeed * taperFactor);
worm.pos += Vec2F::withAngle(worm.angle) * thisSpeed;
worm.length += thisSpeed;
// maybe set new goal angle
if (staticRandomFloat(worm.pos[0], worm.pos[1], seed, 1) < wormTurnChance * thisSpeed) {
worm.goalAngle = pfmod(
staticRandomFloatRange(wormAngleRange[0], wormAngleRange[1], worm.pos[0], worm.pos[1], seed, 2), twoPi);
}
if (worm.angle != worm.goalAngle) {
// turn the worm toward goal angle
float angleDiff = worm.goalAngle - worm.angle;
// stop if we're close enough
if (abs(angleDiff) < wormTurnRate * thisSpeed)
worm.angle = worm.goalAngle;
else {
// turn the shortest angular distance
if (abs(angleDiff) > twoPi)
angleDiff = -angleDiff;
worm.angle = pfmod(worm.angle + copysign(wormTurnRate * thisSpeed, angleDiff), twoPi);
}
}
}
if (idle)
break;
}
}
float WormCaveSector::get(int x, int y) {
auto val = m_values[(x - m_sector[0]) + m_sectorSize * (y - m_sector[1])];
if (val > 0)
return val;
else
return -m_maxValue;
}
bool WormCaveSector::inside(int x, int y) {
int x_ = x - m_sector[0];
if (x_ < 0 || x_ >= m_sectorSize)
return false;
int y_ = y - m_sector[1];
if (y_ < 0 || y_ >= m_sectorSize)
return false;
return true;
}
void WormCaveSector::set(int x, int y, float value) {
m_values[(x - m_sector[0]) + m_sectorSize * (y - m_sector[1])] = value;
}
WormCaveSelector::WormCaveSelector(Json const& config, TerrainSelectorParameters const& parameters)
: TerrainSelector(Name, config, parameters) {
m_sectorSize = config.getUInt("sectorSize", 64);
m_cache.setMaxSize(config.getUInt("lruCacheSize", 16));
}
float WormCaveSelector::get(int x, int y) const {
Vec2I sector = Vec2I(x - pmod(x, m_sectorSize), y - pmod(y, m_sectorSize));
return m_cache.get(sector, [=](Vec2I const& sector) {
return WormCaveSector(m_sectorSize, sector, config, parameters.seed, parameters.commonality);
}).get(x, y);
}
}

View file

@ -0,0 +1,42 @@
#ifndef STAR_WORM_CAVE_HPP
#define STAR_WORM_CAVE_HPP
#include "StarTerrainDatabase.hpp"
#include "StarLruCache.hpp"
#include "StarVector.hpp"
namespace Star {
class WormCaveSector {
public:
WormCaveSector(int sectorSize, Vec2I sector, Json const& config, size_t seed, float commonality);
float get(int x, int y);
private:
bool inside(int x, int y);
void set(int x, int y, float value);
int m_sectorSize;
Vec2I m_sector;
List<float> m_values;
float m_maxValue;
};
class WormCaveSelector : public TerrainSelector {
public:
static char const* const Name;
WormCaveSelector(Json const& config, TerrainSelectorParameters const& parameters);
float get(int x, int y) const override;
private:
int m_sectorSize;
mutable HashLruCache<Vec2I, WormCaveSector> m_cache;
};
}
#endif