Voxel changed from 16 bit to 32 bit + new lua functions

This commit is contained in:
MihailRis 2024-01-04 15:27:07 +03:00
parent 460b08a006
commit 06f66ffd71
10 changed files with 229 additions and 36 deletions

View File

@ -11,6 +11,9 @@ const int CHUNK_W = 16;
const int CHUNK_H = 256; const int CHUNK_H = 256;
const int CHUNK_D = 16; const int CHUNK_D = 16;
const uint VOXEL_USER_BITS = 8;
constexpr uint VOXEL_USER_BITS_OFFSET = sizeof(blockstate_t)*8-VOXEL_USER_BITS;
/* Chunk volume (count of voxels per Chunk) */ /* Chunk volume (count of voxels per Chunk) */
constexpr int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D); constexpr int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D);

View File

@ -8,18 +8,15 @@
#include "../content/ContentLUT.h" #include "../content/ContentLUT.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
using std::string;
using std::unique_ptr;
using fs::path;
WorldConverter::WorldConverter(path folder, WorldConverter::WorldConverter(fs::path folder,
const Content* content, const Content* content,
const ContentLUT* lut) const ContentLUT* lut)
: lut(lut), content(content) { : lut(lut), content(content) {
DebugSettings settings; DebugSettings settings;
wfile = new WorldFiles(folder, settings); wfile = new WorldFiles(folder, settings);
path regionsFolder = wfile->getRegionsFolder(); fs::path regionsFolder = wfile->getRegionsFolder();
if (!fs::is_directory(regionsFolder)) { if (!fs::is_directory(regionsFolder)) {
std::cerr << "nothing to convert" << std::endl; std::cerr << "nothing to convert" << std::endl;
return; return;
@ -41,13 +38,13 @@ void WorldConverter::convertNext() {
if (!hasNext()) { if (!hasNext()) {
throw std::runtime_error("no more regions to convert"); throw std::runtime_error("no more regions to convert");
} }
path regfile = regions.front(); fs::path regfile = regions.front();
regions.pop(); regions.pop();
if (!fs::is_regular_file(regfile)) if (!fs::is_regular_file(regfile))
return; return;
int x, y; int x, z;
string name = regfile.stem().string(); std::string name = regfile.stem().string();
if (!WorldFiles::parseRegionFilename(name, x, y)) { if (!WorldFiles::parseRegionFilename(name, x, z)) {
std::cerr << "could not parse name " << name << std::endl; std::cerr << "could not parse name " << name << std::endl;
return; return;
} }
@ -55,11 +52,16 @@ void WorldConverter::convertNext() {
for (uint cz = 0; cz < REGION_SIZE; cz++) { for (uint cz = 0; cz < REGION_SIZE; cz++) {
for (uint cx = 0; cx < REGION_SIZE; cx++) { for (uint cx = 0; cx < REGION_SIZE; cx++) {
int gx = cx + x * REGION_SIZE; int gx = cx + x * REGION_SIZE;
int gz = cz + y * REGION_SIZE; int gz = cz + z * REGION_SIZE;
unique_ptr<ubyte[]> data (wfile->getChunk(gx, gz)); std::unique_ptr<ubyte[]> data (wfile->getChunk(gx, gz));
if (data == nullptr) if (data == nullptr)
continue; continue;
Chunk::convert(data.get(), lut); if (wfile->getVoxelRegionVersion(x, z) != REGION_FORMAT_VERSION) {
Chunk::fromOld(data.get());
}
if (lut) {
Chunk::convert(data.get(), lut);
}
wfile->put(gx, gz, data.get()); wfile->put(gx, gz, data.get());
} }
} }

View File

@ -38,8 +38,8 @@ regfile::regfile(fs::path filename) : file(filename) {
throw std::runtime_error("invalid region file magic number"); throw std::runtime_error("invalid region file magic number");
} }
version = header[8]; version = header[8];
if (version > 2) { if (version > REGION_FORMAT_VERSION) {
throw std::runtime_error( throw illegal_region_format(
"region format "+std::to_string(version)+" is not supported"); "region format "+std::to_string(version)+" is not supported");
} }
} }
@ -130,6 +130,31 @@ ubyte* WorldFiles::decompress(const ubyte* src, size_t srclen, size_t dstlen) {
return decompressed; return decompressed;
} }
int WorldFiles::getVoxelRegionVersion(int x, int z) {
regfile* rf = getRegFile(glm::ivec3(x, z, REGION_LAYER_VOXELS), getRegionsFolder());
if (rf == nullptr) {
return 0;
}
return rf->version;
}
int WorldFiles::getVoxelRegionsVersion() {
fs::path regionsFolder = getRegionsFolder();
if (!fs::is_directory(regionsFolder)) {
return REGION_FORMAT_VERSION;
}
for (auto file : fs::directory_iterator(regionsFolder)) {
int x;
int z;
if (!parseRegionFilename(file.path().stem().string(), x, z)) {
continue;
}
regfile* rf = getRegFile(glm::ivec3(x, z, REGION_LAYER_VOXELS), regionsFolder);
return rf->version;
}
return REGION_FORMAT_VERSION;
}
/* /*
* Compress and store chunk voxels data in region * Compress and store chunk voxels data in region
* @param x chunk.x * @param x chunk.x
@ -190,8 +215,7 @@ fs::path WorldFiles::getLightsFolder() const {
} }
fs::path WorldFiles::getRegionFilename(int x, int z) const { fs::path WorldFiles::getRegionFilename(int x, int z) const {
std::string filename = std::to_string(x) + "_" + std::to_string(z) + ".bin"; return fs::path(std::to_string(x) + "_" + std::to_string(z) + ".bin");
return fs::path(filename);
} }
/* /*
@ -254,7 +278,6 @@ ubyte* WorldFiles::getData(regionsmap& regions, const fs::path& folder,
int localZ = z - (regionZ * REGION_SIZE); int localZ = z - (regionZ * REGION_SIZE);
WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ); WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ);
ubyte* data = region->getChunkData(localX, localZ); ubyte* data = region->getChunkData(localX, localZ);
if (data == nullptr) { if (data == nullptr) {
uint32_t size; uint32_t size;

View File

@ -34,6 +34,12 @@ class Content;
class ContentIndices; class ContentIndices;
class World; class World;
class illegal_region_format : public std::runtime_error {
public:
illegal_region_format(const std::string& message)
: std::runtime_error(message) {}
};
class WorldRegion { class WorldRegion {
ubyte** chunksData; ubyte** chunksData;
uint32_t* sizes; uint32_t* sizes;
@ -125,6 +131,9 @@ public:
void put(Chunk* chunk); void put(Chunk* chunk);
void put(int x, int z, const ubyte* voxelData); void put(int x, int z, const ubyte* voxelData);
int getVoxelRegionVersion(int x, int z);
int getVoxelRegionsVersion();
ubyte* getChunk(int x, int z); ubyte* getChunk(int x, int z);
light_t* getLights(int x, int z); light_t* getLights(int x, int z);

View File

@ -14,7 +14,9 @@
#include "../util/stringutil.h" #include "../util/stringutil.h"
#include "../files/engine_paths.h" #include "../files/engine_paths.h"
#include "../files/WorldConverter.h" #include "../files/WorldConverter.h"
#include "../files/WorldFiles.h"
#include "../world/World.h" #include "../world/World.h"
#include "../world/Level.h"
#include "../window/Events.h" #include "../window/Events.h"
#include "../window/Window.h" #include "../window/Window.h"
#include "../engine.h" #include "../engine.h"
@ -175,8 +177,18 @@ void open_world(std::string name, Engine* engine) {
show_convert_request(engine, content, lut, folder); show_convert_request(engine, content, lut, folder);
} }
} else { } else {
Level* level = World::load(folder, settings, content, packs); // TODO: remove in 0.18
engine->setScreen(std::make_shared<LevelScreen>(engine, level)); int version;
{
WorldFiles wfile(folder, settings.debug);
version = wfile.getVoxelRegionsVersion();
}
if (version != REGION_FORMAT_VERSION) {
show_convert_request(engine, content, lut, folder);
} else {
Level* level = World::load(folder, settings, content, packs);
engine->setScreen(std::make_shared<LevelScreen>(engine, level));
}
} }
} }

View File

@ -59,6 +59,64 @@ int l_get_block(lua_State* L) {
return 1; return 1;
} }
inline int lua_pushivec3(lua_State* L, int x, int y, int z) {
lua_pushinteger(L, x);
lua_pushinteger(L, y);
lua_pushinteger(L, z);
return 3;
}
int l_get_block_x(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return lua_pushivec3(L, 1, 0, 0);
}
const Block* def = scripting::level->content->indices->getBlockDef(vox->id);
if (!def->rotatable) {
return lua_pushivec3(L, 1, 0, 0);
} else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()];
return lua_pushivec3(L, rot.axisX.x, rot.axisX.y, rot.axisX.z);
}
}
int l_get_block_y(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return lua_pushivec3(L, 0, 1, 0);
}
const Block* def = scripting::level->content->indices->getBlockDef(vox->id);
if (!def->rotatable) {
return lua_pushivec3(L, 0, 1, 0);
} else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()];
return lua_pushivec3(L, rot.axisY.x, rot.axisY.y, rot.axisY.z);
}
}
int l_get_block_z(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return lua_pushivec3(L, 0, 0, 1);
}
const Block* def = scripting::level->content->indices->getBlockDef(vox->id);
if (!def->rotatable) {
return lua_pushivec3(L, 0, 0, 1);
} else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()];
return lua_pushivec3(L, rot.axisZ.x, rot.axisZ.y, rot.axisZ.z);
}
}
int l_get_player_pos(lua_State* L) { int l_get_player_pos(lua_State* L) {
glm::vec3 pos = scripting::level->player->hitbox->position; glm::vec3 pos = scripting::level->player->hitbox->position;
lua_pushnumber(L, pos.x); lua_pushnumber(L, pos.x);
@ -101,6 +159,42 @@ int l_get_block_states(lua_State* L) {
return 1; return 1;
} }
int l_get_block_script_states(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
int offset = lua_tointeger(L, 4) + VOXEL_USER_BITS_OFFSET;
int bits = lua_tointeger(L, 5);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
lua_pushinteger(L, 0);
return 1;
}
uint mask = ((1 << bits) - 1) << offset;
uint data = (vox->states & mask) >> offset;
lua_pushinteger(L, data);
return 1;
}
int l_set_block_script_states(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
int offset = lua_tointeger(L, 4) + VOXEL_USER_BITS_OFFSET;
int bits = lua_tointeger(L, 5);
uint mask = (1 << bits) - 1;
int value = lua_tointeger(L, 6) & mask;
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return 0;
}
vox->states = (vox->states & (~mask)) | (value << offset);
return 0;
}
int l_is_replaceable_at(lua_State* L) { int l_is_replaceable_at(lua_State* L) {
int x = lua_tointeger(L, 1); int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2); int y = lua_tointeger(L, 2);
@ -121,9 +215,14 @@ void apilua::create_funcs(lua_State* L) {
lua_addfunc(L, l_is_replaceable_at, "is_replaceable_at"); lua_addfunc(L, l_is_replaceable_at, "is_replaceable_at");
lua_addfunc(L, l_set_block, "set_block"); lua_addfunc(L, l_set_block, "set_block");
lua_addfunc(L, l_get_block, "get_block"); lua_addfunc(L, l_get_block, "get_block");
lua_addfunc(L, l_get_block_x, "get_block_X");
lua_addfunc(L, l_get_block_y, "get_block_Y");
lua_addfunc(L, l_get_block_z, "get_block_Z");
lua_addfunc(L, l_get_player_pos, "get_player_pos"); lua_addfunc(L, l_get_player_pos, "get_player_pos");
lua_addfunc(L, l_set_player_pos, "set_player_pos"); lua_addfunc(L, l_set_player_pos, "set_player_pos");
lua_addfunc(L, l_get_player_rot, "get_player_rot"); lua_addfunc(L, l_get_player_rot, "get_player_rot");
lua_addfunc(L, l_set_player_rot, "set_player_rot"); lua_addfunc(L, l_set_player_rot, "set_player_rot");
lua_addfunc(L, l_get_block_states, "get_block_states"); lua_addfunc(L, l_get_block_states, "get_block_states");
lua_addfunc(L, l_get_block_script_states, "get_block_script_states");
lua_addfunc(L, l_set_block_script_states, "set_block_script_states");
} }

View File

@ -53,8 +53,14 @@ void scripting::initialize(EnginePaths* paths) {
if (L == nullptr) { if (L == nullptr) {
throw std::runtime_error("could not to initialize Lua"); throw std::runtime_error("could not to initialize Lua");
} }
// Allowed standard libraries
luaopen_base(L); luaopen_base(L);
luaopen_math(L); luaopen_math(L);
luaopen_string(L);
luaopen_table(L);
// io-manipulations will be implemented via api functions
std::cout << LUA_VERSION << std::endl; std::cout << LUA_VERSION << std::endl;
# ifdef LUAJIT_VERSION # ifdef LUAJIT_VERSION

View File

@ -9,8 +9,8 @@ typedef unsigned int uint;
// use for bytes arrays // use for bytes arrays
typedef uint8_t ubyte; typedef uint8_t ubyte;
typedef uint8_t blockid_t; typedef uint16_t blockid_t;
typedef uint8_t blockstate_t; typedef uint16_t blockstate_t;
typedef uint16_t light_t; typedef uint16_t light_t;
#endif #endif

View File

@ -1,4 +1,7 @@
#include "Chunk.h" #include "Chunk.h"
#include <memory>
#include "voxel.h" #include "voxel.h"
#include "../content/ContentLUT.h" #include "../content/ContentLUT.h"
#include "../lighting/Lightmap.h" #include "../lighting/Lightmap.h"
@ -22,7 +25,7 @@ Chunk::~Chunk(){
bool Chunk::isEmpty(){ bool Chunk::isEmpty(){
int id = -1; int id = -1;
for (int i = 0; i < CHUNK_VOL; i++){ for (size_t 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;
@ -34,14 +37,14 @@ bool Chunk::isEmpty(){
} }
void Chunk::updateHeights() { void Chunk::updateHeights() {
for (int i = 0; i < CHUNK_VOL; i++) { for (size_t 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 > -1; 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;
@ -51,7 +54,7 @@ void Chunk::updateHeights() {
Chunk* Chunk::clone() const { Chunk* Chunk::clone() const {
Chunk* other = new Chunk(x,z); Chunk* other = new Chunk(x,z);
for (int i = 0; i < CHUNK_VOL; i++) for (size_t 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;
@ -59,32 +62,67 @@ Chunk* Chunk::clone() const {
/** /**
Current chunk format: Current chunk format:
[voxel_ids...][voxel_states...]; - byte-order: big-endian
- [don't panic!] first and second bytes are separated for RLE efficiency
```cpp
uint8_t voxel_id_first_byte[CHUNK_VOL];
uint8_t voxel_id_second_byte[CHUNK_VOL];
uint8_t voxel_states_first_byte[CHUNK_VOL];
uint8_t voxel_states_second_byte[CHUNK_VOL];
```
Total size: (CHUNK_VOL * 4) bytes
*/ */
ubyte* Chunk::encode() const { ubyte* Chunk::encode() const {
ubyte* buffer = new ubyte[CHUNK_DATA_LEN]; ubyte* buffer = new ubyte[CHUNK_DATA_LEN];
for (size_t i = 0; i < CHUNK_VOL; i++) { for (size_t i = 0; i < CHUNK_VOL; i++) {
buffer[i] = voxels[i].id; buffer[i] = voxels[i].id >> 8;
buffer[CHUNK_VOL + i] = voxels[i].states; 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; return buffer;
} }
/** /**
@return true if all is fine * @return true if all is fine
*/ **/
bool Chunk::decode(ubyte* data) { bool Chunk::decode(ubyte* data) {
for (size_t i = 0; i < CHUNK_VOL; i++) { for (size_t i = 0; i < CHUNK_VOL; i++) {
voxel& vox = voxels[i]; voxel& vox = voxels[i];
vox.id = data[i];
vox.states = data[CHUNK_VOL + i]; ubyte bid1 = data[i];
ubyte bid2 = data[CHUNK_VOL + i];
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; return true;
} }
void Chunk::convert(ubyte* data, const ContentLUT* lut) { /*
* Convert chunk voxels data from 16 bit to 32 bit
*/
void Chunk::fromOld(ubyte* data) {
for (size_t i = 0; i < CHUNK_VOL; i++) { for (size_t i = 0; i < CHUNK_VOL; i++) {
blockid_t id = data[i]; data[i + CHUNK_VOL*3] = data[i + CHUNK_VOL];
data[i] = lut->getBlockId(id); data[i + CHUNK_VOL] = data[i];
data[i + CHUNK_VOL*2] = 0;
data[i] = 0;
}
}
void Chunk::convert(ubyte* data, const ContentLUT* lut) {
for (size_t i = 0; i < CHUNK_VOL; i++) {
// see encode method to understand what the hell is going on here
blockid_t id = ((blockid_t(data[i]) << 8) |
blockid_t(data[CHUNK_VOL+i]));
blockid_t replacement = lut->getBlockId(id);
data[i] = replacement >> 8;
data[CHUNK_VOL+i] = replacement & 0xFF;
} }
} }

View File

@ -12,7 +12,7 @@ struct ChunkFlag{
static const int UNSAVED = 0x10; static const int UNSAVED = 0x10;
static const int LOADED_LIGHTS = 0x20; static const int LOADED_LIGHTS = 0x20;
}; };
#define CHUNK_DATA_LEN (CHUNK_VOL*2) #define CHUNK_DATA_LEN (CHUNK_VOL*4)
struct voxel; struct voxel;
class Lightmap; class Lightmap;
@ -78,6 +78,7 @@ public:
ubyte* encode() const; ubyte* encode() const;
bool decode(ubyte* data); bool decode(ubyte* data);
static void fromOld(ubyte* data);
static void convert(ubyte* data, const ContentLUT* lut); static void convert(ubyte* data, const ContentLUT* lut);
}; };