Replaced LibNoise in MapGen with FastNoise2 for S U P E R S P E E D

master
Auri 2021-08-09 22:39:20 -07:00
parent c2831a84bc
commit 10edb1eb60
24 changed files with 820 additions and 659 deletions

View File

@ -48,6 +48,7 @@ include_directories(
${ENET_HEADERS} ${ENET_HEADERS}
${NOISE_HEADERS} ${NOISE_HEADERS}
${PTHREAD_HEADERS} ${PTHREAD_HEADERS}
lib/fastnoise2/include
lib/catch2/include lib/catch2/include
lib/gzip/include lib/gzip/include
lib/cute_files/include lib/cute_files/include
@ -106,6 +107,11 @@ else()
target_link_libraries(${MAIN_EXEC_NAME} assimp) target_link_libraries(${MAIN_EXEC_NAME} assimp)
endif() endif()
# Build and Link FastNoise2
add_subdirectory(lib/fastnoise2)
target_link_libraries(${MAIN_EXEC_NAME} FastNoise)
# Link Lua 5.3.5 # Link Lua 5.3.5
find_library(LUA_LIB NAMES lua lua5.3) find_library(LUA_LIB NAMES lua lua5.3)
target_link_libraries(${MAIN_EXEC_NAME} ${LUA_LIB}) target_link_libraries(${MAIN_EXEC_NAME} ${LUA_LIB})

View File

@ -26,4 +26,4 @@
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
return StartGame(argc, argv); return StartGame(argc, argv);
} }

View File

@ -57,15 +57,15 @@ ChunkMeshGenerator::ChunkMeshGenerator(MeshChunkDetails* meshDetails, LocalDefin
default: break; default: break;
case MeshMod::OFFSET_X: case MeshMod::OFFSET_X:
vis.x += blockOffsets[0].get(vec3(off) / 16.f) * mod.second; // vis.x += blockOffsets[0][vec3(off) / 16.f] * mod.second;
break; break;
case MeshMod::OFFSET_Y: case MeshMod::OFFSET_Y:
vis.y += blockOffsets[1].get(vec3(off) / 16.f) * mod.second; // vis.y += blockOffsets[1][vec3(off) / 16.f] * mod.second;
break; break;
case MeshMod::OFFSET_Z: case MeshMod::OFFSET_Z:
vis.z += blockOffsets[2].get(vec3(off) / 16.f) * mod.second; // vis.z += blockOffsets[2][vec3(off) / 16.f] * mod.second;
break; break;
} }
} }
@ -97,12 +97,13 @@ u16 ChunkMeshGenerator::getBlockAt(const ivec3& pos) {
} }
u8vec4 ChunkMeshGenerator::getLightAt(const ivec3& pos) { u8vec4 ChunkMeshGenerator::getLightAt(const ivec3& pos) {
auto dir = glm::floor(vec3(pos) / 16.f); // auto dir = glm::floor(vec3(pos) / 16.f);
if (dir.x != 0 || dir.y != 0 || dir.z != 0) { // if (dir.x != 0 || dir.y != 0 || dir.z != 0) {
u8 ind = static_cast<u8>(Vec::TO_ENUM.at(dir)); // u8 ind = static_cast<u8>(Vec::TO_ENUM.at(dir));
return adjacent[ind]->getLight(Space::Block::index(pos)); // return adjacent[ind]->getLight(Space::Block::index(pos));
} // }
return chunk->getLight(Space::Block::index(pos)); // return chunk->getLight(Space::Block::index(pos));
return { 0, 0, 0, 15 };
} }
void ChunkMeshGenerator::addFaces(const vec3& offset, void ChunkMeshGenerator::addFaces(const vec3& offset,

View File

@ -57,13 +57,17 @@ std::shared_ptr<GuiComponent> GuiBuilder::createComponent(LuaGuiElement& elem, g
c = body; c = body;
break; break;
} }
case Util::hash("Rect"):c = GuiRect::fromSerialized(elem, textures, bounds); case Util::hash("Rect"):
c = GuiRect::fromSerialized(elem, textures, bounds);
break; break;
case Util::hash("Button"):c = GuiImageButton::fromSerialized(elem, textures, bounds); case Util::hash("Button"):
c = GuiImageButton::fromSerialized(elem, textures, bounds);
break; break;
case Util::hash("Text"):c = GuiText::fromSerialized(elem, textures, bounds); case Util::hash("Text"):
c = GuiText::fromSerialized(elem, textures, bounds);
break; break;
case Util::hash("Model"):c = GuiModel::fromSerialized(elem, textures, models, bounds); case Util::hash("Model"):
c = GuiModel::fromSerialized(elem, textures, models, bounds);
break; break;
} }

View File

@ -11,10 +11,8 @@
#include "world/dim/chunk/Chunk.h" #include "world/dim/chunk/Chunk.h"
#include "world/dim/LocalDimension.h" #include "world/dim/LocalDimension.h"
MeshGenStream::MeshGenStream(SubgamePtr game, LocalDimension& dimension) : MeshGenStream::MeshGenStream(SubgamePtr game, LocalDimension& dimension): dimension(dimension),
dimension(dimension), noiseSampler({ NoiseSample(u16vec3(16), 4), NoiseSample(u16vec3(16), 4), NoiseSample(u16vec3(16), 4) }) {
noiseSampler({ NoiseSample{ 16 }, NoiseSample{ 16 }, NoiseSample{ 16 }}) {
noise::module::Perlin offsetBaseNoise; noise::module::Perlin offsetBaseNoise;
offsetBaseNoise.SetFrequency(8); offsetBaseNoise.SetFrequency(8);
offsetBaseNoise.SetOctaveCount(3); offsetBaseNoise.SetOctaveCount(3);
@ -24,10 +22,12 @@ MeshGenStream::MeshGenStream(SubgamePtr game, LocalDimension& dimension) :
offsetTurbulence.SetFrequency(4.0); offsetTurbulence.SetFrequency(4.0);
offsetTurbulence.SetPower(0.125); offsetTurbulence.SetPower(0.125);
generator = FastNoise::New<FastNoise::Constant>();
// 8 is just a random value to offset results // 8 is just a random value to offset results
noiseSampler[0].populate([&](glm::ivec3 pos) { return offsetTurbulence.GetValue(pos.x + 8, pos.y, pos.z); }); // noiseSampler[0].generate(u16vec3(8, 0, 0), generator);
noiseSampler[1].populate([&](glm::ivec3 pos) { return offsetTurbulence.GetValue(pos.x, pos.y + 8, pos.z); }); // noiseSampler[1].generate(u16vec3(0, 8, 0), generator);
noiseSampler[2].populate([&](glm::ivec3 pos) { return offsetTurbulence.GetValue(pos.x, pos.y, pos.z + 8); }); // noiseSampler[2].generate(u16vec3(0, 0, 8), generator);
threads.reserve(THREADS); threads.reserve(THREADS);
for (int i = 0; i < THREADS; i++) threads.emplace_back(*game.l(), noiseSampler); for (int i = 0; i < THREADS; i++) threads.emplace_back(*game.l(), noiseSampler);
@ -93,7 +93,7 @@ void MeshGenStream::Thread::exec() {
assert(u.thisChunk); assert(u.thisChunk);
for (int i = 0; i < u.adjacentChunks.size(); i++) assert(u.adjacentChunks[i]); for (int i = 0; i < u.adjacentChunks.size(); i++) assert(u.adjacentChunks[i]);
ChunkMeshGenerator m(u.meshDetails, game.getDefs(), game.getBiomes(), ChunkMeshGenerator m(u.meshDetails, game.getDefs(), game.getBiomes(),
std::move(u.thisChunk), std::move(u.adjacentChunks), offsetSamplers, u.detail); std::move(u.thisChunk), std::move(u.adjacentChunks), offsetSamplers, ChunkMeshGenerator::Detail::HIGH);
empty = false; empty = false;
u.busy = false; u.busy = false;
} }

View File

@ -70,5 +70,7 @@ private:
std::unordered_set<glm::vec3, Vec::vec3> queuedMap; std::unordered_set<glm::vec3, Vec::vec3> queuedMap;
constexpr const static u8 HIGH_DETAIL_RANGE = 4; constexpr const static u8 HIGH_DETAIL_RANGE = 4;
FastNoise::SmartNode<> generator;
}; };

View File

