diff --git a/src/files/WorldRegions.cpp b/src/files/WorldRegions.cpp index 55f3b3d2..af3aadd4 100644 --- a/src/files/WorldRegions.cpp +++ b/src/files/WorldRegions.cpp @@ -374,7 +374,7 @@ void WorldRegions::put(Chunk* chunk){ chunk->encode(), CHUNK_DATA_LEN, true); // Writing lights cache - if (doWriteLights && chunk->isLighted()) { + if (doWriteLights && chunk->flags.lighted) { put(chunk->x, chunk->z, REGION_LAYER_LIGHTS, chunk->lightmap.encode(), LIGHTMAP_DATA_LEN, true); } diff --git a/src/frontend/debug_panel.cpp b/src/frontend/debug_panel.cpp index c281903c..b854fce4 100644 --- a/src/frontend/debug_panel.cpp +++ b/src/frontend/debug_panel.cpp @@ -20,6 +20,7 @@ #include #include #include +#include using namespace gui; @@ -73,19 +74,25 @@ std::shared_ptr create_debug_panel( })); panel->add(create_label([=](){ auto* indices = level->content->getIndices(); - auto def = indices->getBlockDef(player->selectedVoxel.id); std::wstringstream stream; - stream << std::hex << player->selectedVoxel.states; - if (def) { - stream << L" (" << util::str2wstr_utf8(def->name) << L")"; - } + stream << "r:" << player->selectedVoxel.state.rotation << " s:" + << player->selectedVoxel.state.segment << " u:" + << std::bitset<8>(player->selectedVoxel.state.userbits); if (player->selectedVoxel.id == BLOCK_VOID) { - return std::wstring {L"block: none"}; + return std::wstring {L"block: -"}; } else { return L"block: "+std::to_wstring(player->selectedVoxel.id)+ L" "+stream.str(); } })); + panel->add(create_label([=](){ + auto* indices = level->content->getIndices(); + if (auto def = indices->getBlockDef(player->selectedVoxel.id)) { + return L"name: " + util::str2wstr_utf8(def->name); + } else { + return std::wstring {L"name: void"}; + } + })); panel->add(create_label([=](){ return L"seed: "+std::to_wstring(level->getWorld()->getSeed()); })); diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 95aa69f7..ba6546f8 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -333,7 +333,7 @@ void Hud::openInventory( if (blockinv == nullptr) { blockinv = level->inventories->createVirtual(blockUI->getSlotsCount()); } - level->chunks->getChunkByVoxel(block.x, block.y, block.z)->setUnsaved(true); + level->chunks->getChunkByVoxel(block.x, block.y, block.z)->flags.unsaved; blockUI->bind(blockinv, content); blockPos = block; currentblockid = level->chunks->get(block.x, block.y, block.z)->id; diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 4b1779d4..9420d070 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -219,10 +219,13 @@ void BlocksRenderer::blockXSprite(int x, int y, int z, // HINT: texture faces order: {east, west, bottom, top, south, north} /* AABB blocks render method */ -void BlocksRenderer::blockAABB(const ivec3& icoord, - const UVRegion(&texfaces)[6], - const Block* block, ubyte rotation, - bool lights) { +void BlocksRenderer::blockAABB( + const ivec3& icoord, + const UVRegion(&texfaces)[6], + const Block* block, + ubyte rotation, + bool lights +) { if (block->hitboxes.empty()) { return; } @@ -301,11 +304,13 @@ void BlocksRenderer::blockCustomModel(const ivec3& icoord, } /* Fastest solid shaded blocks render method */ -void BlocksRenderer::blockCube(int x, int y, int z, - const UVRegion(&texfaces)[6], - const Block* block, - ubyte states, - bool lights) { +void BlocksRenderer::blockCube( + int x, int y, int z, + const UVRegion(&texfaces)[6], + const Block* block, + blockstate states, + bool lights +) { ubyte group = block->drawGroup; vec3 X(1, 0, 0); @@ -314,7 +319,7 @@ void BlocksRenderer::blockCube(int x, int y, int z, vec3 coord(x, y, z); if (block->rotatable) { auto& rotations = block->rotations; - auto& orient = rotations.variants[states & BLOCK_ROT_MASK]; + auto& orient = rotations.variants[states.rotation]; X = orient.axisX; Y = orient.axisY; Z = orient.axisZ; @@ -423,7 +428,7 @@ void BlocksRenderer::render(const voxel* voxels) { int z = (i / CHUNK_D) % CHUNK_W; switch (def.model) { case BlockModel::block: - blockCube(x, y, z, texfaces, &def, vox.states, !def.rt.emissive); + blockCube(x, y, z, texfaces, &def, vox.state, !def.rt.emissive); break; case BlockModel::xsprite: { blockXSprite(x, y, z, vec3(1.0f), @@ -431,11 +436,11 @@ void BlocksRenderer::render(const voxel* voxels) { break; } case BlockModel::aabb: { - blockAABB(ivec3(x,y,z), texfaces, &def, vox.rotation(), !def.rt.emissive); + blockAABB(ivec3(x,y,z), texfaces, &def, vox.state.rotation, !def.rt.emissive); break; } case BlockModel::custom: { - blockCustomModel(ivec3(x, y, z), &def, vox.rotation(), !def.rt.emissive); + blockCustomModel(ivec3(x, y, z), &def, vox.state.rotation, !def.rt.emissive); break; } default: diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index 23b6d625..244d4674 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -70,16 +70,33 @@ class BlocksRenderer { const UVRegion& texreg, bool lights); - void blockCube(int x, int y, int z, const UVRegion(&faces)[6], const Block* block, ubyte states, bool lights); - void blockAABB(const glm::ivec3& coord, - const UVRegion(&faces)[6], - const Block* block, - ubyte rotation, - bool lights); - void blockXSprite(int x, int y, int z, const glm::vec3& size, const UVRegion& face1, const UVRegion& face2, float spread); - void blockCustomModel(const glm::ivec3& icoord, - const Block* block, ubyte rotation, - bool lights); + void blockCube( + int x, int y, int z, + const UVRegion(&faces)[6], + const Block* block, + blockstate states, + bool lights + ); + void blockAABB( + const glm::ivec3& coord, + const UVRegion(&faces)[6], + const Block* block, + ubyte rotation, + bool lights + ); + void blockXSprite( + int x, int y, int z, + const glm::vec3& size, + const UVRegion& face1, + const UVRegion& face2, + float spread + ); + void blockCustomModel( + const glm::ivec3& icoord, + const Block* block, + ubyte rotation, + bool lights + ); bool isOpenForLight(int x, int y, int z) const; bool isOpen(int x, int y, int z, ubyte group) const; diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 7f3f3959..d1011a10 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -56,19 +56,16 @@ ChunksRenderer::~ChunksRenderer() { } std::shared_ptr ChunksRenderer::render(std::shared_ptr chunk, bool important) { - chunk->setModified(false); - + chunk->flags.modified = false; if (important) { auto mesh = renderer->render(chunk.get(), level->chunksStorage.get()); meshes[glm::ivec2(chunk->x, chunk->z)] = mesh; return mesh; } - glm::ivec2 key(chunk->x, chunk->z); if (inwork.find(key) != inwork.end()) { return nullptr; } - inwork[key] = true; threadPool.enqueueJob(chunk); return nullptr; @@ -86,7 +83,7 @@ std::shared_ptr ChunksRenderer::getOrRender(std::shared_ptr chunk, if (found == meshes.end()) { return render(chunk, important); } - if (chunk->isModified()) { + if (chunk->flags.modified) { render(chunk, important); } return found->second; diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index ad7030a2..8d02a750 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -79,7 +79,7 @@ bool WorldRenderer::drawChunk( bool culling ){ auto chunk = level->chunks->chunks[index]; - if (!chunk->isLighted()) { + if (!chunk->flags.lighted) { return false; } float distance = glm::distance( diff --git a/src/lighting/LightSolver.cpp b/src/lighting/LightSolver.cpp index 0656ee53..f9865956 100644 --- a/src/lighting/LightSolver.cpp +++ b/src/lighting/LightSolver.cpp @@ -21,7 +21,7 @@ void LightSolver::add(int x, int y, int z, int emission) { addqueue.push(lightentry {x, y, z, ubyte(emission)}); Chunk* chunk = chunks->getChunkByVoxel(x, y, z); - chunk->setModified(true); + chunk->flags.modified = true; chunk->lightmap.set(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel, emission); } @@ -67,7 +67,7 @@ void LightSolver::solve(){ if (chunk) { int lx = x - chunk->x * CHUNK_W; int lz = z - chunk->z * CHUNK_D; - chunk->setModified(true); + chunk->flags.modified = true; ubyte light = chunk->lightmap.get(lx,y,lz, channel); if (light != 0 && light == entry.light-1){ @@ -96,7 +96,7 @@ void LightSolver::solve(){ if (chunk) { int lx = x - chunk->x * CHUNK_W; int lz = z - chunk->z * CHUNK_D; - chunk->setModified(true); + chunk->flags.modified = true; ubyte light = chunk->lightmap.get(lx, y, lz, channel); voxel& v = chunk->voxels[vox_index(lx, y, lz)]; diff --git a/src/logic/BlocksController.cpp b/src/logic/BlocksController.cpp index 6cbb4aba..8a8f58a8 100644 --- a/src/logic/BlocksController.cpp +++ b/src/logic/BlocksController.cpp @@ -71,7 +71,7 @@ void BlocksController::updateSides(int x, int y, int z) { } void BlocksController::breakBlock(Player* player, const Block* def, int x, int y, int z) { - chunks->set(x,y,z, 0, 0); + chunks->set(x,y,z, 0, {}); lighting->onBlockSet(x,y,z, 0); if (def->rt.funcsset.onbroken) { scripting::on_block_broken(player, def, x, y, z); @@ -132,7 +132,7 @@ void BlocksController::randomTick(int tickid, int parts) { if ((index + tickid) % parts != 0) continue; auto& chunk = chunks->chunks[index]; - if (chunk == nullptr || !chunk->isLighted()) + if (chunk == nullptr || !chunk->flags.lighted) continue; for (int s = 0; s < segments; s++) { for (int i = 0; i < 4; i++) { diff --git a/src/logic/ChunksController.cpp b/src/logic/ChunksController.cpp index 1c039a14..56eab88c 100644 --- a/src/logic/ChunksController.cpp +++ b/src/logic/ChunksController.cpp @@ -61,7 +61,7 @@ bool ChunksController::loadVisible(){ int index = z * w + x; auto& chunk = chunks->chunks[index]; if (chunk != nullptr){ - if (chunk->isLoaded() && !chunk->isLighted()) { + if (chunk->flags.loaded && !chunk->flags.lighted) { if (buildLights(chunk)) { return true; } @@ -99,12 +99,12 @@ bool ChunksController::buildLights(std::shared_ptr chunk) { } } if (surrounding == MIN_SURROUNDING) { - bool lightsCache = chunk->isLoadedLights(); + bool lightsCache = chunk->flags.loadedLights; if (!lightsCache) { lighting->buildSkyLight(chunk->x, chunk->z); } lighting->onChunkLoaded(chunk->x, chunk->z, !lightsCache); - chunk->setLighted(true); + chunk->flags.lighted = true; return true; } return false; @@ -114,20 +114,20 @@ void ChunksController::createChunk(int x, int z) { auto chunk = level->chunksStorage->create(x, z); chunks->putChunk(chunk); - if (!chunk->isLoaded()) { + if (!chunk->flags.loaded) { generator->generate( chunk->voxels, x, z, level->getWorld()->getSeed() ); - chunk->setUnsaved(true); + chunk->flags.unsaved = true; } chunk->updateHeights(); - if (!chunk->isLoadedLights()) { + if (!chunk->flags.loadedLights) { Lighting::prebuildSkyLight( chunk.get(), level->content->getIndices() ); } - chunk->setLoaded(true); - chunk->setReady(true); + chunk->flags.loaded = true; + chunk->flags.ready = true; } diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 06f884aa..4547a4da 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -364,7 +364,7 @@ void PlayerController::updateInteraction(){ if (vox != nullptr) { player->selectedVoxel = *vox; selectedBlockId = vox->id; - selectedBlockRotation = vox->rotation(); + selectedBlockRotation = vox->state.rotation; player->selectedBlockPosition = iend; selectedPointPosition = end; selectedBlockNormal = norm; @@ -373,7 +373,8 @@ void PlayerController::updateInteraction(){ int z = iend.z; Block* def = indices->getBlockDef(item->rt.placingBlock); - uint8_t states = determine_rotation(def, norm, camera->dir); + blockstate state {}; + state.rotation = determine_rotation(def, norm, camera->dir); if (lclick && !input.shift && item->rt.funcsset.on_block_break_by) { if (scripting::on_item_break_block(player.get(), item, x, y, z)) @@ -410,13 +411,13 @@ void PlayerController::updateInteraction(){ z = (iend.z)+(norm.z); } else { if (def->rotations.name == "pipe") { - states = BLOCK_DIR_UP; + state.rotation = BLOCK_DIR_UP; } } vox = chunks->get(x, y, z); blockid_t chosenBlock = def->rt.id; if (vox && (target = indices->getBlockDef(vox->id))->replaceable) { - if (!level->physics->isBlockInside(x,y,z,def,states, player->hitbox.get()) + if (!level->physics->isBlockInside(x,y,z,def,state, player->hitbox.get()) || !def->obstacle){ if (def->grounded && !chunks->isSolidBlock(x, y-1, z)) { chosenBlock = 0; @@ -426,7 +427,7 @@ void PlayerController::updateInteraction(){ glm::ivec3(x, y, z), def, BlockInteraction::placing ); - chunks->set(x, y, z, chosenBlock, states); + chunks->set(x, y, z, chosenBlock, state); lighting->onBlockSet(x,y,z, chosenBlock); if (def->rt.funcsset.onplaced) { scripting::on_block_placed(player.get(), def, x, y, z); diff --git a/src/logic/scripting/lua/libblock.cpp b/src/logic/scripting/lua/libblock.cpp index 695d8e36..0bc509fc 100644 --- a/src/logic/scripting/lua/libblock.cpp +++ b/src/logic/scripting/lua/libblock.cpp @@ -60,7 +60,7 @@ int l_set_block(lua_State* L) { lua_Integer y = lua_tointeger(L, 2); lua_Integer z = lua_tointeger(L, 3); lua_Integer id = lua_tointeger(L, 4); - lua_Integer states = lua_tointeger(L, 5); + lua_Integer state = lua_tointeger(L, 5); bool noupdate = lua_toboolean(L, 6); if (id < 0 || size_t(id) >= scripting::indices->countBlockDefs()) { return 0; @@ -68,7 +68,7 @@ int l_set_block(lua_State* L) { if (!scripting::level->chunks->get(x, y, z)) { return 0; } - scripting::level->chunks->set(x, y, z, id, states); + scripting::level->chunks->set(x, y, z, id, int2blockstate(state)); scripting::level->lighting->onBlockSet(x,y,z, id); if (!noupdate) scripting::blocks->updateSides(x, y, z); @@ -97,7 +97,7 @@ int l_get_block_x(lua_State* L) { if (!def->rotatable) { return lua::pushivec3(L, 1, 0, 0); } else { - const CoordSystem& rot = def->rotations.variants[vox->rotation()]; + const CoordSystem& rot = def->rotations.variants[vox->state.rotation]; return lua::pushivec3(L, rot.axisX.x, rot.axisX.y, rot.axisX.z); } } @@ -114,7 +114,7 @@ int l_get_block_y(lua_State* L) { if (!def->rotatable) { return lua::pushivec3(L, 0, 1, 0); } else { - const CoordSystem& rot = def->rotations.variants[vox->rotation()]; + const CoordSystem& rot = def->rotations.variants[vox->state.rotation]; return lua::pushivec3(L, rot.axisY.x, rot.axisY.y, rot.axisY.z); } } @@ -131,7 +131,7 @@ int l_get_block_z(lua_State* L) { if (!def->rotatable) { return lua::pushivec3(L, 0, 0, 1); } else { - const CoordSystem& rot = def->rotations.variants[vox->rotation()]; + const CoordSystem& rot = def->rotations.variants[vox->state.rotation]; return lua::pushivec3(L, rot.axisZ.x, rot.axisZ.y, rot.axisZ.z); } } @@ -141,7 +141,7 @@ int l_get_block_rotation(lua_State* L) { lua_Integer y = lua_tointeger(L, 2); lua_Integer z = lua_tointeger(L, 3); voxel* vox = scripting::level->chunks->get(x, y, z); - int rotation = vox == nullptr ? 0 : vox->rotation(); + int rotation = vox == nullptr ? 0 : vox->state.rotation; lua_pushinteger(L, rotation); return 1; } @@ -155,8 +155,8 @@ int l_set_block_rotation(lua_State* L) { if (vox == nullptr) { return 0; } - vox->setRotation(value); - scripting::level->chunks->getChunkByVoxel(x, y, z)->setModified(true); + vox->state.rotation = value; + scripting::level->chunks->getChunkByVoxel(x, y, z)->setModifiedAndUnsaved(); return 0; } @@ -165,7 +165,7 @@ int l_get_block_states(lua_State* L) { lua_Integer y = lua_tointeger(L, 2); lua_Integer z = lua_tointeger(L, 3); voxel* vox = scripting::level->chunks->get(x, y, z); - int states = vox == nullptr ? 0 : vox->states; + int states = vox == nullptr ? 0 : blockstate2int(vox->state); lua_pushinteger(L, states); return 1; } @@ -181,8 +181,8 @@ int l_set_block_states(lua_State* L) { return 0; } voxel* vox = scripting::level->chunks->get(x, y, z); - vox->states = states; - chunk->setModified(true); + vox->state = int2blockstate(states); + chunk->setModifiedAndUnsaved(); return 0; } @@ -199,7 +199,7 @@ int l_get_block_user_bits(lua_State* L) { return 1; } uint mask = ((1 << bits) - 1) << offset; - uint data = (vox->states & mask) >> offset; + uint data = (blockstate2int(vox->state) & mask) >> offset; lua_pushinteger(L, data); return 1; } @@ -208,18 +208,23 @@ int l_set_block_user_bits(lua_State* L) { lua_Integer x = lua_tointeger(L, 1); lua_Integer y = lua_tointeger(L, 2); lua_Integer z = lua_tointeger(L, 3); - lua_Integer offset = lua_tointeger(L, 4) + VOXEL_USER_BITS_OFFSET; + lua_Integer offset = lua_tointeger(L, 4); lua_Integer bits = lua_tointeger(L, 5); size_t mask = ((1 << bits) - 1) << offset; lua_Integer value = (lua_tointeger(L, 6) << offset) & mask; + Chunk* chunk = scripting::level->chunks->getChunkByVoxel(x, y, z); + if (chunk == nullptr) { + return 0; + } voxel* vox = scripting::level->chunks->get(x, y, z); if (vox == nullptr) { return 0; } - vox->states = (vox->states & (~mask)) | value; - return 0; + vox->state.userbits = (vox->state.userbits & (~mask)) | value; + chunk->setModifiedAndUnsaved(); + return 0; } int l_is_replaceable_at(lua_State* L) { diff --git a/src/objects/Player.hpp b/src/objects/Player.hpp index 3d9e8fd6..0afeda5c 100644 --- a/src/objects/Player.hpp +++ b/src/objects/Player.hpp @@ -44,7 +44,7 @@ public: std::shared_ptr currentCamera; std::unique_ptr hitbox; bool debug = false; - voxel selectedVoxel {0, 0}; + voxel selectedVoxel {0, {}}; glm::vec3 cam {}; glm::ivec3 selectedBlockPosition {}; diff --git a/src/physics/PhysicsSolver.cpp b/src/physics/PhysicsSolver.cpp index 6760aa89..f3c5963a 100644 --- a/src/physics/PhysicsSolver.cpp +++ b/src/physics/PhysicsSolver.cpp @@ -219,13 +219,11 @@ bool PhysicsSolver::isBlockInside(int x, int y, int z, Hitbox* hitbox) { y >= floor(pos.y-half.y) && y <= floor(pos.y+half.y); } -bool PhysicsSolver::isBlockInside(int x, int y, int z, Block* def, blockstate_t states, Hitbox* hitbox) { +bool PhysicsSolver::isBlockInside(int x, int y, int z, Block* def, blockstate state, Hitbox* hitbox) { const glm::vec3& pos = hitbox->position; const glm::vec3& half = hitbox->halfsize; - voxel v {}; - v.states = states; const auto& boxes = def->rotatable - ? def->rt.hitboxes[v.rotation()] + ? def->rt.hitboxes[state.rotation] : def->hitboxes; for (const auto& block_hitbox : boxes) { glm::vec3 min = block_hitbox.min(); diff --git a/src/physics/PhysicsSolver.hpp b/src/physics/PhysicsSolver.hpp index e35f364c..6e940f99 100644 --- a/src/physics/PhysicsSolver.hpp +++ b/src/physics/PhysicsSolver.hpp @@ -2,6 +2,7 @@ #define PHYSICS_PHYSICSSOLVER_HPP_ #include "../typedefs.hpp" +#include "../voxels/voxel.hpp" #include @@ -31,7 +32,7 @@ public: float stepHeight ); bool isBlockInside(int x, int y, int z, Hitbox* hitbox); - bool isBlockInside(int x, int y, int z, Block* def, blockstate_t states, Hitbox* hitbox); + bool isBlockInside(int x, int y, int z, Block* def, blockstate state, Hitbox* hitbox); }; #endif // PHYSICS_PHYSICSSOLVER_HPP_ diff --git a/src/voxel_engine.cpp b/src/voxel_engine.cpp index 33d18c0e..c6a2ec7e 100644 --- a/src/voxel_engine.cpp +++ b/src/voxel_engine.cpp @@ -5,7 +5,6 @@ #include "util/platform.hpp" #include "util/command_line.hpp" #include "debug/Logger.hpp" -#include "objects/Player.hpp" #include @@ -13,7 +12,6 @@ static debug::Logger logger("main"); int main(int argc, char** argv) { debug::Logger::init("latest.log"); - std::cout << sizeof(PlayerInput) << std::endl; EnginePaths paths; if (!parse_cmdline(argc, argv, paths)) diff --git a/src/voxels/Chunk.cpp b/src/voxels/Chunk.cpp index bfd79cda..18dabec2 100644 --- a/src/voxels/Chunk.cpp +++ b/src/voxels/Chunk.cpp @@ -7,56 +7,52 @@ #include "../lighting/Lightmap.hpp" Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos){ - bottom = 0; - top = CHUNK_H; - for (uint i = 0; i < CHUNK_VOL; i++) { - voxels[i].id = 2; - voxels[i].states = 0; - } + bottom = 0; + top = CHUNK_H; } bool Chunk::isEmpty(){ - int id = -1; - for (uint i = 0; i < CHUNK_VOL; i++){ - if (voxels[i].id != id){ - if (id != -1) - return false; - else - id = voxels[i].id; - } - } - return true; + int id = -1; + for (uint i = 0; i < CHUNK_VOL; i++){ + if (voxels[i].id != id){ + if (id != -1) + return false; + else + id = voxels[i].id; + } + } + return true; } void Chunk::updateHeights() { - for (uint i = 0; i < CHUNK_VOL; i++) { - if (voxels[i].id != 0) { - bottom = i / (CHUNK_D * CHUNK_W); - break; - } - } - for (int i = CHUNK_VOL - 1; i >= 0; i--) { - if (voxels[i].id != 0) { - top = i / (CHUNK_D * CHUNK_W) + 1; - break; - } - } + for (uint i = 0; i < CHUNK_VOL; i++) { + if (voxels[i].id != 0) { + bottom = i / (CHUNK_D * CHUNK_W); + break; + } + } + for (int i = CHUNK_VOL - 1; i >= 0; i--) { + if (voxels[i].id != 0) { + top = i / (CHUNK_D * CHUNK_W) + 1; + break; + } + } } void Chunk::addBlockInventory(std::shared_ptr inventory, uint x, uint y, uint z) { inventories[vox_index(x, y, z)] = inventory; - setUnsaved(true); + flags.unsaved = true; } void Chunk::removeBlockInventory(uint x, uint y, uint z) { - if (inventories.erase(vox_index(x, y, z))) { - setUnsaved(true); - } + if (inventories.erase(vox_index(x, y, z))) { + flags.unsaved = true; + } } void Chunk::setBlockInventories(chunk_inventories_map map) { - inventories = map; + inventories = map; } std::shared_ptr Chunk::getBlockInventory(uint x, uint y, uint z) const { @@ -70,12 +66,12 @@ std::shared_ptr Chunk::getBlockInventory(uint x, uint y, uint z) cons } std::unique_ptr Chunk::clone() const { - auto other = std::make_unique(x,z); - for (uint i = 0; i < CHUNK_VOL; i++) { - other->voxels[i] = voxels[i]; + auto other = std::make_unique(x,z); + for (uint i = 0; i < CHUNK_VOL; i++) { + other->voxels[i] = voxels[i]; } - other->lightmap.set(&lightmap); - return other; + other->lightmap.set(&lightmap); + return other; } /** @@ -93,19 +89,21 @@ std::unique_ptr Chunk::clone() const { Total size: (CHUNK_VOL * 4) bytes */ std::unique_ptr Chunk::encode() const { - auto buffer = std::make_unique(CHUNK_DATA_LEN); - for (uint i = 0; i < CHUNK_VOL; i++) { - buffer[i] = voxels[i].id >> 8; + auto buffer = std::make_unique(CHUNK_DATA_LEN); + for (uint i = 0; i < CHUNK_VOL; i++) { + buffer[i] = voxels[i].id >> 8; buffer[CHUNK_VOL+i] = voxels[i].id & 0xFF; - buffer[CHUNK_VOL*2 + i] = voxels[i].states >> 8; - buffer[CHUNK_VOL*3 + i] = voxels[i].states & 0xFF; - } - return buffer; + + blockstate_t state = blockstate2int(voxels[i].state); + buffer[CHUNK_VOL*2 + i] = state >> 8; + buffer[CHUNK_VOL*3 + i] = state & 0xFF; + } + return buffer; } bool Chunk::decode(const ubyte* data) { - for (uint i = 0; i < CHUNK_VOL; i++) { - voxel& vox = voxels[i]; + for (uint i = 0; i < CHUNK_VOL; i++) { + voxel& vox = voxels[i]; ubyte bid1 = data[i]; ubyte bid2 = data[CHUNK_VOL + i]; @@ -113,10 +111,10 @@ bool Chunk::decode(const ubyte* data) { ubyte bst1 = data[CHUNK_VOL*2 + i]; ubyte bst2 = data[CHUNK_VOL*3 + i]; - vox.id = (blockid_t(bid1) << 8) | (blockid_t(bid2)); - vox.states = (blockstate_t(bst1) << 8) | (blockstate_t(bst2)); - } - return true; + vox.id = (blockid_t(bid1) << 8) | (blockid_t(bid2)); + vox.state = int2blockstate((blockstate_t(bst1) << 8) | (blockstate_t(bst2))); + } + return true; } void Chunk::convert(ubyte* data, const ContentLUT* lut) { diff --git a/src/voxels/Chunk.hpp b/src/voxels/Chunk.hpp index 019b4f09..535b6125 100644 --- a/src/voxels/Chunk.hpp +++ b/src/voxels/Chunk.hpp @@ -9,14 +9,6 @@ #include "voxel.hpp" #include "../lighting/Lightmap.hpp" -struct ChunkFlag { - static const int MODIFIED = 0x1; - static const int READY = 0x2; - static const int LOADED = 0x4; - static const int LIGHTED = 0x8; - static const int UNSAVED = 0x10; - static const int LOADED_LIGHTS = 0x20; -}; inline constexpr int CHUNK_DATA_LEN = CHUNK_VOL*4; class Lightmap; @@ -27,72 +19,52 @@ using chunk_inventories_map = std::unordered_map clone() const; - - // flags getters/setters below - inline void setFlags(int mask, bool value){ - if (value) - flags |= mask; - else - flags &= ~(mask); - } + std::unique_ptr clone() const; /* Creates new block inventory given size @return inventory id or 0 if block does not exists */ void addBlockInventory(std::shared_ptr inventory, uint x, uint y, uint z); - void removeBlockInventory(uint x, uint y, uint z); - void setBlockInventories(chunk_inventories_map map); + void removeBlockInventory(uint x, uint y, uint z); + void setBlockInventories(chunk_inventories_map map); /* @return inventory bound to the given block or nullptr */ std::shared_ptr getBlockInventory(uint x, uint y, uint z) const; - inline bool isUnsaved() const {return flags & ChunkFlag::UNSAVED;} + inline void setModifiedAndUnsaved() { + flags.modified = true; + flags.unsaved = true; + } - inline bool isModified() const {return flags & ChunkFlag::MODIFIED;} - - inline bool isLighted() const {return flags & ChunkFlag::LIGHTED;} - - inline bool isLoaded() const {return flags & ChunkFlag::LOADED;} - - inline bool isLoadedLights() const {return flags & ChunkFlag::LOADED_LIGHTS;} - - inline bool isReady() const {return flags & ChunkFlag::READY;} - - inline void setUnsaved(bool newState) {setFlags(ChunkFlag::UNSAVED, newState);} - - inline void setModified(bool newState) {setFlags(ChunkFlag::MODIFIED, newState);} - - inline void setLoaded(bool newState) {setFlags(ChunkFlag::LOADED, newState);} - - inline void setLoadedLights(bool newState) {setFlags(ChunkFlag::LOADED_LIGHTS, newState);} - - inline void setLighted(bool newState) {setFlags(ChunkFlag::LIGHTED, newState);} - - inline void setReady(bool newState) {setFlags(ChunkFlag::READY, newState);} - - std::unique_ptr encode() const; + std::unique_ptr encode() const; /** * @return true if all is fine **/ - bool decode(const ubyte* data); + bool decode(const ubyte* data); static void convert(ubyte* data, const ContentLUT* lut); }; diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index 63919499..b9a63e9e 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -68,7 +68,7 @@ const AABB* Chunks::isObstacleAt(float x, float y, float z){ const Block* def = contentIds->getBlockDef(v->id); if (def->obstacle) { const auto& boxes = def->rotatable - ? def->rt.hitboxes[v->rotation()] + ? def->rt.hitboxes[v->state.rotation] : def->hitboxes; for (const auto& hitbox : boxes) { if (hitbox.contains({x - ix, y - iy, z - iz})) { @@ -158,7 +158,7 @@ Chunk* Chunks::getChunk(int x, int z){ return chunks[z * w + x].get(); } -void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, uint8_t states) { +void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state) { if (y < 0 || y >= CHUNK_H) return; x -= ox * CHUNK_W; @@ -178,24 +178,22 @@ void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, uint8_t states) { if (def->inventorySize == 0) chunk->removeBlockInventory(lx, y, lz); vox.id = id; - vox.states = states; - - chunk->setUnsaved(true); - chunk->setModified(true); + vox.state = state; + chunk->setModifiedAndUnsaved(); if (y < chunk->bottom) chunk->bottom = y; else if (y + 1 > chunk->top) chunk->top = y + 1; else if (id == 0) chunk->updateHeights(); if (lx == 0 && (chunk = getChunk(cx+ox-1, cz+oz))) - chunk->setModified(true); + chunk->flags.modified = true; if (lz == 0 && (chunk = getChunk(cx+ox, cz+oz-1))) - chunk->setModified(true); + chunk->flags.modified = true; if (lx == CHUNK_W-1 && (chunk = getChunk(cx+ox+1, cz+oz))) - chunk->setModified(true); + chunk->flags.modified = true; if (lz == CHUNK_D-1 && (chunk = getChunk(cx+ox, cz+oz+1))) - chunk->setModified(true); + chunk->flags.modified = true; } voxel* Chunks::rayCast( @@ -255,7 +253,7 @@ voxel* Chunks::rayCast( if (!def->rt.solid) { const std::vector& hitboxes = def->rotatable - ? def->rt.hitboxes[voxel->rotation()] + ? def->rt.hitboxes[voxel->state.rotation] : def->hitboxes; scalar_t distance = maxDist; @@ -365,7 +363,7 @@ glm::vec3 Chunks::rayCastToObstacle(glm::vec3 start, glm::vec3 dir, float maxDis if (def->obstacle) { if (!def->rt.solid) { const std::vector& hitboxes = def->rotatable - ? def->rt.hitboxes[voxel->rotation()] + ? def->rt.hitboxes[voxel->state.rotation] : def->modelBoxes; scalar_t distance; @@ -499,12 +497,12 @@ void Chunks::saveAndClear(){ for (size_t i = 0; i < volume; i++){ Chunk* chunk = chunks[i].get(); chunks[i] = nullptr; - if (chunk == nullptr || !chunk->isLighted()) + if (chunk == nullptr || !chunk->flags.lighted) continue; - bool lightsUnsaved = !chunk->isLoadedLights() && + bool lightsUnsaved = !chunk->flags.loadedLights && worldFiles->doesWriteLights(); - if (!chunk->isUnsaved() && !lightsUnsaved) + if (!chunk->flags.unsaved && !lightsUnsaved) continue; regions.put(chunk); } diff --git a/src/voxels/Chunks.hpp b/src/voxels/Chunks.hpp index d2eb8cea..7dd4312d 100644 --- a/src/voxels/Chunks.hpp +++ b/src/voxels/Chunks.hpp @@ -5,6 +5,8 @@ #include #include #include + +#include "voxel.hpp" #include "../typedefs.hpp" class VoxelRenderer; @@ -13,7 +15,6 @@ struct AABB; class Content; class ContentIndices; class Chunk; -struct voxel; class WorldFiles; class LevelEvents; @@ -42,7 +43,7 @@ public: voxel* get(int32_t x, int32_t y, int32_t z); light_t getLight(int32_t x, int32_t y, int32_t z); ubyte getLight(int32_t x, int32_t y, int32_t z, int channel); - void set(int32_t x, int32_t y, int32_t z, uint32_t id, uint8_t states); + void set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state); voxel* rayCast( glm::vec3 start, diff --git a/src/voxels/ChunksStorage.cpp b/src/voxels/ChunksStorage.cpp index fa28f4f6..8a9c97b4 100644 --- a/src/voxels/ChunksStorage.cpp +++ b/src/voxels/ChunksStorage.cpp @@ -61,7 +61,7 @@ std::shared_ptr ChunksStorage::create(int x, int z) { chunk->decode(data.get()); auto invs = regions.fetchInventories(chunk->x, chunk->z); chunk->setBlockInventories(std::move(invs)); - chunk->setLoaded(true); + chunk->flags.loaded = true; for(auto& entry : chunk->inventories) { level->inventories->store(entry.second); } @@ -71,7 +71,7 @@ std::shared_ptr ChunksStorage::create(int x, int z) { auto lights = regions.getLights(chunk->x, chunk->z); if (lights) { chunk->lightmap.set(lights.get()); - chunk->setLoadedLights(true); + chunk->flags.loadedLights = true; } return chunk; } diff --git a/src/voxels/DefaultWorldGenerator.cpp b/src/voxels/DefaultWorldGenerator.cpp index b0c8561b..49747519 100644 --- a/src/voxels/DefaultWorldGenerator.cpp +++ b/src/voxels/DefaultWorldGenerator.cpp @@ -163,7 +163,7 @@ void DefaultWorldGenerator::generate(voxel* voxels, int cx, int cz, int seed){ for (int cur_y = 0; cur_y < CHUNK_H; cur_y++){ // int cur_y = y; int id = cur_y < SEA_LEVEL ? idWater : BLOCK_AIR; - int states = 0; + blockstate state {}; if ((cur_y == (int)height) && (SEA_LEVEL-2 < cur_y)) { id = idGrassBlock; } else if (cur_y < (height - 6)){ @@ -177,7 +177,7 @@ void DefaultWorldGenerator::generate(voxel* voxels, int cx, int cz, int seed){ treesTile, idWood, idLeaves); if (tree) { id = tree; - states = BLOCK_DIR_UP; + state.rotation = BLOCK_DIR_UP; } } float sand = fmax(heights.get(MAPS::SAND, cur_x, cur_z), heights.get(MAPS::CLIFF, cur_x, cur_z)); @@ -198,10 +198,10 @@ void DefaultWorldGenerator::generate(voxel* voxels, int cx, int cz, int seed){ } if ((height > SEA_LEVEL+1) && ((int)(height + 1) == cur_y) && ((unsigned short)randomgrass.rand() > 65533)){ id = idWood; - states = BLOCK_DIR_UP; + state.rotation = BLOCK_DIR_UP; } voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].id = id; - voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].states = states; + voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].state = state; } } } diff --git a/src/voxels/FlatWorldGenerator.cpp b/src/voxels/FlatWorldGenerator.cpp index 8e5c440e..f729d32b 100644 --- a/src/voxels/FlatWorldGenerator.cpp +++ b/src/voxels/FlatWorldGenerator.cpp @@ -10,7 +10,7 @@ void FlatWorldGenerator::generate(voxel* voxels, int cx, int cz, int seed) { for (int x = 0; x < CHUNK_W; x++) { for (int cur_y = 0; cur_y < CHUNK_H; cur_y++){ int id = BLOCK_AIR; - int states = 0; + blockstate state {}; if(cur_y == 2) { id = idBazalt; @@ -21,7 +21,7 @@ void FlatWorldGenerator::generate(voxel* voxels, int cx, int cz, int seed) { } voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].id = id; - voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].states = states; + voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].state = state; } } } diff --git a/src/voxels/voxel.hpp b/src/voxels/voxel.hpp index db2c8138..9cfaf698 100644 --- a/src/voxels/voxel.hpp +++ b/src/voxels/voxel.hpp @@ -10,22 +10,34 @@ inline constexpr int BLOCK_DIR_EAST = 0x3; inline constexpr int BLOCK_DIR_UP = 0x4; inline constexpr int BLOCK_DIR_DOWN = 0x5; -// limited to 8 block orientations -inline constexpr int BLOCK_ROT_MASK = 0b0000'0111; -// reserved bits -inline constexpr int BLOCK_RESERVED_MASK = 0b1111'1000; +struct blockstate { + uint8_t rotation : 3; + uint8_t segment : 2; // planned to 0.22 + uint8_t reserved : 3; + uint8_t userbits : 8; +}; +static_assert (sizeof(blockstate) == 2); + +inline constexpr blockstate_t blockstate2int(blockstate b) { + return static_cast(b.rotation) | + static_cast(b.segment) << 3 | + static_cast(b.reserved) << 5 | + static_cast(b.userbits) << 8; +} + +inline constexpr blockstate int2blockstate(blockstate_t i) { + return { + static_cast(i & 0b111), + static_cast((i >> 3) & 0b11), + static_cast((i >> 5) & 0b111), + static_cast((i >> 8) & 0xFF) + }; +} struct voxel { blockid_t id; - blockstate_t states; - - inline uint8_t rotation() const { - return states & BLOCK_ROT_MASK; - } - - inline void setRotation(uint8_t rotation) { - states = (states & (~BLOCK_ROT_MASK)) | (rotation & BLOCK_ROT_MASK); - } + blockstate state; }; +static_assert(sizeof(voxel) == 4); #endif // VOXELS_VOXEL_HPP_ diff --git a/src/world/World.cpp b/src/world/World.cpp index fdd60446..380e2f48 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -57,11 +57,11 @@ void World::write(Level* level) { for (size_t i = 0; i < chunks->volume; i++) { auto chunk = chunks->chunks[i]; - if (chunk == nullptr || !chunk->isLighted()) + if (chunk == nullptr || !chunk->flags.lighted) continue; - bool lightsUnsaved = !chunk->isLoadedLights() && + bool lightsUnsaved = !chunk->flags.loadedLights && settings.debug.doWriteLights.get(); - if (!chunk->isUnsaved() && !lightsUnsaved) + if (!chunk->flags.unsaved && !lightsUnsaved) continue; regions.put(chunk.get()); }