]> git.localhorst.tv Git - blank.git/blob - src/world/Generator.cpp
try to cleanly destruct world
[blank.git] / src / world / Generator.cpp
1 #include "Generator.hpp"
2
3 #include "BlockType.hpp"
4 #include "BlockTypeRegistry.hpp"
5 #include "Chunk.hpp"
6 #include "../rand/OctaveNoise.hpp"
7
8 #include <glm/glm.hpp>
9
10
11 namespace blank {
12
13 namespace {
14
15 struct Candidate {
16         const BlockType *type;
17         float threshold;
18         Candidate(const BlockType *type, float threshold)
19         : type(type), threshold(threshold) { }
20 };
21
22 std::vector<Candidate> candidates;
23
24 }
25
26 Generator::Generator(const Config &config) noexcept
27 : config(config)
28 , types()
29 , min_solidity(2.0f)
30 , solidity_noise(config.seed ^ config.solidity.seed_mask)
31 , humidity_noise(config.seed ^ config.humidity.seed_mask)
32 , temperature_noise(config.seed ^ config.temperature.seed_mask)
33 , richness_noise(config.seed ^ config.richness.seed_mask)
34 , random_noise(config.seed ^ config.randomness.seed_mask) {
35
36 }
37
38 void Generator::LoadTypes(const BlockTypeRegistry &reg) {
39         types.clear();
40         min_solidity = 2.0f;
41         for (const BlockType &type : reg) {
42                 if (type.generate) {
43                         types.push_back(&type);
44                         if (type.min_solidity < min_solidity) {
45                                 min_solidity = type.min_solidity;
46                         }
47                 }
48         }
49         candidates.reserve(types.size());
50 }
51
52 void Generator::operator ()(Chunk &chunk) const noexcept {
53         ExactLocation::Coarse pos(chunk.Position());
54         ExactLocation::Fine coords(pos * ExactLocation::Extent());
55         for (int z = 0; z < Chunk::side; ++z) {
56                 for (int y = 0; y < Chunk::side; ++y) {
57                         for (int x = 0; x < Chunk::side; ++x) {
58                                 ExactLocation::Fine block_pos(x, y, z);
59                                 chunk.SetBlock(RoughLocation::Fine(x, y, z), Generate(coords + ExactLocation::Fine(x, y, z)));
60                         }
61                 }
62         }
63         chunk.SetGenerated();
64 }
65
66 Block Generator::Generate(const glm::vec3 &pos) const noexcept {
67         float solidity = GetValue(solidity_noise, pos, config.solidity);
68         if (solidity < min_solidity) {
69                 return Block(0);
70         }
71         float humidity = GetValue(humidity_noise, pos, config.humidity);
72         float temperature = GetValue(temperature_noise, pos, config.temperature);
73         float richness = GetValue(richness_noise, pos, config.richness);
74
75         candidates.clear();
76         float total = 0.0f;
77         for (const BlockType *type : types) {
78                 if (solidity < type->min_solidity || solidity > type->max_solidity) continue;
79                 if (humidity < type->min_humidity || humidity > type->max_humidity) continue;
80                 if (temperature < type->min_temperature || temperature > type->max_temperature) continue;
81                 if (richness < type->min_richness || richness > type->max_richness) continue;
82                 float solidity_match = 4.0f - ((solidity - type->mid_solidity) * (solidity - type->mid_solidity));
83                 float humidity_match = 4.0f - ((humidity - type->mid_humidity) * (humidity - type->mid_humidity));
84                 float temperature_match = 4.0f - ((temperature - type->mid_temperature) * (temperature - type->mid_temperature));
85                 float richness_match = 4.0f - ((richness - type->mid_richness) * (richness - type->mid_richness));
86                 float chance = (solidity_match + humidity_match + temperature_match + richness_match) * type->commonness;
87                 total += chance;
88                 candidates.emplace_back(type, total);
89         }
90         if (candidates.empty()) {
91                 return Block(0);
92         }
93         float random = GetValue(random_noise, pos, config.randomness);
94         if (random < 0.0f) random += 1.0f;
95         float value = random * total;
96         // TODO: change to binary search
97         for (const Candidate &cand : candidates) {
98                 if (value < cand.threshold) {
99                         return Block(cand.type->id);
100                 }
101         }
102         // theoretically, this should never happen
103         return Block(candidates.back().type->id);
104 }
105
106 float Generator::GetValue(
107         const SimplexNoise &noise,
108         const glm::vec3 &pos,
109         const Config::NoiseParam &conf
110 ) noexcept {
111         return OctaveNoise(
112                 noise,
113                 pos,
114                 conf.octaves,
115                 conf.persistence,
116                 conf.frequency,
117                 conf.amplitude,
118                 conf.growth
119         );
120 }
121
122 }