]> git.localhorst.tv Git - blank.git/blob - src/world/Generator.cpp
more parameters for world generation
[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, const BlockTypeRegistry &types) noexcept
27 : config(config)
28 , types(types)
29 , solidity_noise(config.seed ^ config.solidity.seed_mask)
30 , humidity_noise(config.seed ^ config.humidity.seed_mask)
31 , temperature_noise(config.seed ^ config.temperature.seed_mask)
32 , richness_noise(config.seed ^ config.richness.seed_mask)
33 , random_noise(config.seed ^ config.randomness.seed_mask) {
34
35 }
36
37 void Generator::Scan() {
38         size_t count = 0;
39         for (size_t i = 0, end = types.Size(); i < end; ++i) {
40                 if (types[i].generate) ++count;
41         }
42         candidates.reserve(count);
43 }
44
45 void Generator::operator ()(Chunk &chunk) const noexcept {
46         Chunk::Pos pos(chunk.Position());
47         glm::vec3 coords(pos * Chunk::Extent());
48         for (int z = 0; z < Chunk::depth; ++z) {
49                 for (int y = 0; y < Chunk::height; ++y) {
50                         for (int x = 0; x < Chunk::width; ++x) {
51                                 Block::Pos block_pos(x, y, z);
52                                 chunk.SetBlock(block_pos, Generate(coords + block_pos));
53                         }
54                 }
55         }
56 }
57
58 Block Generator::Generate(const glm::vec3 &pos) const noexcept {
59         float solidity = GetValue(solidity_noise, pos, config.solidity);
60         float humidity = GetValue(humidity_noise, pos, config.humidity);
61         float temperature = GetValue(temperature_noise, pos, config.temperature);
62         float richness = GetValue(richness_noise, pos, config.richness);
63
64         candidates.clear();
65         float total = 0.0f;
66         for (size_t i = 0, end = types.Size(); i < end; ++i) {
67                 const BlockType &type = types[i];
68                 if (!type.generate) continue;
69                 if (solidity < type.min_solidity || solidity > type.max_solidity) continue;
70                 if (humidity < type.min_humidity || humidity > type.max_humidity) continue;
71                 if (temperature < type.min_temperature || temperature > type.max_temperature) continue;
72                 if (richness < type.min_richness || richness > type.max_richness) continue;
73                 float solidity_match = 4.0f - ((solidity - type.mid_solidity) * (solidity - type.mid_solidity));
74                 float humidity_match = 4.0f - ((humidity - type.mid_humidity) * (humidity - type.mid_humidity));
75                 float temperature_match = 4.0f - ((temperature - type.mid_temperature) * (temperature - type.mid_temperature));
76                 float richness_match = 4.0f - ((richness - type.mid_richness) * (richness - type.mid_richness));
77                 float chance = (solidity_match + humidity_match + temperature_match + richness_match) * type.commonness;
78                 total += chance;
79                 candidates.emplace_back(&type, total);
80         }
81         if (candidates.empty()) {
82                 return Block(0);
83         }
84         float random = GetValue(random_noise, pos, config.randomness);
85         if (random < 0.0f) random += 1.0f;
86         float value = random * total;
87         // TODO: change to binary search
88         for (const Candidate &cand : candidates) {
89                 if (value < cand.threshold) {
90                         return Block(cand.type->id);
91                 }
92         }
93         // theoretically, this should never happen
94         return Block(candidates.back().type->id);
95 }
96
97 float Generator::GetValue(
98         const SimplexNoise &noise,
99         const glm::vec3 &pos,
100         const Config::NoiseParam &conf
101 ) noexcept {
102         return OctaveNoise(
103                 noise,
104                 pos,
105                 conf.octaves,
106                 conf.persistence,
107                 conf.frequency,
108                 conf.amplitude,
109                 conf.growth
110         );
111 }
112
113 }