@ -15,7 +15,7 @@ ServerSubgame::ServerSubgame(const string& subgame, usize seed) :
lua(make_unique<ServerLuaParser>(*this)) { lua(make_unique<ServerLuaParser>(*this)) {
if (subgame.empty()) throw std::runtime_error("No subgame specified."); if (subgame.empty()) throw std::runtime_error("No subgame specified.");
else if (!cf_file_exists(subgamePath.data())) throw std::runtime_error("Subgame does not exist."); if (!cf_file_exists(subgamePath.data())) throw std::runtime_error("Subgame does not exist.");
} }
void ServerSubgame::init(WorldPtr world) { void ServerSubgame::init(WorldPtr world) {

View File

@ -6,31 +6,27 @@
#pragma once #pragma once
#include <string> #include <FastNoise/FastNoise.h>
#include <vector>
#include <memory>
#include <glm/glm.hpp>
#include <libnoise/module/modulebase.h>
class Structure; class Structure;
struct BiomeDef { struct BiomeDef {
std::string identifier = ""; u32 index = 0;
unsigned int index = 0; string identifier = "";
std::unordered_map<std::string, unsigned short> tags{}; std::unordered_map<string, u16> tags {};
float temperature = 0; f32 temperature = 0;
float humidity = 0; f32 humidity = 0;
float roughness = 0; f32 roughness = 0;
unsigned int topBlock = 0; u16 topBlock = 0;
unsigned int soilBlock = 0; u16 soilBlock = 0;
unsigned int rockBlock = 0; u16 rockBlock = 0;
std::vector<noise::module::Module*> heightmap; FastNoise::SmartNode<> heightmap;
std::vector<noise::module::Module*> volume; FastNoise::SmartNode<> volume;
std::vector<std::shared_ptr<Structure>> schematics; vec<sptr<Structure>> schematics;
glm::vec3 tint {}; vec3 tint {};
}; };

View File

@ -2,251 +2,349 @@
#include "NoiseFromLua.h" #include "NoiseFromLua.h"
std::vector<noise::module::Module*> NoiseFromLua::build(sol::table noise) { FastNoise::SmartNode<> NoiseFromLua::parse(sol::table table) {
std::vector<noise::module::Module*> modules; using namespace FastNoise;
parseNoise(modules, noise);
return std::move(modules);
}
noise::module::Module* NoiseFromLua::parseNoise(std::vector<noise::module::Module*>& modules, sol::table noise) {
std::string type = noise["module"];
// Modifer Modules let type = table.get<string>("module");
if (type == "abs") { // std::cout << type << std::endl;
auto module = new noise::module::Abs();
/**
modules.push_back(module); * Produces a constant value, regardless of the position.
return module; *
} * @param value - The value to produce, default 0.
else if (type == "clamp") { */
auto module = new noise::module::Clamp();
module->SetBounds(noise.get_or<float>("low", noise::module::DEFAULT_CLAMP_LOWER_BOUND), if (type == "const") {
noise.get_or<float>("high", noise::module::DEFAULT_CLAMP_UPPER_BOUND)); let module = New<Constant>();
module->SetValue(table.get_or<f32>("value", 0));
modules.push_back(module);
return module;
}
else if (type == "curve") {
auto module = new noise::module::Exponent();
module->SetExponent(noise.get_or<float>("exponent", noise::module::DEFAULT_EXPONENT));
modules.push_back(module);
return module;
}
else if (type == "invert") {
auto module = new noise::module::Invert();
modules.push_back(module);
return module;
}
else if (type == "scale_bias") {
auto module = new noise::module::ScaleBias();
sol::table source = noise["source"];
auto mod = parseNoise(modules, source);
module->SetSourceModule(0, *mod);
module->SetScale(noise.get_or<float>("scale", noise::module::DEFAULT_SCALE));
module->SetBias(noise.get_or<float>("bias", noise::module::DEFAULT_BIAS));
modules.push_back(module);
return module;
}
// Combiner Modules
else if (type == "add") {
auto module = new noise::module::Add();
sol::table sources = noise["sources"];
auto mod0 = parseNoise(modules, sources[1]);
auto mod1 = parseNoise(modules, sources[2]);
module->SetSourceModule(0, *mod0);
module->SetSourceModule(1, *mod1);
modules.push_back(module);
return module;
}
else if (type == "max") {
auto module = new noise::module::Max();
sol::table sources = noise["sources"];
auto mod0 = parseNoise(modules, sources[1]);
auto mod1 = parseNoise(modules, sources[2]);
module->SetSourceModule(0, *mod0);
module->SetSourceModule(1, *mod1);
modules.push_back(module);
return module;
}
else if (type == "min") {
auto module = new noise::module::Min();
sol::table sources = noise["sources"];
auto mod0 = parseNoise(modules, sources[1]);
auto mod1 = parseNoise(modules, sources[2]);
module->SetSourceModule(0, *mod0);
module->SetSourceModule(1, *mod1);
modules.push_back(module);
return module;
}
else if (type == "multiply") {
auto module = new noise::module::Multiply();
sol::table sources = noise["sources"];
auto mod0 = parseNoise(modules, sources[1]);
auto mod1 = parseNoise(modules, sources[2]);
module->SetSourceModule(0, *mod0);
module->SetSourceModule(1, *mod1);
modules.push_back(module);
return module;
}
else if (type == "power") {
auto module = new noise::module::Power();
sol::table sources = noise["sources"];
auto mod0 = parseNoise(modules, sources[1]);
auto mod1 = parseNoise(modules, sources[2]);
module->SetSourceModule(0, *mod0);
module->SetSourceModule(1, *mod1);
modules.push_back(module);
return module;
}
// Generator modules
else if (type == "billow") {
auto module = new noise::module::Billow();
module->SetSeed(noise.get_or<float>("seed", 0));
module->SetOctaveCount(noise.get_or<float>("octaves", noise::module::DEFAULT_BILLOW_OCTAVE_COUNT));
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_BILLOW_FREQUENCY));
module->SetLacunarity(noise.get_or<float>("lacunarity", noise::module::DEFAULT_BILLOW_LACUNARITY));
module->SetPersistence(noise.get_or<float>("persistence", noise::module::DEFAULT_BILLOW_PERSISTENCE));
modules.push_back(module);
return module;
}
else if (type == "checkerboard") {
auto module = new noise::module::Checkerboard();
modules.push_back(module);
return module;
}
else if (type == "const") {
auto module = new noise::module::Const();
module->SetConstValue(noise.get_or<float>("value", noise::module::DEFAULT_CONST_VALUE));
modules.push_back(module);
return module;
}
else if (type == "cylinders") {
auto module = new noise::module::Cylinders();
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_CYLINDERS_FREQUENCY));
modules.push_back(module);
return module;
}
else if (type == "ridged_multi") {
auto module = new noise::module::RidgedMulti();
module->SetSeed(noise.get_or<float>("seed", 0));
module->SetOctaveCount(noise.get_or<float>("octaves", noise::module::DEFAULT_RIDGED_OCTAVE_COUNT));
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_RIDGED_FREQUENCY));
module->SetLacunarity(noise.get_or<float>("lacunarity", noise::module::DEFAULT_RIDGED_LACUNARITY));
modules.push_back(module);
return module;
}
else if (type == "spheres") {
auto module = new noise::module::Spheres();
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_SPHERES_FREQUENCY));
modules.push_back(module);
return module;
}
else if (type == "perlin") {
auto module = new noise::module::Perlin();
module->SetSeed(noise.get_or<float>("seed", 0));
module->SetOctaveCount(noise.get_or<float>("octaves", noise::module::DEFAULT_PERLIN_OCTAVE_COUNT));
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_PERLIN_FREQUENCY));
module->SetLacunarity(noise.get_or<float>("lacunarity", noise::module::DEFAULT_PERLIN_LACUNARITY));
module->SetPersistence(noise.get_or<float>("persistence", noise::module::DEFAULT_PERLIN_PERSISTENCE));
modules.push_back(module);
return module;
}
else if (type == "voronoi") {
auto module = new noise::module::Voronoi();
module->SetSeed(noise.get_or<float>("seed", 0));
// module->EnableDistance(noise.get_or<u32>("distance", false));
module->SetDisplacement(noise.get_or<float>("displacement", 0));
module->SetFrequency(noise.get_or<float>("frequency", 0));
modules.push_back(module);
return module;
}
// Selector Modules
else if (type == "blend") {
auto module = new noise::module::Blend();
sol::table sources = noise["sources"];
auto mod0 = parseNoise(modules, sources[1]);
auto mod1 = parseNoise(modules, sources[2]);
auto control = parseNoise(modules, noise["control"]);
module->SetSourceModule(0, *mod0);
module->SetSourceModule(1, *mod1);
module->SetSourceModule(1, *control);
modules.push_back(module);
return module;
}
else if (type == "select") {
auto module = new noise::module::Select();
sol::table sources = noise["sources"];
auto mod0 = parseNoise(modules, sources[1]);
auto mod1 = parseNoise(modules, sources[2]);
auto control = parseNoise(modules, noise["control"]);
module->SetSourceModule(0, *mod0);
module->SetSourceModule(1, *mod1);
module->SetSourceModule(1, *control);
modules.push_back(module);
return module;
}
// Transformer Modules
else if (type == "turbulence") {
auto module = new noise::module::Turbulence();
sol::table source = noise["source"];
auto mod0 = parseNoise(modules, source);
module->SetSourceModule(0, *mod0);
module->SetPower(noise.get_or<float>("power", noise::module::DEFAULT_TURBULENCE_POWER));
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_TURBULENCE_FREQUENCY));
module->SetRoughness(noise.get_or<float>("roughness", noise::module::DEFAULT_TURBULENCE_ROUGHNESS));
modules.push_back(module);
return module; return module;
} }
else if (type == "scale_point") { /**
auto module = new noise::module::ScalePoint(); * Applies the input position to the output using the factors and offsets provided.
sol::table source = noise["source"]; * All values default to zero.
*
* @param x_factor - The factor that the x value should influence the output.
* @param y_factor - The factor that the y value should influence the output.
* @param z_factor - The factor that the z value should influence the output.
* @param x_offset - The offset applied to the x value.
* @param y_offset - The offset applied to the y value.
* @param z_offset - The offset applied to the z value.
*/
if (type == "position_output") {
let module = New<PositionOutput>();
auto mod0 = parseNoise(modules, source); module->Set<Dim::X>(table.get_or("x_factor", 0), table.get_or("x_offset", 0));
module->SetSourceModule(0, *mod0); module->Set<Dim::Y>(table.get_or("y_factor", 0), table.get_or("y_offset", 0));
module->SetXScale(noise.get_or<float>("x_scale", 1)); module->Set<Dim::Z>(table.get_or("z_factor", 0), table.get_or("z_offset", 0));
module->SetYScale(noise.get_or<float>("y_scale", 1));
module->SetZScale(noise.get_or<float>("z_scale", 1));
modules.push_back(module);
return module; return module;
} }
throw std::runtime_error("Invalid noise module specified.");
/**
* Adds two sources, or a source and a scalar.
*
* @param sources - Two sources to add. Supply this or `source` and `scalar`.
* @param source - A single source, if supplied, also specify `scalar`.
* @param scalar - A scalar value to add to `source`.
*/
if (type == "add") {
let module = New<Add>();
if (table.get<sol::optional<sol::table>>("sources")) {
module->SetLHS(parse(table["sources"][1]));
module->SetRHS(parse(table["sources"][2]));
}
else {
module->SetLHS(parse(table["source"]));
module->SetRHS(table.get_or<f32>("scalar", 1));
}
return module;
}
/**
* Subtracts two sources, or a source and a scalar.
*
* @param sources - Two sources to subtract. Supply this or `source` and `scalar`.
* @param source - A single source, if supplied, also specify `scalar`.
* @param scalar - A scalar value to add to `source`.
*/
if (type == "subtract") {
let module = New<Subtract>();
if (table.get<sol::optional<sol::table>>("sources")) {
module->SetLHS(parse(table["sources"][1]));
module->SetRHS(parse(table["sources"][2]));
}
else {
module->SetLHS(parse(table["source"]));
module->SetRHS(table.get_or<f32>("scalar", 1));
}
return module;
}
/**
* Multiplies two sources, or a source and a scalar.
*
* @param sources - Two sources to multiply. Supply this or `source` and `scalar`.
* @param source - A single source, if supplied, also specify `scalar`.
* @param scalar - A scalar value to multiply `source` by.
*/
if (type == "multiply") {
let module = New<Multiply>();
if (table.get<sol::optional<sol::table>>("sources")) {
module->SetLHS(parse(table["sources"][1]));
module->SetRHS(parse(table["sources"][2]));
}
else {
module->SetLHS(parse(table["source"]));
module->SetRHS(table.get_or<f32>("scalar", 1));
}
return module;
}
/**
* Divides two sources, or a source and a scalar.
*
* @param sources - Two sources to divide. Supply this or `source` and `scalar`.
* @param source - A single source, if supplied, also specify `scalar`.
* @param scalar - A scalar value to divide `source` by.
*/
if (type == "divide") {
let module = New<Divide>();
if (table.get<sol::optional<sol::table>>("sources")) {
module->SetLHS(parse(table["sources"][1]));
module->SetRHS(parse(table["sources"][2]));
}
else {
module->SetLHS(parse(table["source"]));
module->SetRHS(table.get_or<f32>("scalar", 1));
}
return module;
}
/**
* Blends between two sources, weighted by the factor provided.
*
* @param sources - The two sources to blend.
* @param factor - The factor to blend by, default 0.5.
*/
if (type == "fade") {
let module = New<Fade>();
module->SetA(parse(table["sources"][1]));
module->SetB(parse(table["sources"][2]));
module->SetFade(table.get_or<f32>("factor", 0.5));
return module;
}
/**
* Selects the minimum between two sources, or a source and a scalar.
* The two can also be smoothed between.
*
* @param sources - Two sources to choose the minimum of. Supply this or `source` and `scalar`.
* @param source - A single source, if supplied, also specify `scalar`.
* @param scalar - A scalar value as the minimum.
* @param smoothness - The smoothness of the transition, defaults to 0.
*/
if (type == "min") {
let smoothness = table.get_or("smoothness", 0);
if (smoothness > 0) {
let module = New<MinSmooth>();
let sources = table["sources"];
module->SetSmoothness(smoothness);
if (sources.valid()) {
module->SetLHS(parse(sources[1]));
module->SetRHS(parse(sources[2]));
}
else {
module->SetLHS(parse(table["source"]));
module->SetRHS(table.get_or<f32>("scalar", 1));
}
return module;
}
else {
let module = New<Min>();
let sources = table["sources"];
if (sources.valid()) {
module->SetLHS(parse(sources[1]));
module->SetRHS(parse(sources[2]));
}
else {
module->SetLHS(parse(table["source"]));
module->SetRHS(table.get_or<f32>("scalar", 1));
}
return module;
}
}
/**
* Selects the maximum between two sources, or a source and a scalar.
* The two can also be smoothed between.
*
* @param sources - Two sources to choose the maximum of. Supply this or `source` and `scalar`.
* @param source - A single source, if supplied, also specify `scalar`.
* @param scalar - A scalar value as the maximum.
* @param smoothness - The smoothness of the transition, defaults to 0.
*/
if (type == "max") {
let smoothness = table.get_or("smoothness", 0);
if (smoothness > 0) {
let module = New<MaxSmooth>();
let sources = table["sources"];
module->SetSmoothness(smoothness);
if (sources.valid()) {
module->SetLHS(parse(sources[1]));
module->SetRHS(parse(sources[2]));
}
else {
module->SetLHS(parse(table["source"]));
module->SetRHS(table.get_or<f32>("scalar", 1));
}
return module;
}
else {
let module = New<Max>();
let sources = table["sources"];
if (sources.valid()) {
module->SetLHS(parse(sources[1]));
module->SetRHS(parse(sources[2]));
}
else {
module->SetLHS(parse(table["source"]));
module->SetRHS(table.get_or<f32>("scalar", 1));
}
return module;
}
}
/**
* Clamps the source between two scalar values. Can also be smoothed.
*
* @param source - The source to clamp.
* @param min - The minimum value, defaults to 0.
* @param max - The maximum value, defaults to 1.
* @param smoothness - The smoothness of the transition, defaults to 0.
*/
if (type == "max") {
let source = parse(table["source"]);
let smoothness = table.get_or<f32>("smoothness", 0);
if (smoothness > 0) {
let minModule = New<MinSmooth>();
minModule->SetLHS(source);
minModule->SetRHS(table.get_or<f32>("min", 0));
minModule->SetSmoothness(smoothness);
let maxModule = New<MaxSmooth>();
maxModule->SetLHS(minModule);
maxModule->SetRHS(table.get_or<f32>("max", 1));
maxModule->SetSmoothness(smoothness);
return maxModule;
}
else {
let minModule = New<Min>();
minModule->SetLHS(source);
minModule->SetRHS(table.get_or<f32>("min", 0));
let maxModule = New<Max>();
maxModule->SetLHS(minModule);
maxModule->SetRHS(table.get_or<f32>("max", 1));
return maxModule;
}
}
/**
* Generates Simplex Noise.
*
* @param frequency - The frequency of the noise, default 1.
* @param octaves - The amount of octaves the noise will have, default 3.
* @param lacunarity - The lacunarity of the octaves, default 0.5.
* @param seed - The seed **offset** to use, relative to the world seed.
*/
if (type == "simplex") {
SmartNode<> module = New<Simplex>();
let seed = table.get_or<u32>("seed", 0);
let frequency = table.get_or<f32>("frequency", 1);
let octaves = table.get_or<f32>("octaves", 3);
let persistence = table.get_or<f32>("persistence", 0.5);
let lacunarity = table.get_or<f32>("lacunarity", 0.5);
if (frequency != 1) {
let scaleModule = New<DomainScale>();
scaleModule->SetSource(module);
scaleModule->SetScale(frequency);
module = scaleModule;
}
if (octaves > 1) {
let fractalModule = New<FractalFBm>();
fractalModule->SetSource(module);
fractalModule->SetOctaveCount(octaves);
fractalModule->SetLacunarity(lacunarity);
fractalModule->SetGain(persistence);
module = fractalModule;
}
if (seed != 0) {
let seedOffsetModule = New<SeedOffset>();
seedOffsetModule->SetSource(module);
seedOffsetModule->SetOffset(seed);
module = seedOffsetModule;
}
return module;
}
/**
* Scales the domain by axis.
*
* @param source - The source to scale.
* @param x_scale - The scaling to apply to the x axis.
* @param y_scale - The scaling to apply to the y axis.
* @param z_scale - The scaling to apply to the z axis.
*/
if (type == "scale") {
let module = New<DomainAxisScale>();
module->SetSource(parse(table["source"]));
module->SetScale<Dim::X>(table.get_or<f32>("x_scale", 1));
module->SetScale<Dim::Y>(table.get_or<f32>("y_scale", 1));
module->SetScale<Dim::Z>(table.get_or<f32>("z_scale", 1));
return module;
}
throw std::runtime_error("Invalid module name: " + type);
} }

