Merge branch 'main' into item-models

This commit is contained in:
MihailRis 2024-10-28 10:18:04 +03:00
commit 962c1afc4a
12 changed files with 141 additions and 8 deletions

View File

@ -299,6 +299,7 @@ Changes the heightmap size.
Available interpolation modes:
- 'nearest' - no interpolation
- 'linear' - bilinear interpolation
- 'cubic' - bicubic interpolation
### heightmap:crop(...)
@ -350,7 +351,15 @@ generation.save_fragment(
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

View File

@ -303,6 +303,7 @@ map:resize(ширина, высота, интерполяция)
Доступные режимы интерполяции:
- 'nearest' - без интерполяции
- 'linear' - билинейная интерполяция
- 'cubic' - бикубическая интерполяция
### heightmap:crop(...)
@ -354,7 +355,15 @@ generation.save_fragment(
Размер фрагмента доступен как свойство `size`.
Фрагмент может быть обрезан до размеров содержимого (воздух игнорируется) вызовом метода `fragment:crop()`.
### Методы
```lua
-- Обрезает фрагмент до размеров содержимого
fragment:crop()
-- Устанавливает фрагмент в мир на указанной позиции
fragment:place(position: vec3, [опционально] rotation:int=0)
```
## Генерация карты высот

View File

@ -187,3 +187,17 @@ console.add_command(
" has been saved as "..file.resolve(filename))
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
)

View File

@ -202,6 +202,16 @@ void ContentLoader::loadGenerator(
map.at("biome-parameters").get(def.biomeParameters);
map.at("biome-bpd").get(def.biomesBPD);
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("wide-structs-chunks-radius").get(def.wideStructsChunksRadius);
if (map.has("heightmap-inputs")) {

View File

@ -45,6 +45,7 @@ static int l_load_fragment(lua::State* L) {
auto fragment = std::make_shared<VoxelFragment>();
fragment->deserialize(map);
fragment->prepare(*content);
return lua::newuserdata<lua::LuaVoxelFragment>(L, std::move(fragment));
}

View File

@ -4,6 +4,7 @@
#include "world/generator/VoxelFragment.hpp"
#include "util/stringutil.hpp"
#include "world/Level.hpp"
using namespace lua;
@ -20,8 +21,20 @@ static int l_crop(lua::State* L) {
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 {
{"crop", lua::wrap<l_crop>},
{"place", lua::wrap<l_place>},
};
static int l_meta_tostring(lua::State* L) {

View File

@ -5,8 +5,15 @@
#include <stdexcept>
#include <glm/glm.hpp>
static inline float smootherstep(float x) {
return glm::smoothstep(std::floor(x), std::floor(x)+1, x);
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(
@ -17,6 +24,27 @@ static inline float sample_at(
return buffer[y*width+x];
}
static inline float sample_at(
const float* buffer,
uint width, uint height,
uint x, uint y
) {
return buffer[(y >= height ? height-1 : y)*width+(x >= width ? width-1 : x)];
}
static inline float interpolate_cubic(float p[4], float x) {
return p[1] + 0.5 * x*(p[2] - p[0] + x*(2.0*p[0] - 5.0*p[1] + 4.0*p[2] -
p[3] + x*(3.0*(p[1] - p[2]) + p[3] - p[0])));
}
static inline float interpolate_bicubic(float p[4][4], float x, float y) {
float q[4];
for (int i = 0; i < 4; i++) {
q[i] = interpolate_cubic(p[i], y);
}
return interpolate_cubic(q, x);
}
static inline float sample_at(
const float* buffer,
uint width, uint height,
@ -50,7 +78,17 @@ static inline float sample_at(
return a00 + a10*tx + a01*ty + a11*tx*ty;
}
// TODO: implement CUBIC (Bicubic) interpolation
case InterpolationType::CUBIC: {
float p[4][4];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
p[i][j] = sample_at(
buffer, width, height, ix + j - 1, iy + i - 1
);
}
}
return interpolate_bicubic(p, ty, tx);
}
default:
throw std::runtime_error("interpolation type is not implemented");
}

View File

@ -2,6 +2,7 @@
#include <vector>
#include <string>
#include <optional>
#include "typedefs.hpp"
#include "maths/Heightmap.hpp"
@ -12,6 +13,8 @@ enum class InterpolationType {
CUBIC,
};
std::optional<InterpolationType> InterpolationType_from(std::string_view str);
class Heightmap {
std::vector<float> buffer;
uint width, height;

View File

@ -209,6 +209,12 @@ struct GeneratorDef {
/// @brief Heightmap blocks per dot
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
/// structures placement triggered
uint wideStructsChunksRadius = 3;

View File

@ -6,6 +6,7 @@
#include "data/dv_util.hpp"
#include "content/Content.hpp"
#include "voxels/Chunks.hpp"
#include "voxels/Block.hpp"
#include "voxels/ChunksStorage.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::vector<voxel> newVoxels(voxels.size());

View File

@ -10,6 +10,7 @@ inline constexpr int STRUCTURE_FORMAT_VERSION = 1;
class Level;
class Content;
class Chunks;
class VoxelFragment : public Serializable {
glm::ivec3 size;
@ -41,6 +42,11 @@ public:
/// @param content world 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
std::unique_ptr<VoxelFragment> rotated(const Content& content) const;

View File

@ -307,13 +307,13 @@ void WorldGenerator::generateBiomes(
copy->resize(
floordiv(CHUNK_W, def.heightsBPD) + 1,
floordiv(CHUNK_D, def.heightsBPD) + 1,
InterpolationType::LINEAR
def.heightsInterpolation
);
prototype.heightmapInputs.push_back(std::move(copy));
}
for (const auto& map : biomeParams) {
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);
}
@ -345,7 +345,7 @@ void WorldGenerator::generateHeightmap(
);
prototype.heightmap->clamp();
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.level = ChunkPrototypeLevel::HEIGHTMAP;