106 lines
3.0 KiB
C++
106 lines
3.0 KiB
C++
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "Block.h"
|
|
#include "EditHistory.h"
|
|
#include "Math.h"
|
|
#include "Selection.h"
|
|
#include "World.h"
|
|
|
|
namespace vf {
|
|
|
|
enum class BrushKind : uint8_t {
|
|
Sphere = 0,
|
|
Cylinder = 1,
|
|
Replace = 2,
|
|
Smooth = 3,
|
|
Erode = 4,
|
|
Overlay = 5,
|
|
Naturalize = 6,
|
|
Gradient = 7,
|
|
};
|
|
|
|
// Everything a stroke needs. One struct for all brushes: a kind reads the
|
|
// fields that apply to it and ignores the rest, which keeps a brush preset a
|
|
// plain value that can be stored, copied and replayed.
|
|
struct BrushParams {
|
|
enum class VolumeMode : uint8_t {
|
|
Fill = 0,
|
|
Hollow = 1,
|
|
Shell = 2,
|
|
};
|
|
|
|
BrushKind kind = BrushKind::Sphere;
|
|
VolumeMode mode = VolumeMode::Fill;
|
|
|
|
Vec3i center{0, 0, 0};
|
|
int radius = 3;
|
|
int height = 4;
|
|
int shellThickness = 1;
|
|
|
|
Block block = Block::Stone;
|
|
Block secondaryBlock = Block::Dirt;
|
|
|
|
// Empty means "every non-air block"; otherwise only the listed types are
|
|
// touched, which is what makes a replace brush safe to drag over terrain.
|
|
std::vector<Block> onlyReplace;
|
|
|
|
int freeNeighbourThreshold = 3;
|
|
int soilDepth = 3;
|
|
Block surfaceBlock = Block::Grass;
|
|
Block soilBlock = Block::Dirt;
|
|
Block deepBlock = Block::Stone;
|
|
|
|
uint32_t seed = 0u;
|
|
|
|
int worldMinY = 0;
|
|
int worldMaxY = 256;
|
|
|
|
std::string label;
|
|
};
|
|
|
|
struct BrushResult {
|
|
std::size_t changed = 0;
|
|
std::size_t visited = 0;
|
|
bool outsideLoadedWorld = false;
|
|
bool clippedAtHeightLimit = false;
|
|
bool recorded = false;
|
|
};
|
|
|
|
// Applies brushes to a world through an EditHistory. One call to apply() is one
|
|
// batch, so every stroke - including the ones that touch thousands of blocks -
|
|
// undoes in a single step.
|
|
class BrushStroke {
|
|
public:
|
|
BrushStroke(World& world, EditHistory& history);
|
|
|
|
BrushResult apply(const BrushParams& params, uint64_t tick);
|
|
BrushResult applyWithin(const BrushParams& params, const Selection& limit, uint64_t tick);
|
|
|
|
// The volume a brush covers when no selection restricts it.
|
|
static Selection regionOf(const BrushParams& params);
|
|
static const char* kindName(BrushKind kind);
|
|
|
|
const BrushResult& lastResult() const { return previous; }
|
|
|
|
private:
|
|
void write(const BrushParams& params, const Vec3i& cell, Block block, BrushResult& outcome);
|
|
void paintVolume(const BrushParams& params, const Selection& limit, BrushResult& outcome);
|
|
void paintReplace(const BrushParams& params, const Selection& limit, BrushResult& outcome);
|
|
void paintSmooth(const BrushParams& params, const Selection& limit, BrushResult& outcome);
|
|
void paintNeighbourRule(const BrushParams& params, const Selection& limit, bool erode,
|
|
BrushResult& outcome);
|
|
void paintNaturalize(const BrushParams& params, const Selection& limit, BrushResult& outcome);
|
|
void paintGradient(const BrushParams& params, const Selection& limit, BrushResult& outcome);
|
|
|
|
World& world;
|
|
EditHistory& history;
|
|
BrushResult previous;
|
|
};
|
|
|
|
} // namespace vf
|