Merge pull request #334 from MihailRis/upgrade-generator
Upgrade generator
This commit is contained in:
commit
493477c27b
@ -351,7 +351,15 @@ generation.save_fragment(
|
|||||||
|
|
||||||
The fragment size is available as the `size` property.
|
The fragment size is available as the `size` property.
|
||||||
|
|
||||||
A fragment can be cropped to fit its contents (air is ignored) by calling the `fragment:crop()` method.
|
### Methods
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- Crop a fragment to content
|
||||||
|
fragment:crop()
|
||||||
|
|
||||||
|
-- Set a fragment to the world at the specified position
|
||||||
|
fragment:place(position: vec3, [optional] rotation:int=0)
|
||||||
|
```
|
||||||
|
|
||||||
## Generating a height map
|
## Generating a height map
|
||||||
|
|
||||||
|
|||||||
@ -355,7 +355,15 @@ generation.save_fragment(
|
|||||||
|
|
||||||
Размер фрагмента доступен как свойство `size`.
|
Размер фрагмента доступен как свойство `size`.
|
||||||
|
|
||||||
Фрагмент может быть обрезан до размеров содержимого (воздух игнорируется) вызовом метода `fragment:crop()`.
|
### Методы
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- Обрезает фрагмент до размеров содержимого
|
||||||
|
fragment:crop()
|
||||||
|
|
||||||
|
-- Устанавливает фрагмент в мир на указанной позиции
|
||||||
|
fragment:place(position: vec3, [опционально] rotation:int=0)
|
||||||
|
```
|
||||||
|
|
||||||
## Генерация карты высот
|
## Генерация карты высот
|
||||||
|
|
||||||
|
|||||||
@ -187,3 +187,17 @@ console.add_command(
|
|||||||
" has been saved as "..file.resolve(filename))
|
" has been saved as "..file.resolve(filename))
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
|
console.add_command(
|
||||||
|
"fragment.place file:str x:num~pos.x y:num~pos.y z:num~pos.z rotation:int=0",
|
||||||
|
"Place fragment to the world",
|
||||||
|
function(args, kwargs)
|
||||||
|
local filename = args[1]
|
||||||
|
local x = args[2]
|
||||||
|
local y = args[3]
|
||||||
|
local z = args[4]
|
||||||
|
local rotation = args[5]
|
||||||
|
local fragment = generation.load_fragment(filename)
|
||||||
|
fragment:place({x, y, z}, rotation)
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|||||||
@ -202,6 +202,16 @@ void ContentLoader::loadGenerator(
|
|||||||
map.at("biome-parameters").get(def.biomeParameters);
|
map.at("biome-parameters").get(def.biomeParameters);
|
||||||
map.at("biome-bpd").get(def.biomesBPD);
|
map.at("biome-bpd").get(def.biomesBPD);
|
||||||
map.at("heights-bpd").get(def.heightsBPD);
|
map.at("heights-bpd").get(def.heightsBPD);
|
||||||
|
std::string interpName;
|
||||||
|
map.at("heights-interpolation").get(interpName);
|
||||||
|
if (auto interp = InterpolationType_from(interpName)) {
|
||||||
|
def.heightsInterpolation = *interp;
|
||||||
|
}
|
||||||
|
map.at("biomes-interpolation").get(interpName);
|
||||||
|
if (auto interp = InterpolationType_from(interpName)) {
|
||||||
|
def.biomesInterpolation = *interp;
|
||||||
|
}
|
||||||
|
|
||||||
map.at("sea-level").get(def.seaLevel);
|
map.at("sea-level").get(def.seaLevel);
|
||||||
map.at("wide-structs-chunks-radius").get(def.wideStructsChunksRadius);
|
map.at("wide-structs-chunks-radius").get(def.wideStructsChunksRadius);
|
||||||
if (map.has("heightmap-inputs")) {
|
if (map.has("heightmap-inputs")) {
|
||||||
|
|||||||
@ -45,6 +45,7 @@ static int l_load_fragment(lua::State* L) {
|
|||||||
|
|
||||||
auto fragment = std::make_shared<VoxelFragment>();
|
auto fragment = std::make_shared<VoxelFragment>();
|
||||||
fragment->deserialize(map);
|
fragment->deserialize(map);
|
||||||
|
fragment->prepare(*content);
|
||||||
return lua::newuserdata<lua::LuaVoxelFragment>(L, std::move(fragment));
|
return lua::newuserdata<lua::LuaVoxelFragment>(L, std::move(fragment));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "world/generator/VoxelFragment.hpp"
|
#include "world/generator/VoxelFragment.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
|
#include "world/Level.hpp"
|
||||||
|
|
||||||
using namespace lua;
|
using namespace lua;
|
||||||
|
|
||||||
@ -20,8 +21,20 @@ static int l_crop(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_place(lua::State* L) {
|
||||||
|
if (auto fragment = touserdata<LuaVoxelFragment>(L, 1)) {
|
||||||
|
auto offset = tovec3(L, 2);
|
||||||
|
int rotation = tointeger(L, 3) & 0b11;
|
||||||
|
fragment->getFragment()->place(
|
||||||
|
*scripting::level->chunks, offset, rotation
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static std::unordered_map<std::string, lua_CFunction> methods {
|
static std::unordered_map<std::string, lua_CFunction> methods {
|
||||||
{"crop", lua::wrap<l_crop>},
|
{"crop", lua::wrap<l_crop>},
|
||||||
|
{"place", lua::wrap<l_place>},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int l_meta_tostring(lua::State* L) {
|
static int l_meta_tostring(lua::State* L) {
|
||||||
|
|||||||
@ -5,6 +5,17 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
std::optional<InterpolationType> InterpolationType_from(std::string_view str) {
|
||||||
|
if (str == "nearest") {
|
||||||
|
return InterpolationType::NEAREST;
|
||||||
|
} else if (str == "linear") {
|
||||||
|
return InterpolationType::LINEAR;
|
||||||
|
} else if (str == "cubic") {
|
||||||
|
return InterpolationType::CUBIC;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
static inline float sample_at(
|
static inline float sample_at(
|
||||||
const float* buffer,
|
const float* buffer,
|
||||||
uint width,
|
uint width,
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "typedefs.hpp"
|
#include "typedefs.hpp"
|
||||||
#include "maths/Heightmap.hpp"
|
#include "maths/Heightmap.hpp"
|
||||||
@ -12,6 +13,8 @@ enum class InterpolationType {
|
|||||||
CUBIC,
|
CUBIC,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::optional<InterpolationType> InterpolationType_from(std::string_view str);
|
||||||
|
|
||||||
class Heightmap {
|
class Heightmap {
|
||||||
std::vector<float> buffer;
|
std::vector<float> buffer;
|
||||||
uint width, height;
|
uint width, height;
|
||||||
|
|||||||
@ -209,6 +209,12 @@ struct GeneratorDef {
|
|||||||
/// @brief Heightmap blocks per dot
|
/// @brief Heightmap blocks per dot
|
||||||
uint heightsBPD = 4;
|
uint heightsBPD = 4;
|
||||||
|
|
||||||
|
/// @brief Biome parameter maps interpolation method
|
||||||
|
InterpolationType biomesInterpolation = InterpolationType::LINEAR;
|
||||||
|
|
||||||
|
/// @brief Height maps interpolation method
|
||||||
|
InterpolationType heightsInterpolation = InterpolationType::LINEAR;
|
||||||
|
|
||||||
/// @brief Number of chunks must be generated before and after wide
|
/// @brief Number of chunks must be generated before and after wide
|
||||||
/// structures placement triggered
|
/// structures placement triggered
|
||||||
uint wideStructsChunksRadius = 3;
|
uint wideStructsChunksRadius = 3;
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "data/dv_util.hpp"
|
#include "data/dv_util.hpp"
|
||||||
#include "content/Content.hpp"
|
#include "content/Content.hpp"
|
||||||
|
#include "voxels/Chunks.hpp"
|
||||||
#include "voxels/Block.hpp"
|
#include "voxels/Block.hpp"
|
||||||
#include "voxels/ChunksStorage.hpp"
|
#include "voxels/ChunksStorage.hpp"
|
||||||
#include "voxels/VoxelsVolume.hpp"
|
#include "voxels/VoxelsVolume.hpp"
|
||||||
@ -168,6 +169,29 @@ void VoxelFragment::prepare(const Content& content) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VoxelFragment::place(
|
||||||
|
Chunks& chunks, const glm::ivec3& offset, ubyte rotation
|
||||||
|
) {
|
||||||
|
auto& structVoxels = getRuntimeVoxels();
|
||||||
|
for (int y = 0; y < size.y; y++) {
|
||||||
|
int sy = y + offset.y;
|
||||||
|
if (sy < 0 || sy >= CHUNK_H) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int z = 0; z < size.z; z++) {
|
||||||
|
int sz = z + offset.z;
|
||||||
|
for (int x = 0; x < size.x; x++) {
|
||||||
|
int sx = x + offset.x;
|
||||||
|
const auto& structVoxel =
|
||||||
|
structVoxels[vox_index(x, y, z, size.x, size.z)];
|
||||||
|
if (structVoxel.id) {
|
||||||
|
chunks.set(sx, sy, sz, structVoxel.id, structVoxel.state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<VoxelFragment> VoxelFragment::rotated(const Content& content) const {
|
std::unique_ptr<VoxelFragment> VoxelFragment::rotated(const Content& content) const {
|
||||||
std::vector<voxel> newVoxels(voxels.size());
|
std::vector<voxel> newVoxels(voxels.size());
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ inline constexpr int STRUCTURE_FORMAT_VERSION = 1;
|
|||||||
|
|
||||||
class Level;
|
class Level;
|
||||||
class Content;
|
class Content;
|
||||||
|
class Chunks;
|
||||||
|
|
||||||
class VoxelFragment : public Serializable {
|
class VoxelFragment : public Serializable {
|
||||||
glm::ivec3 size;
|
glm::ivec3 size;
|
||||||
@ -41,6 +42,11 @@ public:
|
|||||||
/// @param content world content
|
/// @param content world content
|
||||||
void prepare(const Content& content);
|
void prepare(const Content& content);
|
||||||
|
|
||||||
|
/// @brief Place fragment to the world
|
||||||
|
/// @param offset target location
|
||||||
|
/// @param rotation rotation index
|
||||||
|
void place(Chunks& chunks, const glm::ivec3& offset, ubyte rotation);
|
||||||
|
|
||||||
/// @brief Create structure copy rotated 90 deg. clockwise
|
/// @brief Create structure copy rotated 90 deg. clockwise
|
||||||
std::unique_ptr<VoxelFragment> rotated(const Content& content) const;
|
std::unique_ptr<VoxelFragment> rotated(const Content& content) const;
|
||||||
|
|
||||||
|
|||||||
@ -307,13 +307,13 @@ void WorldGenerator::generateBiomes(
|
|||||||
copy->resize(
|
copy->resize(
|
||||||
floordiv(CHUNK_W, def.heightsBPD) + 1,
|
floordiv(CHUNK_W, def.heightsBPD) + 1,
|
||||||
floordiv(CHUNK_D, def.heightsBPD) + 1,
|
floordiv(CHUNK_D, def.heightsBPD) + 1,
|
||||||
InterpolationType::LINEAR
|
def.heightsInterpolation
|
||||||
);
|
);
|
||||||
prototype.heightmapInputs.push_back(std::move(copy));
|
prototype.heightmapInputs.push_back(std::move(copy));
|
||||||
}
|
}
|
||||||
for (const auto& map : biomeParams) {
|
for (const auto& map : biomeParams) {
|
||||||
map->resize(
|
map->resize(
|
||||||
CHUNK_W + bpd, CHUNK_D + bpd, InterpolationType::LINEAR
|
CHUNK_W + bpd, CHUNK_D + bpd, def.biomesInterpolation
|
||||||
);
|
);
|
||||||
map->crop(0, 0, CHUNK_W, CHUNK_D);
|
map->crop(0, 0, CHUNK_W, CHUNK_D);
|
||||||
}
|
}
|
||||||
@ -345,7 +345,7 @@ void WorldGenerator::generateHeightmap(
|
|||||||
);
|
);
|
||||||
prototype.heightmap->clamp();
|
prototype.heightmap->clamp();
|
||||||
prototype.heightmap->resize(
|
prototype.heightmap->resize(
|
||||||
CHUNK_W + bpd, CHUNK_D + bpd, InterpolationType::LINEAR
|
CHUNK_W + bpd, CHUNK_D + bpd, def.heightsInterpolation
|
||||||
);
|
);
|
||||||
prototype.heightmap->crop(0, 0, CHUNK_W, CHUNK_D);
|
prototype.heightmap->crop(0, 0, CHUNK_W, CHUNK_D);
|
||||||
prototype.level = ChunkPrototypeLevel::HEIGHTMAP;
|
prototype.level = ChunkPrototypeLevel::HEIGHTMAP;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user