View File

@ -1,35 +1,13 @@
#pragma once #pragma once
#include <vector> #include "util/Types.h"
#include <sol/forward.hpp> #include <sol/forward.hpp>
#include <libnoise/module/add.h> #include <FastNoise/FastNoise.h>
#include <libnoise/module/module.h>
#include <libnoise/module/modulebase.h>
namespace NoiseFromLua { namespace NoiseFromLua {
/** Builds a FastNoise node tree from a Lua table. */
/** FastNoise::SmartNode<> parse(sol::table table);
* Builds a noise module vector from a Lua noise table.
* The top level module will always be the last element in the vector.
*
* @param noise - The lua noise definition to parse.
* @returns a vector containing all of the noise modules built.
*/
std::vector<noise::module::Module*> build(sol::table noise);
/**
* Will initialize Noise::Module instances from a lua noise module definition, and recursively initialize it's
* child modules as well. All modules will be added in reverse-discovered-order to the modules vector reference
* passed in. The top level module will always be the last element in the vector.
*
* @param modules - The vector reference to insert generated noise modules into.
* @param noise - The lua noise definition to parse.
* @returns the noise module that was parsed.
*/
noise::module::Module* parseNoise(std::vector<noise::module::Module*>& modules, sol::table noise);
}; };

View File

