converting block states to a bitfield

This commit is contained in:
MihailRis 2024-05-31 11:13:36 +03:00
parent 5dd06b233e
commit 6d933ac263
17 changed files with 197 additions and 164 deletions

View File

@ -20,6 +20,7 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <bitset>
using namespace gui; using namespace gui;
@ -75,7 +76,9 @@ std::shared_ptr<UINode> create_debug_panel(
auto* indices = level->content->getIndices(); auto* indices = level->content->getIndices();
auto def = indices->getBlockDef(player->selectedVoxel.id); auto def = indices->getBlockDef(player->selectedVoxel.id);
std::wstringstream stream; std::wstringstream stream;
stream << std::hex << player->selectedVoxel.states; stream << "r:" << player->selectedVoxel.state.rotation << " s:"
<< player->selectedVoxel.state.segment << " u:"
<< std::bitset<8>(player->selectedVoxel.state.userbits);
if (def) { if (def) {
stream << L" (" << util::str2wstr_utf8(def->name) << L")"; stream << L" (" << util::str2wstr_utf8(def->name) << L")";
} }

View File

@ -219,10 +219,13 @@ void BlocksRenderer::blockXSprite(int x, int y, int z,
// HINT: texture faces order: {east, west, bottom, top, south, north} // HINT: texture faces order: {east, west, bottom, top, south, north}
/* AABB blocks render method */ /* AABB blocks render method */
void BlocksRenderer::blockAABB(const ivec3& icoord, void BlocksRenderer::blockAABB(
const UVRegion(&texfaces)[6], const ivec3& icoord,
const Block* block, ubyte rotation, const UVRegion(&texfaces)[6],
bool lights) { const Block* block,
ubyte rotation,
bool lights
) {
if (block->hitboxes.empty()) { if (block->hitboxes.empty()) {
return; return;
} }
@ -301,11 +304,13 @@ void BlocksRenderer::blockCustomModel(const ivec3& icoord,
} }
/* Fastest solid shaded blocks render method */ /* Fastest solid shaded blocks render method */
void BlocksRenderer::blockCube(int x, int y, int z, void BlocksRenderer::blockCube(
const UVRegion(&texfaces)[6], int x, int y, int z,
const Block* block, const UVRegion(&texfaces)[6],
ubyte states, const Block* block,
bool lights) { blockstate states,
bool lights
) {
ubyte group = block->drawGroup; ubyte group = block->drawGroup;
vec3 X(1, 0, 0); vec3 X(1, 0, 0);
@ -314,7 +319,7 @@ void BlocksRenderer::blockCube(int x, int y, int z,
vec3 coord(x, y, z); vec3 coord(x, y, z);
if (block->rotatable) { if (block->rotatable) {
auto& rotations = block->rotations; auto& rotations = block->rotations;
auto& orient = rotations.variants[states & BLOCK_ROT_MASK]; auto& orient = rotations.variants[states.rotation];
X = orient.axisX; X = orient.axisX;
Y = orient.axisY; Y = orient.axisY;
Z = orient.axisZ; Z = orient.axisZ;
@ -423,7 +428,7 @@ void BlocksRenderer::render(const voxel* voxels) {
int z = (i / CHUNK_D) % CHUNK_W; int z = (i / CHUNK_D) % CHUNK_W;
switch (def.model) { switch (def.model) {
case BlockModel::block: 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; break;
case BlockModel::xsprite: { case BlockModel::xsprite: {
blockXSprite(x, y, z, vec3(1.0f), blockXSprite(x, y, z, vec3(1.0f),
@ -431,11 +436,11 @@ void BlocksRenderer::render(const voxel* voxels) {
break; break;
} }
case BlockModel::aabb: { 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; break;
} }
case BlockModel::custom: { 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; break;
} }
default: default:

View File

@ -70,16 +70,33 @@ class BlocksRenderer {
const UVRegion& texreg, const UVRegion& texreg,
bool lights); bool lights);
void blockCube(int x, int y, int z, const UVRegion(&faces)[6], const Block* block, ubyte states, bool lights); void blockCube(
void blockAABB(const glm::ivec3& coord, int x, int y, int z,
const UVRegion(&faces)[6], const UVRegion(&faces)[6],
const Block* block, const Block* block,
ubyte rotation, blockstate states,
bool lights); 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, void blockAABB(
const Block* block, ubyte rotation, const glm::ivec3& coord,
bool lights); 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 isOpenForLight(int x, int y, int z) const;
bool isOpen(int x, int y, int z, ubyte group) const; bool isOpen(int x, int y, int z, ubyte group) const;

View File

@ -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) { 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); lighting->onBlockSet(x,y,z, 0);
if (def->rt.funcsset.onbroken) { if (def->rt.funcsset.onbroken) {
scripting::on_block_broken(player, def, x, y, z); scripting::on_block_broken(player, def, x, y, z);

View File

@ -364,7 +364,7 @@ void PlayerController::updateInteraction(){
if (vox != nullptr) { if (vox != nullptr) {
player->selectedVoxel = *vox; player->selectedVoxel = *vox;
selectedBlockId = vox->id; selectedBlockId = vox->id;
selectedBlockRotation = vox->rotation(); selectedBlockRotation = vox->state.rotation;
player->selectedBlockPosition = iend; player->selectedBlockPosition = iend;
selectedPointPosition = end; selectedPointPosition = end;
selectedBlockNormal = norm; selectedBlockNormal = norm;
@ -373,7 +373,8 @@ void PlayerController::updateInteraction(){
int z = iend.z; int z = iend.z;
Block* def = indices->getBlockDef(item->rt.placingBlock); 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 (lclick && !input.shift && item->rt.funcsset.on_block_break_by) {
if (scripting::on_item_break_block(player.get(), item, x, y, z)) if (scripting::on_item_break_block(player.get(), item, x, y, z))
@ -410,13 +411,13 @@ void PlayerController::updateInteraction(){
z = (iend.z)+(norm.z); z = (iend.z)+(norm.z);
} else { } else {
if (def->rotations.name == "pipe") { if (def->rotations.name == "pipe") {
states = BLOCK_DIR_UP; state.rotation = BLOCK_DIR_UP;
} }
} }
vox = chunks->get(x, y, z); vox = chunks->get(x, y, z);
blockid_t chosenBlock = def->rt.id; blockid_t chosenBlock = def->rt.id;
if (vox && (target = indices->getBlockDef(vox->id))->replaceable) { 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){ || !def->obstacle){
if (def->grounded && !chunks->isSolidBlock(x, y-1, z)) { if (def->grounded && !chunks->isSolidBlock(x, y-1, z)) {
chosenBlock = 0; chosenBlock = 0;
@ -426,7 +427,7 @@ void PlayerController::updateInteraction(){
glm::ivec3(x, y, z), def, glm::ivec3(x, y, z), def,
BlockInteraction::placing BlockInteraction::placing
); );
chunks->set(x, y, z, chosenBlock, states); chunks->set(x, y, z, chosenBlock, state);
lighting->onBlockSet(x,y,z, chosenBlock); lighting->onBlockSet(x,y,z, chosenBlock);
if (def->rt.funcsset.onplaced) { if (def->rt.funcsset.onplaced) {
scripting::on_block_placed(player.get(), def, x, y, z); scripting::on_block_placed(player.get(), def, x, y, z);

View File

@ -60,7 +60,7 @@ int l_set_block(lua_State* L) {
lua_Integer y = lua_tointeger(L, 2); lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3); lua_Integer z = lua_tointeger(L, 3);
lua_Integer id = lua_tointeger(L, 4); 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); bool noupdate = lua_toboolean(L, 6);
if (id < 0 || size_t(id) >= scripting::indices->countBlockDefs()) { if (id < 0 || size_t(id) >= scripting::indices->countBlockDefs()) {
return 0; return 0;
@ -68,7 +68,7 @@ int l_set_block(lua_State* L) {
if (!scripting::level->chunks->get(x, y, z)) { if (!scripting::level->chunks->get(x, y, z)) {
return 0; 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); scripting::level->lighting->onBlockSet(x,y,z, id);
if (!noupdate) if (!noupdate)
scripting::blocks->updateSides(x, y, z); scripting::blocks->updateSides(x, y, z);
@ -97,7 +97,7 @@ int l_get_block_x(lua_State* L) {
if (!def->rotatable) { if (!def->rotatable) {
return lua::pushivec3(L, 1, 0, 0); return lua::pushivec3(L, 1, 0, 0);
} else { } 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); 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) { if (!def->rotatable) {
return lua::pushivec3(L, 0, 1, 0); return lua::pushivec3(L, 0, 1, 0);
} else { } 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); 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) { if (!def->rotatable) {
return lua::pushivec3(L, 0, 0, 1); return lua::pushivec3(L, 0, 0, 1);
} else { } 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); 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 y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3); lua_Integer z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z); 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); lua_pushinteger(L, rotation);
return 1; return 1;
} }
@ -155,7 +155,7 @@ int l_set_block_rotation(lua_State* L) {
if (vox == nullptr) { if (vox == nullptr) {
return 0; return 0;
} }
vox->setRotation(value); vox->state.rotation = value;
scripting::level->chunks->getChunkByVoxel(x, y, z)->setModified(true); scripting::level->chunks->getChunkByVoxel(x, y, z)->setModified(true);
return 0; return 0;
} }
@ -165,7 +165,7 @@ int l_get_block_states(lua_State* L) {
lua_Integer y = lua_tointeger(L, 2); lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3); lua_Integer z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z); 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); lua_pushinteger(L, states);
return 1; return 1;
} }
@ -181,7 +181,7 @@ int l_set_block_states(lua_State* L) {
return 0; return 0;
} }
voxel* vox = scripting::level->chunks->get(x, y, z); voxel* vox = scripting::level->chunks->get(x, y, z);
vox->states = states; vox->state = int2blockstate(states);
chunk->setModified(true); chunk->setModified(true);
return 0; return 0;
} }
@ -199,7 +199,7 @@ int l_get_block_user_bits(lua_State* L) {
return 1; return 1;
} }
uint mask = ((1 << bits) - 1) << offset; uint mask = ((1 << bits) - 1) << offset;
uint data = (vox->states & mask) >> offset; uint data = (blockstate2int(vox->state) & mask) >> offset;
lua_pushinteger(L, data); lua_pushinteger(L, data);
return 1; return 1;
} }
@ -208,7 +208,7 @@ int l_set_block_user_bits(lua_State* L) {
lua_Integer x = lua_tointeger(L, 1); lua_Integer x = lua_tointeger(L, 1);
lua_Integer y = lua_tointeger(L, 2); lua_Integer y = lua_tointeger(L, 2);
lua_Integer z = lua_tointeger(L, 3); 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); lua_Integer bits = lua_tointeger(L, 5);
size_t mask = ((1 << bits) - 1) << offset; size_t mask = ((1 << bits) - 1) << offset;
@ -218,7 +218,7 @@ int l_set_block_user_bits(lua_State* L) {
if (vox == nullptr) { if (vox == nullptr) {
return 0; return 0;
} }
vox->states = (vox->states & (~mask)) | value; vox->state.userbits = (vox->state.userbits & (~mask)) | value;
return 0; return 0;
} }

View File

@ -44,7 +44,7 @@ public:
std::shared_ptr<Camera> currentCamera; std::shared_ptr<Camera> currentCamera;
std::unique_ptr<Hitbox> hitbox; std::unique_ptr<Hitbox> hitbox;
bool debug = false; bool debug = false;
voxel selectedVoxel {0, 0}; voxel selectedVoxel {0, {}};
glm::vec3 cam {}; glm::vec3 cam {};
glm::ivec3 selectedBlockPosition {}; glm::ivec3 selectedBlockPosition {};

View File

@ -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); 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& pos = hitbox->position;
const glm::vec3& half = hitbox->halfsize; const glm::vec3& half = hitbox->halfsize;
voxel v {};
v.states = states;
const auto& boxes = def->rotatable const auto& boxes = def->rotatable
? def->rt.hitboxes[v.rotation()] ? def->rt.hitboxes[state.rotation]
: def->hitboxes; : def->hitboxes;
for (const auto& block_hitbox : boxes) { for (const auto& block_hitbox : boxes) {
glm::vec3 min = block_hitbox.min(); glm::vec3 min = block_hitbox.min();

View File

@ -2,6 +2,7 @@
#define PHYSICS_PHYSICSSOLVER_HPP_ #define PHYSICS_PHYSICSSOLVER_HPP_
#include "../typedefs.hpp" #include "../typedefs.hpp"
#include "../voxels/voxel.hpp"
#include <glm/glm.hpp> #include <glm/glm.hpp>
@ -31,7 +32,7 @@ public:
float stepHeight float stepHeight
); );
bool isBlockInside(int x, int y, int z, Hitbox* hitbox); 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_ #endif // PHYSICS_PHYSICSSOLVER_HPP_

View File

@ -5,7 +5,6 @@
#include "util/platform.hpp" #include "util/platform.hpp"
#include "util/command_line.hpp" #include "util/command_line.hpp"
#include "debug/Logger.hpp" #include "debug/Logger.hpp"
#include "objects/Player.hpp"
#include <stdexcept> #include <stdexcept>
@ -13,7 +12,6 @@ static debug::Logger logger("main");
int main(int argc, char** argv) { int main(int argc, char** argv) {
debug::Logger::init("latest.log"); debug::Logger::init("latest.log");
std::cout << sizeof(PlayerInput) << std::endl;
EnginePaths paths; EnginePaths paths;
if (!parse_cmdline(argc, argv, paths)) if (!parse_cmdline(argc, argv, paths))

View File

@ -7,40 +7,36 @@
#include "../lighting/Lightmap.hpp" #include "../lighting/Lightmap.hpp"
Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos){ Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos){
bottom = 0; bottom = 0;
top = CHUNK_H; top = CHUNK_H;
for (uint i = 0; i < CHUNK_VOL; i++) {
voxels[i].id = 2;
voxels[i].states = 0;
}
} }
bool Chunk::isEmpty(){ bool Chunk::isEmpty(){
int id = -1; int id = -1;
for (uint i = 0; i < CHUNK_VOL; i++){ for (uint i = 0; i < CHUNK_VOL; i++){
if (voxels[i].id != id){ if (voxels[i].id != id){
if (id != -1) if (id != -1)
return false; return false;
else else
id = voxels[i].id; id = voxels[i].id;
} }
} }
return true; return true;
} }
void Chunk::updateHeights() { void Chunk::updateHeights() {
for (uint i = 0; i < CHUNK_VOL; i++) { for (uint i = 0; i < CHUNK_VOL; i++) {
if (voxels[i].id != 0) { if (voxels[i].id != 0) {
bottom = i / (CHUNK_D * CHUNK_W); bottom = i / (CHUNK_D * CHUNK_W);
break; break;
} }
} }
for (int i = CHUNK_VOL - 1; i >= 0; i--) { for (int i = CHUNK_VOL - 1; i >= 0; i--) {
if (voxels[i].id != 0) { if (voxels[i].id != 0) {
top = i / (CHUNK_D * CHUNK_W) + 1; top = i / (CHUNK_D * CHUNK_W) + 1;
break; break;
} }
} }
} }
void Chunk::addBlockInventory(std::shared_ptr<Inventory> inventory, void Chunk::addBlockInventory(std::shared_ptr<Inventory> inventory,
@ -50,13 +46,13 @@ void Chunk::addBlockInventory(std::shared_ptr<Inventory> inventory,
} }
void Chunk::removeBlockInventory(uint x, uint y, uint z) { void Chunk::removeBlockInventory(uint x, uint y, uint z) {
if (inventories.erase(vox_index(x, y, z))) { if (inventories.erase(vox_index(x, y, z))) {
setUnsaved(true); setUnsaved(true);
} }
} }
void Chunk::setBlockInventories(chunk_inventories_map map) { void Chunk::setBlockInventories(chunk_inventories_map map) {
inventories = map; inventories = map;
} }
std::shared_ptr<Inventory> Chunk::getBlockInventory(uint x, uint y, uint z) const { std::shared_ptr<Inventory> Chunk::getBlockInventory(uint x, uint y, uint z) const {
@ -70,12 +66,12 @@ std::shared_ptr<Inventory> Chunk::getBlockInventory(uint x, uint y, uint z) cons
} }
std::unique_ptr<Chunk> Chunk::clone() const { std::unique_ptr<Chunk> Chunk::clone() const {
auto other = std::make_unique<Chunk>(x,z); auto other = std::make_unique<Chunk>(x,z);
for (uint i = 0; i < CHUNK_VOL; i++) { for (uint i = 0; i < CHUNK_VOL; i++) {
other->voxels[i] = voxels[i]; other->voxels[i] = voxels[i];
} }
other->lightmap.set(&lightmap); other->lightmap.set(&lightmap);
return other; return other;
} }
/** /**
@ -93,19 +89,21 @@ std::unique_ptr<Chunk> Chunk::clone() const {
Total size: (CHUNK_VOL * 4) bytes Total size: (CHUNK_VOL * 4) bytes
*/ */
std::unique_ptr<ubyte[]> Chunk::encode() const { std::unique_ptr<ubyte[]> Chunk::encode() const {
auto buffer = std::make_unique<ubyte[]>(CHUNK_DATA_LEN); auto buffer = std::make_unique<ubyte[]>(CHUNK_DATA_LEN);
for (uint i = 0; i < CHUNK_VOL; i++) { for (uint i = 0; i < CHUNK_VOL; i++) {
buffer[i] = voxels[i].id >> 8; buffer[i] = voxels[i].id >> 8;
buffer[CHUNK_VOL+i] = voxels[i].id & 0xFF; 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; blockstate_t state = blockstate2int(voxels[i].state);
} buffer[CHUNK_VOL*2 + i] = state >> 8;
return buffer; buffer[CHUNK_VOL*3 + i] = state & 0xFF;
}
return buffer;
} }
bool Chunk::decode(const ubyte* data) { bool Chunk::decode(const ubyte* data) {
for (uint i = 0; i < CHUNK_VOL; i++) { for (uint i = 0; i < CHUNK_VOL; i++) {
voxel& vox = voxels[i]; voxel& vox = voxels[i];
ubyte bid1 = data[i]; ubyte bid1 = data[i];
ubyte bid2 = data[CHUNK_VOL + 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 bst1 = data[CHUNK_VOL*2 + i];
ubyte bst2 = data[CHUNK_VOL*3 + i]; ubyte bst2 = data[CHUNK_VOL*3 + i];
vox.id = (blockid_t(bid1) << 8) | (blockid_t(bid2)); vox.id = (blockid_t(bid1) << 8) | (blockid_t(bid2));
vox.states = (blockstate_t(bst1) << 8) | (blockstate_t(bst2)); vox.state = int2blockstate((blockstate_t(bst1) << 8) | (blockstate_t(bst2)));
} }
return true; return true;
} }
void Chunk::convert(ubyte* data, const ContentLUT* lut) { void Chunk::convert(ubyte* data, const ContentLUT* lut) {

View File

@ -10,12 +10,12 @@
#include "../lighting/Lightmap.hpp" #include "../lighting/Lightmap.hpp"
struct ChunkFlag { struct ChunkFlag {
static const int MODIFIED = 0x1; static const int MODIFIED = 0x1;
static const int READY = 0x2; static const int READY = 0x2;
static const int LOADED = 0x4; static const int LOADED = 0x4;
static const int LIGHTED = 0x8; static const int LIGHTED = 0x8;
static const int UNSAVED = 0x10; static const int UNSAVED = 0x10;
static const int LOADED_LIGHTS = 0x20; static const int LOADED_LIGHTS = 0x20;
}; };
inline constexpr int CHUNK_DATA_LEN = CHUNK_VOL*4; inline constexpr int CHUNK_DATA_LEN = CHUNK_VOL*4;
@ -27,72 +27,72 @@ using chunk_inventories_map = std::unordered_map<uint, std::shared_ptr<Inventory
class Chunk { class Chunk {
public: public:
int x, z; int x, z;
int bottom, top; int bottom, top;
voxel voxels[CHUNK_VOL]; voxel voxels[CHUNK_VOL] {};
Lightmap lightmap; Lightmap lightmap;
int flags = 0; int flags = 0;
/* Block inventories map where key is index of block in voxels array */ /* Block inventories map where key is index of block in voxels array */
chunk_inventories_map inventories; chunk_inventories_map inventories;
Chunk(int x, int z); Chunk(int x, int z);
bool isEmpty(); bool isEmpty();
void updateHeights(); void updateHeights();
// unused // unused
std::unique_ptr<Chunk> clone() const; std::unique_ptr<Chunk> clone() const;
// flags getters/setters below // flags getters/setters below
inline void setFlags(int mask, bool value){ inline void setFlags(int mask, bool value){
if (value) if (value)
flags |= mask; flags |= mask;
else else
flags &= ~(mask); flags &= ~(mask);
} }
/* Creates new block inventory given size /* Creates new block inventory given size
@return inventory id or 0 if block does not exists */ @return inventory id or 0 if block does not exists */
void addBlockInventory(std::shared_ptr<Inventory> inventory, void addBlockInventory(std::shared_ptr<Inventory> inventory,
uint x, uint y, uint z); uint x, uint y, uint z);
void removeBlockInventory(uint x, uint y, uint z); void removeBlockInventory(uint x, uint y, uint z);
void setBlockInventories(chunk_inventories_map map); void setBlockInventories(chunk_inventories_map map);
/* @return inventory bound to the given block or nullptr */ /* @return inventory bound to the given block or nullptr */
std::shared_ptr<Inventory> getBlockInventory(uint x, uint y, uint z) const; std::shared_ptr<Inventory> getBlockInventory(uint x, uint y, uint z) const;
inline bool isUnsaved() const {return flags & ChunkFlag::UNSAVED;} inline bool isUnsaved() const {return flags & ChunkFlag::UNSAVED;}
inline bool isModified() const {return flags & ChunkFlag::MODIFIED;} inline bool isModified() const {return flags & ChunkFlag::MODIFIED;}
inline bool isLighted() const {return flags & ChunkFlag::LIGHTED;} inline bool isLighted() const {return flags & ChunkFlag::LIGHTED;}
inline bool isLoaded() const {return flags & ChunkFlag::LOADED;} inline bool isLoaded() const {return flags & ChunkFlag::LOADED;}
inline bool isLoadedLights() const {return flags & ChunkFlag::LOADED_LIGHTS;} inline bool isLoadedLights() const {return flags & ChunkFlag::LOADED_LIGHTS;}
inline bool isReady() const {return flags & ChunkFlag::READY;} inline bool isReady() const {return flags & ChunkFlag::READY;}
inline void setUnsaved(bool newState) {setFlags(ChunkFlag::UNSAVED, newState);} inline void setUnsaved(bool newState) {setFlags(ChunkFlag::UNSAVED, newState);}
inline void setModified(bool newState) {setFlags(ChunkFlag::MODIFIED, newState);} inline void setModified(bool newState) {setFlags(ChunkFlag::MODIFIED, newState);}
inline void setLoaded(bool newState) {setFlags(ChunkFlag::LOADED, newState);} inline void setLoaded(bool newState) {setFlags(ChunkFlag::LOADED, newState);}
inline void setLoadedLights(bool newState) {setFlags(ChunkFlag::LOADED_LIGHTS, newState);} inline void setLoadedLights(bool newState) {setFlags(ChunkFlag::LOADED_LIGHTS, newState);}
inline void setLighted(bool newState) {setFlags(ChunkFlag::LIGHTED, newState);} inline void setLighted(bool newState) {setFlags(ChunkFlag::LIGHTED, newState);}
inline void setReady(bool newState) {setFlags(ChunkFlag::READY, newState);} inline void setReady(bool newState) {setFlags(ChunkFlag::READY, newState);}
std::unique_ptr<ubyte[]> encode() const; std::unique_ptr<ubyte[]> encode() const;
/** /**
* @return true if all is fine * @return true if all is fine
**/ **/
bool decode(const ubyte* data); bool decode(const ubyte* data);
static void convert(ubyte* data, const ContentLUT* lut); static void convert(ubyte* data, const ContentLUT* lut);
}; };

View File

@ -68,7 +68,7 @@ const AABB* Chunks::isObstacleAt(float x, float y, float z){
const Block* def = contentIds->getBlockDef(v->id); const Block* def = contentIds->getBlockDef(v->id);
if (def->obstacle) { if (def->obstacle) {
const auto& boxes = def->rotatable const auto& boxes = def->rotatable
? def->rt.hitboxes[v->rotation()] ? def->rt.hitboxes[v->state.rotation]
: def->hitboxes; : def->hitboxes;
for (const auto& hitbox : boxes) { for (const auto& hitbox : boxes) {
if (hitbox.contains({x - ix, y - iy, z - iz})) { 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(); 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) if (y < 0 || y >= CHUNK_H)
return; return;
x -= ox * CHUNK_W; x -= ox * CHUNK_W;
@ -178,7 +178,7 @@ void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, uint8_t states) {
if (def->inventorySize == 0) if (def->inventorySize == 0)
chunk->removeBlockInventory(lx, y, lz); chunk->removeBlockInventory(lx, y, lz);
vox.id = id; vox.id = id;
vox.states = states; vox.state = state;
chunk->setUnsaved(true); chunk->setUnsaved(true);
chunk->setModified(true); chunk->setModified(true);
@ -255,7 +255,7 @@ voxel* Chunks::rayCast(
if (!def->rt.solid) { if (!def->rt.solid) {
const std::vector<AABB>& hitboxes = def->rotatable const std::vector<AABB>& hitboxes = def->rotatable
? def->rt.hitboxes[voxel->rotation()] ? def->rt.hitboxes[voxel->state.rotation]
: def->hitboxes; : def->hitboxes;
scalar_t distance = maxDist; scalar_t distance = maxDist;
@ -365,7 +365,7 @@ glm::vec3 Chunks::rayCastToObstacle(glm::vec3 start, glm::vec3 dir, float maxDis
if (def->obstacle) { if (def->obstacle) {
if (!def->rt.solid) { if (!def->rt.solid) {
const std::vector<AABB>& hitboxes = def->rotatable const std::vector<AABB>& hitboxes = def->rotatable
? def->rt.hitboxes[voxel->rotation()] ? def->rt.hitboxes[voxel->state.rotation]
: def->modelBoxes; : def->modelBoxes;
scalar_t distance; scalar_t distance;

View File

@ -5,6 +5,8 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "voxel.hpp"
#include "../typedefs.hpp" #include "../typedefs.hpp"
class VoxelRenderer; class VoxelRenderer;
@ -13,7 +15,6 @@ struct AABB;
class Content; class Content;
class ContentIndices; class ContentIndices;
class Chunk; class Chunk;
struct voxel;
class WorldFiles; class WorldFiles;
class LevelEvents; class LevelEvents;
@ -42,7 +43,7 @@ public:
voxel* get(int32_t x, int32_t y, int32_t z); voxel* get(int32_t x, int32_t y, int32_t z);
light_t getLight(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); 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( voxel* rayCast(
glm::vec3 start, glm::vec3 start,

View File

@ -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++){ for (int cur_y = 0; cur_y < CHUNK_H; cur_y++){
// int cur_y = y; // int cur_y = y;
int id = cur_y < SEA_LEVEL ? idWater : BLOCK_AIR; int id = cur_y < SEA_LEVEL ? idWater : BLOCK_AIR;
int states = 0; blockstate state {};
if ((cur_y == (int)height) && (SEA_LEVEL-2 < cur_y)) { if ((cur_y == (int)height) && (SEA_LEVEL-2 < cur_y)) {
id = idGrassBlock; id = idGrassBlock;
} else if (cur_y < (height - 6)){ } else if (cur_y < (height - 6)){
@ -177,7 +177,7 @@ void DefaultWorldGenerator::generate(voxel* voxels, int cx, int cz, int seed){
treesTile, idWood, idLeaves); treesTile, idWood, idLeaves);
if (tree) { if (tree) {
id = 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)); 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)){ if ((height > SEA_LEVEL+1) && ((int)(height + 1) == cur_y) && ((unsigned short)randomgrass.rand() > 65533)){
id = idWood; 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].id = id;
voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].states = states; voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].state = state;
} }
} }
} }

View File

@ -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 x = 0; x < CHUNK_W; x++) {
for (int cur_y = 0; cur_y < CHUNK_H; cur_y++){ for (int cur_y = 0; cur_y < CHUNK_H; cur_y++){
int id = BLOCK_AIR; int id = BLOCK_AIR;
int states = 0; blockstate state {};
if(cur_y == 2) { if(cur_y == 2) {
id = idBazalt; 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].id = id;
voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].states = states; voxels[(cur_y * CHUNK_D + z) * CHUNK_W + x].state = state;
} }
} }
} }

View File

@ -10,22 +10,33 @@ inline constexpr int BLOCK_DIR_EAST = 0x3;
inline constexpr int BLOCK_DIR_UP = 0x4; inline constexpr int BLOCK_DIR_UP = 0x4;
inline constexpr int BLOCK_DIR_DOWN = 0x5; inline constexpr int BLOCK_DIR_DOWN = 0x5;
// limited to 8 block orientations struct blockstate {
inline constexpr int BLOCK_ROT_MASK = 0b0000'0111; uint8_t rotation : 3;
// reserved bits uint8_t segment : 2;
inline constexpr int BLOCK_RESERVED_MASK = 0b1111'1000; uint8_t reserved : 3;
uint8_t userbits : 8;
};
static_assert (sizeof(blockstate) == 2);
inline constexpr blockstate_t blockstate2int(blockstate b) {
return b.rotation |
(b.segment << 3) |
(b.reserved << 5) |
(b.userbits << 8);
}
inline constexpr blockstate int2blockstate(blockstate_t i) {
return {
static_cast<uint8_t>(i & 0b111),
static_cast<uint8_t>((i >> 3) & 0b11),
static_cast<uint8_t>((i >> 5) & 0b111),
static_cast<uint8_t>((i >> 8) & 0xFF)
};
}
struct voxel { struct voxel {
blockid_t id; blockid_t id;
blockstate_t states; blockstate state;
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);
}
}; };
#endif // VOXELS_VOXEL_HPP_ #endif // VOXELS_VOXEL_HPP_