add fragment.crop, fragment:crop() & fix fragments rotation when width is not equal to depth & fix extra structures placements

This commit is contained in:
MihailRis 2024-10-15 00:03:06 +03:00
parent 44eedadc06
commit 48143c5a2b
13 changed files with 93 additions and 20 deletions

View File

@ -174,3 +174,16 @@ console.add_command(
" has been saved as "..file.resolve(filename))
end
)
console.add_command(
"fragment.crop filename:str",
"Crop fragment",
function(args, kwargs)
local filename = args[1]
local fragment = generation.load_fragment(filename)
fragment:crop()
generation.save_fragment(fragment, filename, crop)
console.log("fragment with size "..vec3.tostring(fragment.size)..
" has been saved as "..file.resolve(filename))
end
)

View File

@ -145,6 +145,9 @@ static std::vector<std::unique_ptr<VoxelStructure>> load_structures(
}
auto fragment = std::make_unique<VoxelFragment>();
fragment->deserialize(files::read_binary_json(structFile));
logger.info() << "fragment " << name << " has size [" <<
fragment->getSize().x << ", " << fragment->getSize().y << ", " <<
fragment->getSize().z << "]";
structures.push_back(std::make_unique<VoxelStructure>(
load_structure_meta(name, config),

View File

@ -36,9 +36,8 @@ static int l_create_fragment(lua::State* L) {
static int l_load_fragment(lua::State* L) {
auto paths = engine->getPaths();
auto [prefix, filename] = EnginePaths::parsePath(lua::require_string(L, 1));
auto path = paths->resolve(prefix+":generators/"+filename+".vox");
auto filename = lua::require_string(L, 1);
auto path = paths->resolve(filename);
if (!std::filesystem::exists(path)) {
throw std::runtime_error("file "+path.u8string()+" does not exist");
}

View File

@ -13,6 +13,17 @@ LuaVoxelFragment::LuaVoxelFragment(std::shared_ptr<VoxelFragment> fragment)
LuaVoxelFragment::~LuaVoxelFragment() {
}
static int l_crop(lua::State* L) {
if (auto fragment = touserdata<LuaVoxelFragment>(L, 1)) {
fragment->getFragment()->crop();
}
return 0;
}
static std::unordered_map<std::string, lua_CFunction> methods {
{"crop", lua::wrap<l_crop>},
};
static int l_meta_tostring(lua::State* L) {
return pushstring(L, "VoxelFragment(0x" + util::tohex(
reinterpret_cast<uint64_t>(topointer(L, 1)))+")");
@ -27,12 +38,16 @@ static int l_meta_index(lua::State* L) {
auto fieldname = tostring(L, 2);
if (!std::strcmp(fieldname, "size")) {
return pushivec(L, fragment->getFragment()->getSize());
} else {
auto found = methods.find(tostring(L, 2));
if (found != methods.end()) {
return pushcfunction(L, found->second);
}
}
}
return 0;
}
int LuaVoxelFragment::createMetatable(lua::State* L) {
createtable(L, 0, 2);
pushcfunction(L, lua::wrap<l_meta_tostring>);

View File

@ -108,10 +108,10 @@ void ChunksStorage::getVoxels(VoxelsVolume* volume, bool backlight) const {
int ecz = floordiv(z + d, CHUNK_D);
int cw = ecx - scx + 1;
int ch = ecz - scz + 1;
int cd = ecz - scz + 1;
// cw*ch chunks will be scanned
for (int cz = scz; cz < scz + ch; cz++) {
// cw*cd chunks will be scanned
for (int cz = scz; cz < scz + cd; cz++) {
for (int cx = scx; cx < scx + cw; cx++) {
const auto& found = chunksMap.find(glm::ivec2(cx, cz));
if (found == chunksMap.end()) {

View File

@ -9,6 +9,7 @@
#include "voxels/ChunksStorage.hpp"
#include "voxels/VoxelsVolume.hpp"
#include "world/Level.hpp"
#include "core_defs.hpp"
std::unique_ptr<VoxelFragment> VoxelFragment::create(
Level* level,
@ -51,10 +52,10 @@ std::unique_ptr<VoxelFragment> VoxelFragment::create(
level->chunksStorage->getVoxels(&volume);
auto volVoxels = volume.getVoxels();
std::vector<voxel> voxels(size.x*size.y*size.z);
std::vector<voxel> voxels(size.x * size.y * size.z);
std::vector<std::string> blockNames;
std::unordered_map<blockid_t, blockid_t> blocksRegistered;
std::vector<std::string> blockNames {CORE_AIR};
std::unordered_map<blockid_t, blockid_t> blocksRegistered {{0, 0}};
auto contentIndices = level->content->getIndices();
for (size_t i = 0 ; i < voxels.size(); i++) {
blockid_t id = volVoxels[i].id;
@ -113,6 +114,49 @@ void VoxelFragment::deserialize(const dv::value& src) {
}
}
void VoxelFragment::crop() {
glm::ivec3 min = size;
glm::ivec3 max = {};
blockid_t air;
const auto& found = std::find(blockNames.begin(), blockNames.end(), CORE_AIR);
if (found == blockNames.end()) {
throw std::runtime_error(CORE_AIR+" is not found in fragment");
}
air = found - blockNames.begin();
for (int y = 0; y < size.y; y++) {
for (int z = 0; z < size.z; z++) {
for (int x = 0; x < size.x; x++) {
if (voxels[vox_index(x, y, z, size.x, size.z)].id != air) {
min = glm::min(min, {x, y, z});
max = glm::max(max, {x+1, y+1, z+1});
}
}
}
}
if (glm::min(min, max) == min) {
auto newSize = max - min;
std::vector<voxel> newVoxels(newSize.x * newSize.y * newSize.z);
for (int y = 0; y < newSize.y; y++) {
for (int z = 0; z < newSize.z; z++) {
for (int x = 0; x < newSize.x; x++) {
newVoxels[vox_index(x, y, z, newSize.x, newSize.z)] =
voxels[vox_index(
x + min.x,
y + min.y,
z + min.z,
size.x,
size.z
)];
}
}
}
voxels = std::move(newVoxels);
size = newSize;
}
}
void VoxelFragment::prepare(const Content& content) {
auto volume = size.x*size.y*size.z;
voxelsRuntime.resize(volume);
@ -129,8 +173,8 @@ std::unique_ptr<VoxelFragment> VoxelFragment::rotated(const Content& content) co
for (int y = 0; y < size.y; y++) {
for (int z = 0; z < size.z; z++) {
for (int x = 0; x < size.x; x++) {
auto& voxel = newVoxels[vox_index(x, y, z, size.x, size.z)];
voxel = voxels[vox_index(size.z-z-1, y, x, size.z, size.x)];
auto& voxel = newVoxels[vox_index(size.z-z-1, y, x, size.z, size.x)];
voxel = voxels[vox_index(x, y, z, size.x, size.z)];
// swap X and Z segment bits
voxel.state.segment = ((voxel.state.segment & 0b001) << 2)
| (voxel.state.segment & 0b010)

View File

@ -35,6 +35,7 @@ public:
dv::value serialize() const override;
void deserialize(const dv::value& src) override;
void crop();
/// @brief Build runtime voxel indices
/// @param content world content

View File

@ -272,9 +272,6 @@ void WorldGenerator::generateStructures(
glm::ivec3 position {x, height, z};
position.x -= structure.getSize().x / 2;
position.z -= structure.getSize().z / 2;
prototype.placements.emplace_back(
1, StructurePlacement {structureId, position, rotation}
);
placeStructure(
StructurePlacement {
structureId,
@ -486,6 +483,7 @@ void WorldGenerator::generateStructure(
auto& structVoxels = structure.getRuntimeVoxels();
const auto& offset = placement.position;
const auto& size = structure.getSize();
for (int y = 0; y < size.y; y++) {
int sy = y + offset.y;
if (sy < 0 || sy >= CHUNK_H) {

View File

@ -66,10 +66,6 @@ class WorldGenerator {
void generateStructures(ChunkPrototype& prototype, int x, int z);
void generatePlacements(
const ChunkPrototype& prototype, voxel* voxels, int x, int z
);
void generateBiomes(ChunkPrototype& prototype, int x, int z);
void generateHeightmap(ChunkPrototype& prototype, int x, int z);
@ -81,6 +77,9 @@ class WorldGenerator {
void placeLine(const LinePlacement& line, int priority);
void generatePlacements(
const ChunkPrototype& prototype, voxel* voxels, int x, int z
);
void generateLine(
const ChunkPrototype& prototype,
const LinePlacement& placement,
@ -113,7 +112,8 @@ class WorldGenerator {
void placeStructures(
const std::vector<Placement>& placements,
ChunkPrototype& prototype,
int x, int z);
int x, int z
);
public:
WorldGenerator(
const GeneratorDef& def,