@ -66,21 +66,18 @@ namespace RegisterBiome {
if (!biomeTint) throw identifier + "biome definitions require a biome_tint"; if (!biomeTint) throw identifier + "biome definitions require a biome_tint";
// Get noise parameters // Get noise parameters
let constGenerator = FastNoise::New<FastNoise::Constant>();
constGenerator->SetValue(0);
FastNoise::SmartNode<> heightmap = constGenerator, volume = constGenerator;
auto noiseList = biomeTable.get<sol::optional<sol::table>>("noise"); auto noiseList = biomeTable.get<sol::optional<sol::table>>("noise");
std::vector<noise::module::Module*> volumeModules, heightmapModules;
if (noiseList) { if (noiseList) {
if (noiseList->get<sol::optional<sol::table>>("heightmap")) let heightTable = noiseList->get<sol::optional<sol::table>>("heightmap");
NoiseFromLua::parseNoise(heightmapModules, noiseList->get<sol::table>("heightmap")); if (heightTable) heightmap = NoiseFromLua::parse(*heightTable);
else heightmapModules.push_back(new noise::module::Const);
if (noiseList->get<sol::optional<sol::table>>("volume")) let volumeTable = noiseList->get<sol::optional<sol::table>>("volume");
NoiseFromLua::parseNoise(volumeModules, noiseList->get<sol::table>("volume")); if (volumeTable) volume = NoiseFromLua::parse(*volumeTable);
else volumeModules.push_back(new noise::module::Const);
}
else {
volumeModules.push_back(new noise::module::Const);
heightmapModules.push_back(new noise::module::Const);
} }
std::vector<std::shared_ptr<Structure>> schematics {}; std::vector<std::shared_ptr<Structure>> schematics {};
@ -103,8 +100,8 @@ namespace RegisterBiome {
biomeDef->soilBlock = defs.blockFromStr(*bSoil).index; biomeDef->soilBlock = defs.blockFromStr(*bSoil).index;
biomeDef->rockBlock = defs.blockFromStr(*bRock).index; biomeDef->rockBlock = defs.blockFromStr(*bRock).index;
biomeDef->heightmap = heightmapModules; biomeDef->heightmap = heightmap;
biomeDef->volume = volumeModules; biomeDef->volume = volume;
biomeDef->schematics = schematics; biomeDef->schematics = schematics;

View File

@ -17,8 +17,8 @@ class ServerSubgame;
class ServerGenStream { class ServerGenStream {
public: public:
static const usize THREADS = 6; static const usize THREADS = 4;
static const usize THREAD_QUEUE_SIZE = 6; static const usize THREAD_QUEUE_SIZE = 16;
struct FinishedJob { struct FinishedJob {
FinishedJob(u16 dim, ivec3 pos, uptr<MapGen::ChunkMap> created) : FinishedJob(u16 dim, ivec3 pos, uptr<MapGen::ChunkMap> created) :

View File

@ -21,6 +21,21 @@ namespace Space {
const static i16f MAPBLOCK_CHUNK_LENGTH = MAPBLOCK_SIZE; const static i16f MAPBLOCK_CHUNK_LENGTH = MAPBLOCK_SIZE;
const static i16f REGION_CHUNK_LENGTH = MAPBLOCK_CHUNK_LENGTH * REGION_SIZE; const static i16f REGION_CHUNK_LENGTH = MAPBLOCK_CHUNK_LENGTH * REGION_SIZE;
// Get the index of a position vector in a cube.
static inline u32 posToIndex(const ivec3& pos, const u32 size) {
return pos.x + size * (pos.z + size * pos.y);
}
// Return a position vector from an index of a cube.
static inline ivec3 indexToPos(u32 ind, const u32 size) {
ivec3 vec {};
vec.y = ind / pow(size, 2);
ind -= static_cast<u32>(vec.y) * pow(size, 2);
vec.z = ind / size;
vec.x = ind % size;
return vec;
}
// Private helper methods // Private helper methods
namespace { namespace {
inline u16vec3 localFromGlobal(const ivec3& pos, i16 size) { inline u16vec3 localFromGlobal(const ivec3& pos, i16 size) {
@ -86,8 +101,7 @@ namespace Space {
// Get the index of a MapBlock within its Region from its local or world position. // Get the index of a MapBlock within its Region from its local or world position.
static inline u16 index(const ivec3& vec) { static inline u16 index(const ivec3& vec) {
u8vec3 local = MapBlock::relative::toRegion(vec); return Space::posToIndex(MapBlock::relative::toRegion(vec), REGION_SIZE);
return local.x + REGION_SIZE * (local.y + REGION_SIZE * local.z);
} }
} }
@ -123,20 +137,12 @@ namespace Space {
// Get the index of a Chunk within its MapBlock from its local or world position. // Get the index of a Chunk within its MapBlock from its local or world position.
static inline u16 index(const glm::ivec3& vec) { static inline u16 index(const glm::ivec3& vec) {
u8vec3 local = Chunk::relative::toMapBlock(vec); return Space::posToIndex(Chunk::relative::toMapBlock(vec), MAPBLOCK_SIZE);
return local.x + MAPBLOCK_SIZE * (local.z + MAPBLOCK_SIZE * local.y);
} }
// Return a local vector of an chunk within its mapblock. // Return a local vector of an chunk within its mapblock.
static inline ivec3 fromIndex(u16 ind) { static inline ivec3 fromIndex(u16 ind) {
u8vec3 vec {}; return Space::indexToPos(ind, MAPBLOCK_SIZE);
vec.y = ind / (MAPBLOCK_SIZE * MAPBLOCK_SIZE);
ind -= (static_cast<int>(vec.y) * MAPBLOCK_SIZE * MAPBLOCK_SIZE);
vec.z = ind / MAPBLOCK_SIZE;
vec.x = ind % MAPBLOCK_SIZE;
return vec;
} }
} }
@ -177,20 +183,12 @@ namespace Space {
// Get the index of a Block within its Chunk from its local or world position. // Get the index of a Block within its Chunk from its local or world position.
static inline u16 index(const ivec3& vec) { static inline u16 index(const ivec3& vec) {
u8vec3 local = Block::relative::toChunk(vec); return Space::posToIndex(Block::relative::toChunk(vec), CHUNK_SIZE);
return local.x + CHUNK_SIZE * (local.z + CHUNK_SIZE * local.y);
} }
// Return a local vector of an block within its chunk. // Return a local vector of an block within its chunk.
static inline u8vec3 fromIndex(u16 ind) { static inline u8vec3 fromIndex(u16 ind) {
u8vec3 vec {}; return Space::indexToPos(ind, CHUNK_SIZE);
vec.y = ind / (CHUNK_SIZE * CHUNK_SIZE);
ind -= (static_cast<int>(vec.y) * CHUNK_SIZE * CHUNK_SIZE);
vec.z = ind / CHUNK_SIZE;
vec.x = ind % CHUNK_SIZE;
return vec;
} }
} }
} }

View File

@ -16,6 +16,7 @@ using i8 = int8_t;
using i16 = int16_t; using i16 = int16_t;
using i32 = int32_t; using i32 = int32_t;
using i64 = int64_t; using i64 = int64_t;
using isize = intmax_t;
using i8f = int_fast8_t; using i8f = int_fast8_t;
using i16f = int_fast16_t; using i16f = int_fast16_t;

View File

@ -26,6 +26,18 @@ MapGen::MapGen(Subgame& game, World& world, u32 seed, std::unordered_set<string>
} }
generateVoronoi(biomeIndices); generateVoronoi(biomeIndices);
let biomePerlin = FastNoise::New<FastNoise::Simplex>();
let biomeScale = FastNoise::New<FastNoise::DomainScale>();
biomeScale->SetSource(biomePerlin);
biomeScale->SetScale(1/1000.f);
let biomeFractal = FastNoise::New<FastNoise::FractalFBm>();
biomeFractal->SetSource(biomeScale);
biomeFractal->SetOctaveCount(4);
biomeGenerator = biomeFractal;
} }
[[maybe_unused]] uptr<MapGen::ChunkMap> MapGen::generateChunk(u16 dim, ivec3 pos) { [[maybe_unused]] uptr<MapGen::ChunkMap> MapGen::generateChunk(u16 dim, ivec3 pos) {
@ -39,50 +51,29 @@ uptr<MapGen::ChunkMap> MapGen::generateMapBlock(u16 dim, ivec3 pos) {
std::unique_ptr<MapGen::ChunkMap> MapGen::generateArea(u16 dim, ivec3 origin, u16 size) { std::unique_ptr<MapGen::ChunkMap> MapGen::generateArea(u16 dim, ivec3 origin, u16 size) {
Job job(origin, size); Job job(origin, size);
// Build Biome Prop Maps job.temperature.generate({ job.pos.x * 16, 0, job.pos.z * 16 }, biomeGenerator);
job.roughness.generate({ job.pos.x * 16, 0, job.pos.z * 16 }, biomeGenerator);
const auto fill = [&](const noise::module::Module& s) { job.humidity.generate({ job.pos.x * 16, 0, job.pos.z * 16 }, biomeGenerator);
return [&](vec3 pos) {
vec3 worldPos = vec3(job.pos) + pos * static_cast<f32>(job.size); let biomeMap = vec<u16>(pow(job.size * 16 + 1, 2));
return s.GetValue(worldPos.x, 0, worldPos.z); u16vec3 bPos {};
}; for (bPos.x = 0; bPos.x < job.size * 16 + 1; bPos.x++) {
}; for (bPos.z = 0; bPos.z < job.size * 16 + 1; bPos.z++) {
biomeMap[bPos.z * (job.size * 16 + 1 ) + bPos.x] =
job.temperature.populate(fill(props.temperature)); getBiomeAt(job.temperature[bPos], job.humidity[bPos], job.roughness[bPos]);
job.roughness.populate(fill(props.roughness)); }
job.humidity.populate(fill(props.humidity));
// Generate Biome Topmap
vec<u16> biomeMap {};
biomeMap.resize((job.size * 16 + 1) * (job.size * 16 + 1));
for (usize i = 0; i < biomeMap.size(); i++) {
vec3 indPos = { i / (job.size * 16 + 1), 0, i % (job.size * 16 + 1) };
vec3 queryPos = indPos / 16.f / static_cast<f32>(job.size);
biomeMap[i] = getBiomeAt(job.temperature.get(queryPos),
job.humidity.get(queryPos), job.roughness.get(queryPos));
} }
// Generate Heightmap and Volume job.heightmap.fill([&](ivec3 pos) {
return game.getBiomes().biomeFromId(biomeMap[pos.z * (job.size * 16 + 1) + pos.x])
job.heightmap.populate([&](vec3 pos) { .heightmap->GenSingle2D(job.pos.x * 16 + pos.x, job.pos.z * 16 + pos.z, 1337);
ivec3 blockPos = ivec3(pos * 16.f * static_cast<f32>(job.size));
auto& biome = game.getBiomes().biomeFromId(biomeMap.at(blockPos.x * (job.size * 16 + 1) + blockPos.z));
vec3 worldPos = vec3(job.pos) + pos * static_cast<f32>(job.size);
return biome.heightmap[biome.heightmap.size() - 1]->GetValue(worldPos.x, 0, worldPos.z);
}); });
job.volume.populate([&](vec3 pos) { job.volume.fill([&](ivec3 pos) {
ivec3 blockPos = ivec3(pos * 16.f * static_cast<f32>(job.size)); return game.getBiomes().biomeFromId(biomeMap[pos.z * (job.size * 16 + 1) + pos.x])
auto& biome = game.getBiomes().biomeFromId(biomeMap.at(blockPos.x * (job.size * 16 + 1) + blockPos.z)); .volume->GenSingle3D(job.pos.x * 16 + pos.x, job.pos.y * 16 + pos.y, job.pos.z * 16 + pos.z, 1337);
vec3 worldPos = vec3(job.pos) + pos * static_cast<f32>(job.size);
return biome.volume[biome.volume.size() - 1]->GetValue(worldPos.x, worldPos.y, worldPos.z);
}); });
// Generate Chunks
i16vec3 pos {}; i16vec3 pos {};
for (pos.x = 0; pos.x < job.size; pos.x++) { for (pos.x = 0; pos.x < job.size; pos.x++) {
for (pos.z = 0; pos.z < job.size; pos.z++) { for (pos.z = 0; pos.z < job.size; pos.z++) {
@ -104,7 +95,7 @@ std::unique_ptr<MapGen::ChunkMap> MapGen::generateArea(u16 dim, ivec3 origin, u1
} }
} }
propogateSunlightNodes(job); // propogateSunlightNodes(job);
for (let& chunk : *job.chunks) { for (let& chunk : *job.chunks) {
chunk.second->compress(); chunk.second->compress();
@ -138,12 +129,12 @@ u16 MapGen::getBiomeAt(f32 temperature, f32 humidity, f32 roughness) {
uptr<MapGen::ChunkData> MapGen::populateChunkDensity(MapGen::Job& job, ivec3 localPos) { uptr<MapGen::ChunkData> MapGen::populateChunkDensity(MapGen::Job& job, ivec3 localPos) {
auto data = make_unique<ChunkData>(); auto data = make_unique<ChunkData>();
for (u16 i = 0; i < 4096; i++) { for (u16 i = 0; i < 4096; i++) {
ivec3 indPos = Space::Block::fromIndex(i); ivec3 indPos = Space::Block::fromIndex(i);
vec3 queryPos = (vec3(localPos) + vec3(indPos) / 16.f) / static_cast<f32>(job.size); let ind3d = localPos * 16 + indPos;
(*data)[i] = (job.volume.get(queryPos) + job.heightmap.get({ queryPos.x, 0, queryPos.z })) let ind2d = (localPos.z * 16 + indPos.z) * (job.size * 16) + (localPos.x * 16 + indPos.x);
- ((job.pos.y + localPos.y) * 16 + indPos.y); (*data)[i] = (job.heightmap[ind2d]) + (job.volume[ind3d]) - ((job.pos.y + localPos.y) * 16 + indPos.y);
} }
return data; return data;
@ -191,7 +182,7 @@ void MapGen::generateChunkBlocks(Job& job, ivec3 localPos, vec<u16> biomeMap, Ch
for (u16 i = 0; i < 4096; i++) { for (u16 i = 0; i < 4096; i++) {
ivec3 indPos = Space::Block::fromIndex(i); ivec3 indPos = Space::Block::fromIndex(i);
u16 biomeId = biomeMap[(localPos.x * 16 + indPos.x) * (job.size * 16 + 1) + (localPos.z * 16 + indPos.z)]; u16 biomeId = biomeMap[(localPos.z * 16 + indPos.z) * (job.size * 16 + 1) + (localPos.x * 16 + indPos.x)];
auto& biome = game.getBiomes().biomeFromId(biomeId); auto& biome = game.getBiomes().biomeFromId(biomeId);
chunk.d->biomes[i] = biomeId; chunk.d->biomes[i] = biomeId;
@ -225,11 +216,10 @@ void MapGen::generateChunkDecorAndLight(Job& job, ivec3 localPos, vec<u16> biome
job.chunks->count(abovePos) ? job.chunks->at(abovePos) : nullptr : nullptr; job.chunks->count(abovePos) ? job.chunks->at(abovePos) : nullptr : nullptr;
for (u16 i = 0; i < 256; i++) { for (u16 i = 0; i < 256; i++) {
ivec3 indPos = { i / 16, 15, i % 16 }; ivec3 indPos { i / 16, 15, i % 16 };
u16 biomeID = biomeMap[(localPos.x * 16 + indPos.x) u16 biomeId = biomeMap[(localPos.z * 16 + indPos.z) * (job.size * 16 + 1) + (localPos.x * 16 + indPos.x)];
* (job.size * 16 + 1) + (localPos.z * 16 + indPos.z)]; auto& biome = game.getBiomes().biomeFromId(biomeId);
auto& biome = game.getBiomes().biomeFromId(biomeID);
i16 schemID = -1; i16 schemID = -1;
for (u16 j = 0; j < biome.schematics.size(); j++) { for (u16 j = 0; j < biome.schematics.size(); j++) {

View File

@ -21,10 +21,10 @@ class DefinitionAtlas;
class MapGen { class MapGen {
public: public:
/** The precision of the Biome map, as a divisor of the chunk size. */ /** The precision of the Biome map, as a divisor of the chunk size. */
constexpr static u8 BIOP = 4; // constexpr static u8 BIOP = 4;
/** The precision of the Terrain maps, as a divisor of the chunk size. */ /** The precision of the Terrain maps, as a divisor of the chunk size. */
constexpr static u8 TERP = 4; // constexpr static u8 TERP = 4;
/** A type alias for the type the map of Chunks stored in the Job. */ /** A type alias for the type the map of Chunks stored in the Job. */
typedef std::unordered_map<ivec3, sptr<Chunk>, Vec::ivec3> ChunkMap; typedef std::unordered_map<ivec3, sptr<Chunk>, Vec::ivec3> ChunkMap;
@ -55,16 +55,20 @@ public:
Job(ivec3 pos, u16 size) : Job(ivec3 pos, u16 size) :
pos(pos), size(size), pos(pos), size(size),
volume {{ size * TERP, (size + 1) * TERP }, { 1, 1.25 }}, heightmap {{ size * TERP, 0 }}, volume(u16vec3(size * 16), 4),
temperature {{ size * BIOP, 0 }}, roughness {{ size * BIOP, 0 }}, humidity {{ size * BIOP, 0 }} {} heightmap(u16vec2(size * 16), 4),
temperature(u16vec2(size * 16), 4),
humidity(u16vec2(size * 16), 4),
roughness(u16vec2(size * 16), 4) {}
ivec3 pos {}; ivec3 pos {};
u16 size {}; u16 size {};
uptr<ChunkMap> chunks = make_unique<ChunkMap>(); uptr<ChunkMap> chunks = make_unique<ChunkMap>();
std::queue<SunlightNode> sunlightQueue {}; std::queue<SunlightNode> sunlightQueue {};
NoiseSample volume, heightmap; NoiseSample heightmap, volume;
NoiseSample temperature, humidity, roughness; NoiseSample temperature, humidity, roughness;
}; };
@ -218,6 +222,8 @@ private:
constexpr const static u16 voronoiSize = 64; constexpr const static u16 voronoiSize = 64;
Voronoi3D voronoi { voronoiSize }; Voronoi3D voronoi { voronoiSize };
FastNoise::SmartNode<> biomeGenerator;
Subgame& game; Subgame& game;
World& world; World& world;

View File

@ -1,21 +1,57 @@
#include <iostream>
#include <util/Util.h>
#include "NoiseSample.h" #include "NoiseSample.h"
NoiseSample::NoiseSample(u16 precision, f32 scaleBy) :
NoiseSample({ precision, precision }, { scaleBy, scaleBy }) {}
NoiseSample::NoiseSample(u16vec2 precision, glm::vec2 scaleBy) : NoiseSample::NoiseSample(u16vec2 size, u16 precision) : NoiseSample({ size.x, 0, size.y }, precision) {}
precision(precision.x, precision.y, precision.x),
scaleBy(scaleBy.x, scaleBy.y, scaleBy.x) { NoiseSample::NoiseSample(u16vec3 size, u16 precision):
data.resize((this->precision.x + 1) * (this->precision.y + 1) * (this->precision.z + 1)); size(size), precision(precision), data((size.x + 1) * (size.y + 1) * (size.z + 1), 0) {
if (size.x % precision != 0 || (size.y != 0 && size.y % precision) != 0 || size.z % precision != 0)
throw std::runtime_error("NoiseSample precision must be a divisor of size." +
Util::toString(size) + " : " + Util::toString(precision));
} }
void NoiseSample::populate(const NoiseSample::fill_function& fn) { void NoiseSample::generate(ivec3 pos, const FastNoise::SmartNode<>& generator) {
vec3 pos {}, precisionFloat = vec3(precision); for (u16 x = 0; x < size.x + 1; x += precision)
for (pos.x = 0; pos.x <= precisionFloat.x; pos.x++) for (u16 y = 0; y < size.y + 1; y += precision)
for (pos.y = 0; pos.y <= precisionFloat.y; pos.y++) for (u16 z = 0; z < size.z + 1; z += precision)
for (pos.z = 0; pos.z <= precisionFloat.z; pos.z++) { data[index(x, y, z)] = generator->GenSingle3D(
vec3 queryPos = pos / precisionFloat * scaleBy; pos.x + x, pos.y + y, pos.z + z, 1337);
if (queryPos.y == NAN) queryPos.y = 0;
data[index(pos.x, pos.y, pos.z)] = fn(queryPos); interpolateData();
}
void NoiseSample::fill(const NoiseSample::fill_function& fill) {
u16vec3 pos {};
for (pos.x = 0; pos.x < size.x + 1; pos.x += precision)
for (pos.y = 0; pos.y < size.y + 1; pos.y += precision)
for (pos.z = 0; pos.z < size.z + 1; pos.z += precision)
data[index(pos)] = fill(pos);
interpolateData();
}
void NoiseSample::interpolateData() {
u16vec3 pos = {};
for (pos.x = 0; pos.x < size.x + 1; pos.x += 1) {
for (pos.y = 0; pos.y < size.y + 1; pos.y += 1) {
for (pos.z = 0; pos.z < size.z + 1; pos.z += 1) {
if (pos.x % precision == 0 && pos.y % precision == 0 && pos.z % precision == 0) continue;
vec3 frac = vec3(pos) / static_cast<f32>(precision);
u16vec3 a = u16vec3(glm::floor(frac)) * static_cast<u16>(precision);
u16vec3 b = u16vec3(glm::ceil(frac)) * static_cast<u16>(precision);
vec3 factor = frac - glm::floor(frac);
data[index(pos)] = Interp::trilerp(
data[index(a.x, a.y, a.z)], data[index(b.x, a.y, a.z)],
data[index(a.x, a.y, b.z)], data[index(b.x, a.y, b.z)],
data[index(a.x, b.y, a.z)], data[index(b.x, b.y, a.z)],
data[index(a.x, b.y, b.z)], data[index(b.x, b.y, b.z)],
factor.x, factor.z, factor.y);
} }
} }
}
}

View File

@ -1,54 +1,87 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include <FastNoise/FastNoise.h>
#include "util/Types.h" #include "util/Types.h"
#include "util/Interp.h" #include "util/Interp.h"
class NoiseSample { class NoiseSample {
public: public:
typedef std::function<f32(vec3 pos)> fill_function; typedef std::function<f32(ivec3 pos)> fill_function;
NoiseSample(u16 precision, f32 scaleBy = 1); NoiseSample(u16vec2 size, u16 precision);
NoiseSample(u16vec3 size, u16 precision);
NoiseSample(u16vec2 precision, vec2 scaleBy = vec2(1)); void generate(ivec3 pos, const FastNoise::SmartNode<>& generator);
void populate(const fill_function& fn); void fill(const fill_function& fill);
inline f32 get(vec3 pos) { inline f32 operator[](u16vec3 pos) {
vec3 scaled = pos * vec3(precision) / scaleBy; return data[index(pos)];
ivec3 a = { scaled.x, scaled.y, scaled.z };
vec3 factor = { scaled.x - a.x, scaled.y - a.y, scaled.z - a.z };
ivec3 b = {
(std::min)(static_cast<i32>(std::ceil(scaled.x)), precision.x),
(std::min)(static_cast<i32>(std::ceil(scaled.y)), precision.y),
(std::min)(static_cast<i32>(std::ceil(scaled.z)), precision.z) };
assert(index(b.x, b.y, b.z) < data.size());
// No vertical interpolation
if (precision.y == 0)
return Interp::bilerp(
data[index(a.x, a.y, a.z)], data[index(b.x, a.y, a.z)],
data[index(a.x, a.y, b.z)], data[index(b.x, a.y, b.z)],
factor.x, factor.z);
return Interp::trilerp(
data[index(a.x, a.y, a.z)], data[index(b.x, a.y, a.z)],
data[index(a.x, a.y, b.z)], data[index(b.x, a.y, b.z)],
data[index(a.x, b.y, a.z)], data[index(b.x, b.y, a.z)],
data[index(a.x, b.y, b.z)], data[index(b.x, b.y, b.z)],
factor.x, factor.z, factor.y);
} }
inline f32 operator[](u32 ind) {
return data[shiftIndexByOne(ind)];
}
// inline f32 get(vec3 pos) {
// vec3 scaled = pos * vec3(precision) / scaleBy;
//
// ivec3 a = { scaled.x, scaled.y, scaled.z };
// vec3 factor = { scaled.x - a.x, scaled.y - a.y, scaled.z - a.z };
// ivec3 b = {
// (std::min)(static_cast<i32>(std::ceil(scaled.x)), precision.x),
// (std::min)(static_cast<i32>(std::ceil(scaled.y)), precision.y),
// (std::min)(static_cast<i32>(std::ceil(scaled.z)), precision.z) };
//
// assert(index(b.x, b.y, b.z) < data.size());
//
// // No vertical interpolation
// if (precision.y == 0)
// return Interp::bilerp(
// data[index(a.x, a.y, a.z)], data[index(b.x, a.y, a.z)],
// data[index(a.x, a.y, b.z)], data[index(b.x, a.y, b.z)],
// factor.x, factor.z);
//
// return Interp::trilerp(
// data[index(a.x, a.y, a.z)], data[index(b.x, a.y, a.z)],
// data[index(a.x, a.y, b.z)], data[index(b.x, a.y, b.z)],
// data[index(a.x, b.y, a.z)], data[index(b.x, b.y, a.z)],
// data[index(a.x, b.y, b.z)], data[index(b.x, b.y, b.z)],
// factor.x, factor.z, factor.y);
// }
private: private:
inline u16 index(u16 x, u16 y, u16 z) { void interpolateData();
return x * (precision.x + 1) * (precision.y + 1) + y * (precision.x + 1) + z;
// inline u32 innerIndex(u16 x, u16 y, u16 z) {
// return static_cast<u32>(x) * size.x * size.y + y * size.x + z;
// };
inline u32 index(u16vec3 pos) {
return index(pos.x, pos.y, pos.z);
}; };
std::vector<f32> data {}; inline u32 index(u16 x, u16 y, u16 z) {
ivec3 precision {}; return static_cast<u32>(x) * (size.x + 1) * (size.y + 1) + y * (size.x + 1) + z;
vec3 scaleBy; };
inline u32 shiftIndexByOne(u32 ind) {
u16vec3 vec = {};
let divY = size.y == 0 ? 1 : size.y;
vec.z = ind / (size.x * divY);
ind -= (vec.z * size.x * divY);
vec.y = ind / size.x;
vec.x = ind % size.x;
return index(vec);
};
u16vec3 size;
u16 precision;
vec<f32> data {};
}; };

View File

@ -8,7 +8,6 @@
#include "world/LocalWorld.h" #include "world/LocalWorld.h"
#include "game/def/BlockDef.h" #include "game/def/BlockDef.h"
#include "util/net/NetField.h" #include "util/net/NetField.h"
#include "lua/usertype/Player.h"
#include "lua/usertype/Target.h" #include "lua/usertype/Target.h"
#include "client/graph/Renderer.h" #include "client/graph/Renderer.h"
#include "world/dim/chunk/Chunk.h" #include "world/dim/chunk/Chunk.h"

View File

@ -9,8 +9,8 @@ local menu = zepha.build_gui(function()
Gui.Rect { Gui.Rect {
key = "inventory", key = "inventory",
position = { pc(50), pc(50) }, position = { pc(50), pc(50) },
position_anchor = { pc(50), pc(55) }, position_anchor = { pc(50), pc(50) },
size = { 237, 187 }, size = { 342, 187 },
Gui.Rect { Gui.Rect {
key = "backpack", key = "backpack",
@ -63,10 +63,26 @@ local menu = zepha.build_gui(function()
list = "hot_wheel_6", list = "hot_wheel_6",
} }
}, },
Gui.Rect {
key = "player_frame",
position = { 105, 0 },
size = { 106, 187 },
background = "zeus:inventory:player_frame",
Gui.Model {
position = { 52, 150 },
scale = { 64, 64 },
type = "model",
source = "zeus:default:player",
texture = "zeus:default:player",
anim_range = { 0, 100 }
}
},
Gui.Rect { Gui.Rect {
key = "equipment", key = "equipment",
position = { 106, 1 }, position = { 209, 1 },
size = { 132, 80 }, size = { 132, 80 },
padding = { 18, 8, 8, 8 }, padding = { 18, 8, 8, 8 },
background = "zeus:inventory:equipment", background = "zeus:inventory:equipment",
@ -76,23 +92,13 @@ local menu = zepha.build_gui(function()
position = { 41, 1 }, position = { 41, 1 },
size = { 34, 52 }, size = { 34, 52 },
overflow = "hidden", overflow = "hidden"
Gui.Model {
position = { 15, 52 },
scale = { 28, 28 },
type = "model",
source = "zeus:default:player",
texture = "zeus:default:player",
anim_range = { 0, 100 }
}
} }
}, },
Gui.Rect { Gui.Rect {
key = "dynamic", key = "dynamic",
position = { 106, 80 }, position = { 209, 80 },
size = { 132, 107 }, size = { 132, 107 },
padding = { 8, 8, 8, 8 }, padding = { 8, 8, 8, 8 },
background = "zeus:inventory:dynamic", background = "zeus:inventory:dynamic",

View File

@ -65,15 +65,20 @@ local noise = {
-- }} -- }}
-- } -- }
volume = { volume = {
module = "scale_bias", module = "scale",
scale = 3000, y_scale = 2,
bias = -3500,
source = { source = {
module = "scale_point", module = "add",
y_scale = 2, scalar = -2200,
source = { source = {
module = "perlin", module = "multiply",
frequency = 0.1 scalar = 3000,
source = {
module = "simplex",
frequency = 0.0025,
octaves = 6,
lacunarity = 2
}
} }
} }
} }

View File

@ -1,178 +1,178 @@
local identifier = "zeus:world:forest" -- local identifier = "zeus:world:forest"
--
local wood = "zeus:default:wood" -- local wood = "zeus:default:wood"
local leaf = "zeus:default:leaves" -- local leaf = "zeus:default:leaves"
local none = "invalid" -- local none = "invalid"
--
local structures = {} -- local structures = {}
-- --
-- -- table.insert(structures, zepha.create_structure({
-- -- -- noise = {
-- -- -- module = "perlin",
-- -- -- frequency = 0.002,
-- -- -- octaves = 8
-- -- -- },
-- -- -- region_size = 4,
-- -- probability = 0.1,
-- -- -- origin = V{1, 1, 1},
-- -- origin = V(),
-- -- layout = {{{ "zeus:flowers:flower_geranium" }}}
-- -- }))
--
-- for i = 1, 5 do
-- table.insert(structures, zepha.create_structure({
-- origin = V(),
-- probability = 0.025,
-- layout = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
-- }))
-- end
-- --
-- table.insert(structures, zepha.create_structure({
-- origin = V(),
-- probability = 0.05,
-- layout = {{{ "zeus:flowers:flower_red_mushroom" }}}
-- }))
-- --
-- table.insert(structures, zepha.create_structure({ -- table.insert(structures, zepha.create_structure({
-- -- noise = { -- origin = V(),
-- -- module = "perlin", -- probability = 0.05,
-- -- frequency = 0.002, -- layout = {{{ "zeus:flowers:flower_brown_mushroom" }}}
-- -- octaves = 8
-- -- },
-- -- region_size = 4,
-- probability = 0.1,
-- -- origin = V{1, 1, 1},
-- origin = V(),
-- layout = {{{ "zeus:flowers:flower_geranium" }}}
-- })) -- }))
for i = 1, 5 do
table.insert(structures, zepha.create_structure({
origin = V(),
probability = 0.025,
layout = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
}))
end
-- --
table.insert(structures, zepha.create_structure({ -- table.insert(structures, zepha.create_structure({
origin = V(), -- origin = V(1),
probability = 0.05, -- probability = 0.1,
layout = {{{ "zeus:flowers:flower_red_mushroom" }}} -- layout = {{
})) -- { none, none, none },
-- { none, wood, none },
table.insert(structures, zepha.create_structure({ -- { none, none, none }
origin = V(), -- }, {
probability = 0.05, -- { none, leaf, none },
layout = {{{ "zeus:flowers:flower_brown_mushroom" }}} -- { leaf, wood, leaf },
})) -- { none, leaf, none }
-- }, {
table.insert(structures, zepha.create_structure({ -- { none, none, none },
origin = V(1), -- { none, leaf, none },
probability = 0.1, -- { none, none, none }
layout = {{ -- }}
{ none, none, none }, -- }))
{ none, wood, none }, --
{ none, none, none } -- local woo = "zeus:default:wood"
}, { -- local lea = "zeus:default:leaves"
{ none, leaf, none }, -- local inv = "invalid"
{ leaf, wood, leaf }, --
{ none, leaf, none } -- local trunk_layer_0 = {
}, { -- { inv, inv, inv, inv, inv },
{ none, none, none }, -- { inv, woo, woo, woo, inv },
{ none, leaf, none }, -- { inv, woo, woo, woo, inv },
{ none, none, none } -- { inv, woo, woo, woo, inv },
}} -- { inv, inv, inv, inv, inv }
})) -- }
--
local woo = "zeus:default:wood" -- local trunk_layer_1 = {
local lea = "zeus:default:leaves" -- { inv, inv, inv, inv, inv },
local inv = "invalid" -- { inv, inv, woo, inv, inv },
-- { inv, woo, woo, woo, inv },
local trunk_layer_0 = { -- { inv, inv, woo, inv, inv },
{ inv, inv, inv, inv, inv }, -- { inv, inv, inv, inv, inv }
{ inv, woo, woo, woo, inv }, -- }
{ inv, woo, woo, woo, inv }, --
{ inv, woo, woo, woo, inv }, -- local trunk_layer_2 = {
{ inv, inv, inv, inv, inv } -- { inv, inv, inv, inv, inv },
} -- { inv, inv, inv, inv, inv },
-- { inv, inv, woo, inv, inv },
local trunk_layer_1 = { -- { inv, inv, inv, inv, inv },
{ inv, inv, inv, inv, inv }, -- { inv, inv, inv, inv, inv }
{ inv, inv, woo, inv, inv }, -- }
{ inv, woo, woo, woo, inv }, --
{ inv, inv, woo, inv, inv }, -- local leaf_layer_1 = {
{ inv, inv, inv, inv, inv } -- { inv, lea, lea, lea, inv },
} -- { lea, lea, lea, lea, lea },
-- { lea, lea, woo, lea, lea },
local trunk_layer_2 = { -- { lea, lea, lea, lea, lea },
{ inv, inv, inv, inv, inv }, -- { inv, lea, lea, lea, inv }
{ inv, inv, inv, inv, inv }, -- }
{ inv, inv, woo, inv, inv }, --
{ inv, inv, inv, inv, inv }, -- local leaf_layer_2 = {
{ inv, inv, inv, inv, inv } -- { inv, inv, inv, inv, inv },
} -- { inv, lea, lea, lea, inv },
-- { inv, lea, woo, lea, inv },
local leaf_layer_1 = { -- { inv, lea, lea, lea, inv },
{ inv, lea, lea, lea, inv }, -- { inv, inv, inv, inv, inv }
{ lea, lea, lea, lea, lea }, -- }
{ lea, lea, woo, lea, lea }, --
{ lea, lea, lea, lea, lea }, -- local leaf_layer_3 = {
{ inv, lea, lea, lea, inv } -- { inv, inv, inv, inv, inv },
} -- { inv, lea, lea, inv, inv },
-- { inv, lea, lea, lea, inv },
local leaf_layer_2 = { -- { inv, inv, lea, lea, inv },
{ inv, inv, inv, inv, inv }, -- { inv, inv, inv, inv, inv }
{ inv, lea, lea, lea, inv }, -- }
{ inv, lea, woo, lea, inv }, --
{ inv, lea, lea, lea, inv }, -- table.insert(structures, zepha.create_structure({
{ inv, inv, inv, inv, inv } -- origin = V(2, 2, 2),
} -- probability = 0.05,
-- layout = {
local leaf_layer_3 = { -- trunk_layer_0,
{ inv, inv, inv, inv, inv }, -- trunk_layer_0,
{ inv, lea, lea, inv, inv }, -- trunk_layer_0,
{ inv, lea, lea, lea, inv }, -- trunk_layer_0,
{ inv, inv, lea, lea, inv }, -- trunk_layer_1,
{ inv, inv, inv, inv, inv } -- trunk_layer_1,
} -- trunk_layer_1,
-- trunk_layer_2,
table.insert(structures, zepha.create_structure({ -- trunk_layer_2,
origin = V(2, 2, 2), -- trunk_layer_2,
probability = 0.05, -- trunk_layer_2,
layout = { -- trunk_layer_2,
trunk_layer_0, -- trunk_layer_2,
trunk_layer_0, -- trunk_layer_2,
trunk_layer_0, -- trunk_layer_2,
trunk_layer_0, -- trunk_layer_2,
trunk_layer_1, -- trunk_layer_2,
trunk_layer_1, -- trunk_layer_2,
trunk_layer_1, -- leaf_layer_2,
trunk_layer_2, -- leaf_layer_1,
trunk_layer_2, -- leaf_layer_1,
trunk_layer_2, -- leaf_layer_1,
trunk_layer_2, -- leaf_layer_1,
trunk_layer_2, -- leaf_layer_2,
trunk_layer_2, -- leaf_layer_3
trunk_layer_2, -- }
trunk_layer_2, -- }))
trunk_layer_2, --
trunk_layer_2, -- local noise = {
trunk_layer_2, -- -- heightmap = runfile(_PATH .. 'world_noise'),
leaf_layer_2, -- volume = {
leaf_layer_1, -- module = "scale_bias",
leaf_layer_1, -- scale = 3000,
leaf_layer_1, -- bias = -3500,
leaf_layer_1, -- source = {
leaf_layer_2, -- module = "scale_point",
leaf_layer_3 -- y_scale = 2,
} -- source = {
})) -- module = "perlin",
-- frequency = 0.1
local noise = { -- }
-- heightmap = runfile(_PATH .. 'world_noise'), -- }
volume = { -- }
module = "scale_bias", -- }
scale = 3000, --
bias = -3500, -- zepha.register_biome(identifier, {
source = { -- environment = {
module = "scale_point", -- temperature = 25/100,
y_scale = 2, -- humidity = 70/100,
source = { -- roughness = 20/100,
module = "perlin", -- },
frequency = 0.1 -- blocks = {
} -- top = "zeus:default:grass",
} -- soil = "zeus:default:dirt",
} -- rock = "zeus:default:stone"
} -- },
-- tags = { natural = 1, default = 1 },
zepha.register_biome(identifier, { -- structures = structures,
environment = { -- biome_tint = "#aaed45",
temperature = 25/100, -- noise = noise
humidity = 70/100, -- })
roughness = 20/100, --
}, -- return identifier
blocks = {
top = "zeus:default:grass",
soil = "zeus:default:dirt",
rock = "zeus:default:stone"
},
tags = { natural = 1, default = 1 },
structures = structures,
biome_tint = "#aaed45",
noise = noise
})
return identifier

View File

@ -144,15 +144,20 @@ table.insert(structures, zepha.create_structure({
local noise = { local noise = {
-- heightmap = runfile(_PATH .. 'world_noise'), -- heightmap = runfile(_PATH .. 'world_noise'),
volume = { volume = {
module = "scale_bias", module = "scale",
scale = 3000, y_scale = 2,
bias = -3500,
source = { source = {
module = "scale_point", module = "add",
y_scale = 2, scalar = -2200,
source = { source = {
module = "perlin", module = "multiply",
frequency = 0.1 scalar = 3000,
source = {
module = "simplex",
frequency = 0.0025,
octaves = 6,
lacunarity = 2
}
} }
} }
} }

View File

@ -1,6 +1,6 @@
return { return {
runfile(_PATH.."biomes/plains"), runfile(_PATH .. "biomes/plains"),
runfile(_PATH.."biomes/highlands"), runfile(_PATH .. "biomes/highlands"),
runfile(_PATH.."biomes/desert"), runfile(_PATH .. "biomes/desert"),
runfile(_PATH.."biomes/forest") runfile(_PATH .. "biomes/forest")
} }