Diggler/CaveGenerator.cpp
Dorian Wouters f2062d6fe7 Faster atlas creation
Block selection
Chunk de/compression now uses internal buffer directly (0-copy)
Optimized Chunk vertices list order (faster vert access from GPU cache)
F5 Debug info: added triangle count
Implemented ladder climb
Road + jump pad makes you jump farther
Fixed bad fog color blending (alpha-channel)
Changed LZFX and enet compilation to Release, -O3
2016-01-02 20:03:37 +01:00

250 lines
7.3 KiB
C++

#include "CaveGenerator.hpp"
#include <climits>
#include <thread>
#include "Blocks.hpp"
#include "Chunk.hpp"
#include "Platform.hpp"
#include "stb_perlin.h"
namespace Diggler {
CaveGenerator::GenConf::GenConf() :
groundLevel(0.9), oreFactor(0.5) {
seed = FastRand();
cave.enabled = true;
cave.length = 0.0002;
cave.count = 18;
ore.enabled = true;
ore.thresold = 0.3;
lava.enabled = true;
lava.freq = 0.0001;
lava.freqAmpl = 0;
lava.minLevel = 0;
lava.maxLevel = 0.5;
diamond.enabled = true;
diamond.freq = 0.0005;
diamond.freqAmpl = 0;
diamond.minLevel = 0;
diamond.maxLevel = 0.5;
rocks.enabled = true;
rocks.freq = 0.05;
rocks.freqAmpl = 0;
rocks.minLevel = 0;
rocks.maxLevel = 0.1;
rocks.minSize = 2;
rocks.maxSize = 4;
gold.enabled = true;
gold.freq = 0.002;
gold.freqAmpl = 0;
gold.minLevel = 0;
gold.maxLevel = 0.7;
gold.minSize = 2;
gold.maxSize = 5;
}
static void PaintAtPoint(Superchunk &sc, int x, int y, int z, int paintRadius, BlockType paintValue) {
int prsq = paintRadius*paintRadius;
for (int dx = -paintRadius; dx <= paintRadius; dx++) {
int dxsq = dx*dx;
for (int dy = -paintRadius; dy <= paintRadius; dy++) {
int dxdysq = dxsq+dy*dy;
for (int dz = -paintRadius; dz <= paintRadius; dz++)
if (x+dx >= 0 && y+dy>= 0 && z+dz >= 0 && x+dx < sc.getChunksX()*CX && y+dy < sc.getChunksY()*CY && z+dz < sc.getChunksZ()*CZ)
if (dxdysq+dz*dz<prsq)
sc.set(x + dx, y + dy, z + dz, paintValue);
}
}
}
static void WalkL(Superchunk &sc, int x, int y, int z, int len, int paintRadius, BlockType paintValue, bool dontStopAtEdge,
bool cond = false, BlockType condType = BlockType::Dirt) {
const int xs = sc.getChunksX()*CX, ys = sc.getChunksY()*CY, zs = sc.getChunksZ()*CZ;
int m = len, count = 0;
while (count < m) {
if (!cond || (cond && sc.get(x, y, z) == condType))
PaintAtPoint(sc, x, y, z, paintRadius, paintValue);
int dx = FastRand(-paintRadius, paintRadius);
int dy = FastRand(-paintRadius, paintRadius);
int dz = FastRand(-paintRadius, paintRadius);
x += dx;
y += dy;
z += dz;
++count;
if (x < 0 || y < 0 || z < 0 || x >= xs || y >= ys || z >= zs) {
if (dontStopAtEdge) {
if (x < 0) x = 0;
if (y < 0) y = 0;
if (z < 0) z = 0;
if (x >= xs) x = xs - 1;
if (y >= ys) y = ys - 1;
if (z >= zs) z = zs - 1;
} else
break;
}
if (FastRand() & 0x800) {
if (!cond || (cond && sc.get(x, y, z) == condType))
PaintAtPoint(sc, x, y, z, paintRadius, paintValue);
x += dx;
y += dy;
z += dz;
++count;
if (x < 0 || y < 0 || z < 0 || x >= xs || y >= ys || z >= zs) {
if (dontStopAtEdge) {
if (x < 0) x = 0;
if (y < 0) y = 0;
if (z < 0) z = 0;
if (x >= xs) x = xs - 1;
if (y >= ys) y = ys - 1;
if (z >= zs) z = zs - 1;
} else
break;
}
}
}
}
static void Walk(Superchunk &sc, double len, int paintRadius, BlockType paintValue, bool dontStopAtEdge,
bool cond = false, BlockType condType = BlockType::Dirt) {
const int xs = sc.getChunksX()*CX, ys = sc.getChunksY()*CY, zs = sc.getChunksZ()*CZ;
WalkL(sc, FastRand(0, xs-1), FastRand(0, ys-1), FastRand(0, zs-1), xs*ys*zs*len, paintRadius, paintValue, dontStopAtEdge,
cond, condType);
}
static void AddRocks(Superchunk &sc, const CaveGenerator::GenConf &gc) {
int xs = sc.getChunksX()*CX, ys = sc.getChunksY()*CY, zs = sc.getChunksZ()*CZ;
int size = xs*zs;
int numRocks = FastRand(gc.rocks.freq*size, (gc.rocks.freq+gc.rocks.freqAmpl)*size);
for (int i = 0; i < numRocks; i++) {
int x = FastRand(0, xs);
int z = FastRand(0, zs);
// generate a random y-value weighted toward a deep depth
float yf = 0;
for (int j = 0; j < 4; j++)
yf += FastRandF();
yf /= 2;
yf = 1 - fabs(yf - 1);
int y = (int)(yf * ys)-ys+4;
// +4: little padding so we can see the rockballs
int rockSize = (int)(FastRandF()*(gc.rocks.maxSize-gc.rocks.minSize)+gc.rocks.minSize);
PaintAtPoint(sc, x, y, z, rockSize, BlockType::Rock);
}
}
static void AddLava(Superchunk &sc, const CaveGenerator::GenConf &gc) {
const int xs = sc.getChunksX()*CX, ys = sc.getChunksY()*CY, zs = sc.getChunksZ()*CZ;
int minY = gc.lava.minLevel*ys, maxY = gc.lava.maxLevel*ys,
dY = maxY-minY;
int minNum = gc.lava.freq * xs*dY*zs, maxNum = (gc.lava.freq+gc.lava.freqAmpl) * xs*dY*zs;
int numFlows = FastRandF()*(maxNum-minNum)+minNum;
while (numFlows > 0) {
int x = FastRand(0, xs);
int z = FastRand(2, zs);
int y = FastRandF()*(maxY-minY)+minY;
if (sc.get(x, y, z) == BlockType::Air) {
sc.set(x, y, z, BlockType::Lava);
numFlows--;
}
}
}
static void AddOre(Superchunk &sc, const CaveGenerator::GenConf &gc) {
const int xs = sc.getChunksX()*CX, ys = sc.getChunksY()*CY, zs = sc.getChunksZ()*CZ;
int yRand = FastRand(0xFFFF);
for (int x = 0; x < xs; x++)
for (int y = 0; y < ys; y++)
for (int z = 0; z < zs; z++) {
float noise = stb_perlin_noise3(x/8.f, y/8.f+yRand, z/8.f);
sc.set(x, y, z, (noise > gc.ore.thresold) ? BlockType::Ore : BlockType::Dirt);
}
}
static void AddDiamond(Superchunk &sc, const CaveGenerator::GenConf &gc) {
const int xs = sc.getChunksX()*CX, ys = sc.getChunksY()*CY, zs = sc.getChunksZ()*CZ;
int minY = gc.diamond.minLevel*ys, maxY = gc.diamond.maxLevel*ys,
dY = maxY-minY;
int minNum = gc.diamond.freq * xs*dY*zs, maxNum = (gc.diamond.freq+gc.diamond.freqAmpl) * xs*dY*zs;
int numDiam = FastRandF()*(maxNum-minNum)+minNum;
while (numDiam > 0) {
int x = FastRand(0, xs);
int z = FastRand(0, zs);
int y = FastRandF()*(maxY-minY)+minY;
if (y > 2 && (sc.get(x, y, z) == BlockType::Dirt || sc.get(x, y, z) == BlockType::Ore)) {
sc.set(x, y, z, BlockType::Diamond);
numDiam--;
}
}
}
static void AddGold(Superchunk &sc, const CaveGenerator::GenConf &gc) {
const int xs = sc.getChunksX()*CX, ys = sc.getChunksY()*CY, zs = sc.getChunksZ()*CZ;
int minY = gc.gold.minLevel*ys, maxY = gc.gold.maxLevel*ys,
dY = maxY-minY;
int minNum = gc.gold.freq * xs*dY*zs, maxNum = (gc.gold.freq+gc.gold.freqAmpl) * xs*dY*zs;
int numVeins = FastRandF()*(maxNum-minNum)+minNum;
while (numVeins > 0) {
int x = FastRand(0, xs);
int z = FastRand(0, zs);
int y = FastRandF()*(maxY-minY)+minY;
if (y > 2 && (sc.get(x, y, z) == BlockType::Dirt || sc.get(x, y, z) == BlockType::Ore)) {
WalkL(sc, x, y, z, FastRand(gc.gold.minSize, gc.gold.maxSize), 1, BlockType::Gold, false, true);
numVeins--;
}
}
}
void CaveGenerator::Generate(Superchunk &sc, const GenConf &gc) {
const int xs = sc.getChunksX()*CX, ys = sc.getChunksY()*CY, zs = sc.getChunksZ()*CZ;
int groundLevel = ys*gc.groundLevel;
FastRandSeed(gc.seed);
if (gc.ore.enabled)
AddOre(sc, gc);
else
for (int x = 0; x < xs; x++)
for (int y = 0; y < groundLevel; y++)
for (int z = 0; z < zs; z++)
sc.set(x, y, z, BlockType::Dirt);
// Mountains
int yRand = FastRand(0xFFFF);
for (int y = groundLevel; y < ys; y++) {
float intensity = (groundLevel-y)/(float)(ys-groundLevel)+1;
for (int x = 0; x < xs; x++)
for (int z = 0; z < zs; z++) {
float noise = stb_perlin_noise3(x/8.f, y/8.f+yRand, z/8.f) * intensity;
sc.set(x, y, z, (noise > 0.05f) ? BlockType::Dirt : BlockType::Air);
}
}
if (gc.cave.enabled) {
for (int i=0; i < gc.cave.count; ++i)
Walk(sc, gc.cave.length, 3, BlockType::Air, true);
}
if (gc.lava.enabled)
AddLava(sc, gc);
if (gc.rocks.enabled)
AddRocks(sc, gc);
if (gc.diamond.enabled)
AddDiamond(sc, gc);
if (gc.gold.enabled)
AddGold(sc, gc);
}
}