diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e02d1487..4f9a4bed6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,8 +30,12 @@ endif() if(MSVC) - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - target_compile_options(${PROJECT_NAME} PRIVATE /W4 /MT /O2) + if((CMAKE_BUILD_TYPE EQUAL "Release") OR (CMAKE_BUILD_TYPE EQUAL "RelWithDebInfo")) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Release>") + target_compile_options(${PROJECT_NAME} PRIVATE /W4 /MT /O2) + else() + target_compile_options(${PROJECT_NAME} PRIVATE /W4) + endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /source-charset:UTF-8") else() target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -lstdc++fs diff --git a/dev/VoxelEngine.png b/dev/VoxelEngine.png index 689245472..0d69ae740 100644 Binary files a/dev/VoxelEngine.png and b/dev/VoxelEngine.png differ diff --git a/res/texts/langs.json b/res/texts/langs.json index f39d5a9dc..1f1c884c3 100644 --- a/res/texts/langs.json +++ b/res/texts/langs.json @@ -12,9 +12,6 @@ "ru_RU": { "name": "Русский" }, - "su_SU": { - "name": "Советский" - }, "uk_UA": { "name": "Українська" } diff --git a/res/texts/su_SU.txt b/res/texts/su_SU.txt deleted file mode 100644 index 8756e3a70..000000000 --- a/res/texts/su_SU.txt +++ /dev/null @@ -1,53 +0,0 @@ -# Общее -Yes=Да -No=Нет -Ok = Понятно -Cancel=Отмена -Back = Обратно -Continue=Продолжить - -error.pack-not-found=Не удалось найти пакет - -# Меню -menu.New World = Новый Мир -menu.Quit=Выход -menu.Continue=Продолжить -menu.Save and Quit to Menu=Сохранить и Вернуться на Главную -menu.missing-content=Отсутствует некоторое наполнение! -menu.Controls=Управление -menu.Back to Main Menu=Вернуться на Главную -menu.Settings=Настройки -menu.Content=Наполнение -menu.Seed=Семя -menu.Name=Название -menu.Create World=Создать Мир - -world.convert-request=Есть изменения в индексах! Преобразовать мир? - -# Настройки -settings.Load Distance=Дальность Загрузки -settings.Load Speed=Скорость Загрузки -settings.Fog Curve=Искривление Тумана -settings.Backlight=Подсветка -settings.V-Sync=Вертикальная Синхронизация - -settings.FOV=Поле Зрения -settings.Mouse Sensitivity=Чувствительность Мыши -settings.Language=Язык - -# Управление -movement.forward=Вперёд -movement.back=Назад -movement.left=Влево -movement.right=Вправо -movement.jump=Прыжок -movement.sprint=Ускорение -movement.crouch=Красться -movement.cheat=Чит -hud.inventory=Инвентарь -player.pick=Подобрать Блок -player.attack=Атаковать / Сломать -player.build=Поставить Блок -player.flight=Полёт -camera.zoom=Приближение -camera.mode=Сменить Режим Камеры \ No newline at end of file diff --git a/src/coders/png.cpp b/src/coders/png.cpp index b2ffc0e2e..d022fd1da 100644 --- a/src/coders/png.cpp +++ b/src/coders/png.cpp @@ -8,8 +8,6 @@ #include "../graphics/Texture.h" #include "../files/files.h" -using std::unique_ptr; - #ifndef _WIN32 #define LIBPNG #endif @@ -18,10 +16,8 @@ using std::unique_ptr; #include // returns 0 if all-right, 1 otherwise -int _png_write(const char* filename, uint width, uint height, const u_char8* data, bool alpha) { - png_structp png_ptr = nullptr; - png_infop info_ptr = nullptr; - uint pixsize = alpha ? 4 : 3; +int _png_write(const char* filename, u_int width, u_int height, const u_char8* data, bool alpha) { + u_int pixsize = alpha ? 4 : 3; // Open file for writing (binary mode) FILE* fp = fopen(filename, "wb"); @@ -32,7 +28,7 @@ int _png_write(const char* filename, uint width, uint height, const u_char8* dat } // Initialize write structure - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (png_ptr == nullptr) { fprintf(stderr, "Could not allocate write struct\n"); fclose(fp); @@ -41,7 +37,7 @@ int _png_write(const char* filename, uint width, uint height, const u_char8* dat } // Initialize info structure - info_ptr = png_create_info_struct(png_ptr); + png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == nullptr) { fprintf(stderr, "Could not allocate info struct\n"); fclose(fp); @@ -73,7 +69,7 @@ int _png_write(const char* filename, uint width, uint height, const u_char8* dat png_write_info(png_ptr, info_ptr); - unique_ptr row(new png_byte[pixsize * width]); + std::unique_ptr row(new png_byte[pixsize * width]); // Write image data for (uint y = 0; y < height; y++) { @@ -95,15 +91,11 @@ int _png_write(const char* filename, uint width, uint height, const u_char8* dat } ImageData* _png_load(const char* file){ - FILE *f = nullptr; - bool is_png = false; int bit_depth, color_type, row_bytes; - png_infop info_ptr, end_info; png_uint_32 t_width, t_height; - png_byte header[8], *image_data; - png_bytepp row_pointers; - png_structp png_ptr; + png_byte header[8]; + FILE *f = nullptr; if ((f = fopen(file, "r")) == nullptr) { return nullptr; } @@ -112,28 +104,28 @@ ImageData* _png_load(const char* file){ return nullptr; } - is_png = (png_sig_cmp(header, 0, 8) == 0); + bool is_png = (png_sig_cmp(header, 0, 8) == 0); if (!is_png) { fclose(f); return nullptr; } - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, + png_struct* png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (png_ptr == nullptr) { fclose(f); return nullptr; } - info_ptr = png_create_info_struct(png_ptr); + png_info* info_ptr = png_create_info_struct(png_ptr); if (info_ptr == nullptr) { - png_destroy_read_struct( &png_ptr, (png_infopp) nullptr, - (png_infopp) nullptr ); + png_destroy_read_struct(&png_ptr, (png_info**) nullptr, + (png_info**) nullptr); fclose(f); return nullptr; } - end_info = png_create_info_struct(png_ptr); + png_info* end_info = png_create_info_struct(png_ptr); if (end_info == nullptr) { - png_destroy_read_struct(&png_ptr, (png_infopp) nullptr, - (png_infopp) nullptr); + png_destroy_read_struct(&png_ptr, (png_info**) nullptr, + (png_info**) nullptr); fclose(f); return nullptr; } @@ -144,33 +136,34 @@ ImageData* _png_load(const char* file){ return nullptr; } - png_init_io( png_ptr, f ); - png_set_sig_bytes( png_ptr, 8 ); - png_read_info( png_ptr, info_ptr ); - png_get_IHDR( png_ptr, info_ptr, &t_width, &t_height, &bit_depth, - &color_type, nullptr, nullptr, nullptr ); - png_read_update_info( png_ptr, info_ptr ); - row_bytes = png_get_rowbytes( png_ptr, info_ptr ); - image_data = new png_byte[row_bytes * t_height]; + png_init_io(png_ptr, f); + png_set_sig_bytes(png_ptr, 8); + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &t_width, &t_height, &bit_depth, + &color_type, nullptr, nullptr, nullptr); + png_read_update_info(png_ptr, info_ptr); + row_bytes = png_get_rowbytes(png_ptr, info_ptr); + + std::unique_ptr image_data (new png_byte[row_bytes * t_height]); if (!image_data) { - png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return nullptr; } - row_pointers = (png_bytepp) malloc( t_height * sizeof(png_bytep) ); - if ( row_pointers == nullptr ) { - png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); - delete[] image_data; + + std::unique_ptr row_pointers (new png_byte*[t_height]); + if (row_pointers == nullptr) { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return nullptr; } for (uint i = 0; i < t_height; ++i ) { - row_pointers[t_height - 1 - i] = image_data + i * row_bytes; + row_pointers[t_height - 1 - i] = image_data.get() + i * row_bytes; } - png_read_image(png_ptr, row_pointers); + png_read_image(png_ptr, row_pointers.get()); ImageFormat format; - switch ( png_get_color_type( png_ptr, info_ptr ) ) { + switch (png_get_color_type(png_ptr, info_ptr)) { case PNG_COLOR_TYPE_RGBA: format = ImageFormat::rgba8888; break; @@ -178,18 +171,15 @@ ImageData* _png_load(const char* file){ format = ImageFormat::rgb888; break; default: - printf( "Color type %d not supported!\n", - png_get_color_type( png_ptr, info_ptr ) ); - png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); - delete[] image_data; - free( row_pointers ); + printf("Color type %d not supported!\n", + png_get_color_type(png_ptr, info_ptr)); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return nullptr; } - ImageData* image = new ImageData(format, t_width, t_height, (void*)image_data); + ImageData* image = new ImageData(format, t_width, t_height, (void*)image_data.release()); png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); - free( row_pointers ); - fclose( f ); + fclose(f); return image; } #else @@ -335,7 +325,7 @@ ImageData* _png_load(const char* file){ flipped[(ihdr.height-i-1)*rowsize+j] = out[i*rowsize+j]; } } - delete[] out; // <- finally delete out + delete[] out; // <- finally delete out // no, delete spng usage ImageData* image = new ImageData(ImageFormat::rgba8888, ihdr.width, ihdr.height, (void*)flipped); @@ -356,7 +346,7 @@ ImageData* png::load_image(std::string filename) { } Texture* png::load_texture(std::string filename) { - unique_ptr image (_png_load(filename.c_str())); + std::unique_ptr image (_png_load(filename.c_str())); if (image == nullptr){ std::cerr << "Could not load texture " << filename << std::endl; return nullptr; diff --git a/src/constants.h b/src/constants.h index 00d7f7d55..0b135aa4a 100644 --- a/src/constants.h +++ b/src/constants.h @@ -5,14 +5,17 @@ #include "typedefs.h" const int ENGINE_VERSION_MAJOR = 0; -const int ENGINE_VERSION_MINOR = 16; +const int ENGINE_VERSION_MINOR = 17; const int CHUNK_W = 16; const int CHUNK_H = 256; 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) */ -const int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D); +constexpr int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D); /* BLOCK_VOID is block id used to mark non-existing voxel (voxel of missing chunk) */ const blockid_t BLOCK_VOID = std::numeric_limits::max(); diff --git a/src/files/WorldConverter.cpp b/src/files/WorldConverter.cpp index eeb206107..ea40387b8 100644 --- a/src/files/WorldConverter.cpp +++ b/src/files/WorldConverter.cpp @@ -8,18 +8,15 @@ #include "../content/ContentLUT.h" 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 ContentLUT* lut) : lut(lut), content(content) { DebugSettings settings; wfile = new WorldFiles(folder, settings); - path regionsFolder = wfile->getRegionsFolder(); + fs::path regionsFolder = wfile->getRegionsFolder(); if (!fs::is_directory(regionsFolder)) { std::cerr << "nothing to convert" << std::endl; return; @@ -41,13 +38,13 @@ void WorldConverter::convertNext() { if (!hasNext()) { throw std::runtime_error("no more regions to convert"); } - path regfile = regions.front(); + fs::path regfile = regions.front(); regions.pop(); if (!fs::is_regular_file(regfile)) return; - int x, y; - string name = regfile.stem().string(); - if (!WorldFiles::parseRegionFilename(name, x, y)) { + int x, z; + std::string name = regfile.stem().string(); + if (!WorldFiles::parseRegionFilename(name, x, z)) { std::cerr << "could not parse name " << name << std::endl; return; } @@ -55,11 +52,16 @@ void WorldConverter::convertNext() { for (uint cz = 0; cz < REGION_SIZE; cz++) { for (uint cx = 0; cx < REGION_SIZE; cx++) { int gx = cx + x * REGION_SIZE; - int gz = cz + y * REGION_SIZE; - unique_ptr data (wfile->getChunk(gx, gz)); + int gz = cz + z * REGION_SIZE; + std::unique_ptr data (wfile->getChunk(gx, gz)); if (data == nullptr) 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()); } } diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp index efa2b28c7..59b28a5f5 100644 --- a/src/files/WorldFiles.cpp +++ b/src/files/WorldFiles.cpp @@ -23,9 +23,27 @@ #include #include #include +#include namespace fs = std::filesystem; +regfile::regfile(fs::path filename) : file(filename) { + if (file.length() < REGION_HEADER_SIZE) + throw std::runtime_error("incomplete region file header"); + char header[REGION_HEADER_SIZE]; + file.read(header, REGION_HEADER_SIZE); + + // avoid of use strcmp_s + if (std::string(header, strlen(REGION_FORMAT_MAGIC)) != REGION_FORMAT_MAGIC) { + throw std::runtime_error("invalid region file magic number"); + } + version = header[8]; + if (uint(version) > REGION_FORMAT_VERSION) { + throw illegal_region_format( + "region format "+std::to_string(version)+" is not supported"); + } +} + WorldRegion::WorldRegion() { chunksData = new u_char8*[REGION_CHUNKS_COUNT]{}; sizes = new uint32_t[REGION_CHUNKS_COUNT]{}; @@ -112,6 +130,31 @@ u_char8* WorldFiles::decompress(const u_char8* src, size_t srclen, size_t dstlen 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 * @param x chunk.x @@ -172,8 +215,7 @@ fs::path WorldFiles::getLightsFolder() 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(filename); + return fs::path(std::to_string(x) + "_" + std::to_string(z) + ".bin"); } /* @@ -236,7 +278,6 @@ u_char8* WorldFiles::getData(regionsmap& regions, const fs::path& folder, int localZ = z - (regionZ * REGION_SIZE); WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ); - u_char8* data = region->getChunkData(localX, localZ); if (data == nullptr) { uint32_t size; @@ -252,7 +293,8 @@ u_char8* WorldFiles::getData(regionsmap& regions, const fs::path& folder, return nullptr; } -files::rafile* WorldFiles::getRegFile(glm::ivec3 coord, const fs::path& folder) { + +regfile* WorldFiles::getRegFile(glm::ivec3 coord, const fs::path& folder) { const auto found = openRegFiles.find(coord); if (found != openRegFiles.end()) { return found->second.get(); @@ -266,7 +308,7 @@ files::rafile* WorldFiles::getRegFile(glm::ivec3 coord, const fs::path& folder) if (!fs::is_regular_file(filename)) { return nullptr; } - openRegFiles[coord] = std::make_unique(filename); + openRegFiles[coord] = std::make_unique(filename); return openRegFiles[coord].get(); } @@ -285,26 +327,27 @@ u_char8* WorldFiles::readChunkData(int x, int chunkIndex = localZ * REGION_SIZE + localX; glm::ivec3 coord(regionX, regionZ, layer); - files::rafile* file = WorldFiles::getRegFile(coord, folder); - if (file == nullptr) { + regfile* rfile = WorldFiles::getRegFile(coord, folder); + if (rfile == nullptr) { return nullptr; } + files::rafile& file = rfile->file; - size_t file_size = file->length(); + size_t file_size = file.length(); size_t table_offset = file_size - REGION_CHUNKS_COUNT * 4; uint32_t offset; - file->seekg(table_offset + chunkIndex * 4); - file->read((char*)(&offset), 4); + file.seekg(table_offset + chunkIndex * 4); + file.read((char*)(&offset), 4); offset = dataio::read_int32_big((const u_char8*)(&offset), 0); if (offset == 0){ return nullptr; } - file->seekg(offset); - file->read((char*)(&offset), 4); + file.seekg(offset); + file.read((char*)(&offset), 4); length = dataio::read_int32_big((const u_char8*)(&offset), 0); u_char8* data = new u_char8[length]; - file->read((char*)data, length); + file.read((char*)data, length); if (data == nullptr) { std::cerr << "ERROR: failed to read data of chunk x("<< x <<"), z("<< z <<")" << std::endl; } @@ -343,13 +386,13 @@ void WorldFiles::writeRegion(int x, int z, WorldRegion* entry, fs::path folder, openRegFiles.erase(regcoord); } - char header[10] = REGION_FORMAT_MAGIC; + char header[REGION_HEADER_SIZE] = REGION_FORMAT_MAGIC; header[8] = REGION_FORMAT_VERSION; header[9] = 0; // flags std::ofstream file(filename, std::ios::out | std::ios::binary); - file.write(header, 10); + file.write(header, REGION_HEADER_SIZE); - size_t offset = 10; + size_t offset = REGION_HEADER_SIZE; char intbuf[4]{}; uint offsets[REGION_CHUNKS_COUNT]{}; diff --git a/src/files/WorldFiles.h b/src/files/WorldFiles.h index cba7bfaee..b5f7cd008 100644 --- a/src/files/WorldFiles.h +++ b/src/files/WorldFiles.h @@ -15,12 +15,13 @@ #include "../typedefs.h" #include "../settings.h" +const uint REGION_HEADER_SIZE = 10; const uint REGION_LAYER_VOXELS = 0; const uint REGION_LAYER_LIGHTS = 1; const uint REGION_SIZE_BIT = 5; const uint REGION_SIZE = (1 << (REGION_SIZE_BIT)); const uint REGION_CHUNKS_COUNT = ((REGION_SIZE) * (REGION_SIZE)); -const uint REGION_FORMAT_VERSION = 1; +const uint REGION_FORMAT_VERSION = 2; const uint WORLD_FORMAT_VERSION = 1; const uint MAX_OPEN_REGION_FILES = 16; @@ -33,6 +34,12 @@ class Content; class ContentIndices; class World; +class illegal_region_format : public std::runtime_error { +public: + illegal_region_format(const std::string& message) + : std::runtime_error(message) {} +}; + class WorldRegion { u_char8** chunksData; uint32_t* sizes; @@ -52,9 +59,16 @@ public: uint32_t* getSizes() const; }; +struct regfile { + files::rafile file; + int version; + + regfile(std::filesystem::path filename); +}; + typedef std::unordered_map> regionsmap; class WorldFiles { - std::unordered_map> openRegFiles; + std::unordered_map> openRegFiles; void writeWorldInfo(const World* world); std::filesystem::path getLightsFolder() const; @@ -98,8 +112,8 @@ class WorldFiles { const std::filesystem::path& folder, int x, int z, int layer); - files::rafile* getRegFile(glm::ivec3 coord, - const std::filesystem::path& folder); + regfile* getRegFile(glm::ivec3 coord, + const std::filesystem::path& folder); public: static bool parseRegionFilename(const std::string& name, int& x, int& y); std::filesystem::path getRegionsFolder() const; @@ -117,6 +131,9 @@ public: void put(Chunk* chunk); void put(int x, int z, const u_char8* voxelData); + int getVoxelRegionVersion(int x, int z); + int getVoxelRegionsVersion(); + u_char8* getChunk(int x, int z); light_t* getLights(int x, int z); diff --git a/src/files/binary_io.cpp b/src/files/binary_io.cpp index 7c7b4b818..a1a53b584 100644 --- a/src/files/binary_io.cpp +++ b/src/files/binary_io.cpp @@ -4,8 +4,6 @@ #include #include -using std::string; - void BinaryWriter::put(u_char8 b) { buffer.push_back(b); } @@ -18,7 +16,7 @@ void BinaryWriter::putCStr(const char* str) { } } -void BinaryWriter::put(const string& s) { +void BinaryWriter::put(const std::string& s) { size_t len = s.length(); if (len > INT16_MAX) { throw std::domain_error("length > INT16_MAX"); @@ -27,7 +25,7 @@ void BinaryWriter::put(const string& s) { put((const u_char8*)s.data(), len); } -void BinaryWriter::putShortStr(const string& s) { +void BinaryWriter::putShortStr(const std::string& s) { size_t len = s.length(); if (len > 255) { throw std::domain_error("length > 255"); @@ -144,22 +142,22 @@ float BinaryReader::getFloat32() { return value.valfloat; } -string BinaryReader::getString() { +std::string BinaryReader::getString() { uint16_t length = (uint16_t)getInt16(); if (pos+length > size) { throw std::underflow_error("unexpected end"); } pos += length; - return string((const char*)(data+pos-length), length); + return std::string((const char*)(data+pos-length), length); } -string BinaryReader::getShortString() { +std::string BinaryReader::getShortString() { u_char8 length = get(); if (pos+length > size) { throw std::underflow_error("unexpected end"); } pos += length; - return string((const char*)(data+pos-length), length); + return std::string((const char*)(data+pos-length), length); } bool BinaryReader::hasNext() const { diff --git a/src/files/settings_io.cpp b/src/files/settings_io.cpp index 0d56e9e59..ed19b80fd 100644 --- a/src/files/settings_io.cpp +++ b/src/files/settings_io.cpp @@ -9,8 +9,6 @@ #include "../coders/toml.h" #include "../coders/json.h" -using std::string; - toml::Wrapper* create_wrapper(EngineSettings& settings) { std::unique_ptr wrapper (new toml::Wrapper()); toml::Section& display = wrapper->add("display"); @@ -47,7 +45,7 @@ toml::Wrapper* create_wrapper(EngineSettings& settings) { return wrapper.release(); } -string write_controls() { +std::string write_controls() { json::JObject* obj = new json::JObject(); for (auto& entry : Events::bindings) { const auto& binding = entry.second; @@ -64,7 +62,7 @@ string write_controls() { return json::stringify(obj, true, " "); } -void load_controls(string filename, string source) { +void load_controls(std::string filename, std::string source) { json::JObject* obj = json::parse(filename, source); for (auto& entry : Events::bindings) { auto& binding = entry.second; @@ -73,7 +71,7 @@ void load_controls(string filename, string source) { if (jentry == nullptr) continue; inputtype type; - string typestr; + std::string typestr; jentry->str("type", typestr); if (typestr == "keyboard") { @@ -87,4 +85,4 @@ void load_controls(string filename, string source) { binding.type = type; jentry->num("code", binding.code); } -} \ No newline at end of file +} diff --git a/src/frontend/BlocksPreview.cpp b/src/frontend/BlocksPreview.cpp index fc478d006..9b81ccbf8 100644 --- a/src/frontend/BlocksPreview.cpp +++ b/src/frontend/BlocksPreview.cpp @@ -11,9 +11,6 @@ #include "../voxels/Block.h" #include "ContentGfxCache.h" -using glm::vec4; -using glm::vec3; - BlocksPreview::BlocksPreview(Shader* shader, Atlas* atlas, const ContentGfxCache* cache) @@ -31,19 +28,21 @@ void BlocksPreview::begin(const Viewport* viewport) { glm::ortho(0.0f, float(viewport->getWidth()), 0.0f, float(viewport->getHeight()), -1000.0f, 1000.0f) * - glm::lookAt(vec3(2, 2, 2), vec3(0.0f), vec3(0, 1, 0))); + glm::lookAt(glm::vec3(2, 2, 2), glm::vec3(0.0f), glm::vec3(0, 1, 0))); atlas->getTexture()->bind(); } /* Draw one block preview at given screen position */ -void BlocksPreview::draw(const Block* def, int x, int y, int size, vec4 tint) { +void BlocksPreview::draw(const Block* def, int x, int y, int size, glm::vec4 tint) { uint width = viewport->getWidth(); uint height = viewport->getHeight(); y = height - y - 1; x += 2; y -= 35; - shader->uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), vec3(x/float(width) * 2, y/float(height) * 2, 0.0f))); + + glm::vec3 offset (x/float(width) * 2, y/float(height) * 2, 0.0f); + shader->uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset)); blockid_t id = def->rt.id; const UVRegion texfaces[6]{ cache->getRegion(id, 0), cache->getRegion(id, 1), cache->getRegion(id, 2), cache->getRegion(id, 3), @@ -54,15 +53,20 @@ void BlocksPreview::draw(const Block* def, int x, int y, int size, vec4 tint) { // something went wrong... break; case BlockModel::block: - batch->blockCube(vec3(size * 0.63f), texfaces, tint, !def->rt.emissive); + batch->blockCube(glm::vec3(size * 0.63f), texfaces, tint, !def->rt.emissive); break; case BlockModel::aabb: - batch->blockCube(def->hitbox.size() * vec3(size * 0.63f), texfaces, tint, !def->rt.emissive); + batch->blockCube(def->hitbox.size() * glm::vec3(size * 0.63f), + texfaces, tint, !def->rt.emissive); break; case BlockModel::xsprite: { - //batch->xSprite(size, size, texfaces[0], tint, !def->rt.emissive); - vec3 right = glm::normalize(vec3(1.f, 0.f, -1.f)); - batch->sprite(right*float(size)*0.43f+vec3(0, size*0.4f, 0), vec3(0.f, 1.f, 0.f), right, size*0.5f, size*0.6f, texfaces[0], tint); + glm::vec3 right = glm::normalize(glm::vec3(1.f, 0.f, -1.f)); + batch->sprite(right*float(size)*0.43f+glm::vec3(0, size*0.4f, 0), + glm::vec3(0.f, 1.f, 0.f), + right, + size*0.5f, size*0.6f, + texfaces[0], + tint); break; } } diff --git a/src/frontend/ContentGfxCache.cpp b/src/frontend/ContentGfxCache.cpp index 72e039fb4..ff935f9ce 100644 --- a/src/frontend/ContentGfxCache.cpp +++ b/src/frontend/ContentGfxCache.cpp @@ -7,8 +7,6 @@ #include "../graphics/Atlas.h" #include "../voxels/Block.h" -using std::string; - ContentGfxCache::ContentGfxCache(const Content* content, Assets* assets) { const ContentIndices* contentIds = content->indices; sideregions = new UVRegion[contentIds->countBlockDefs() * 6]; @@ -17,7 +15,7 @@ ContentGfxCache::ContentGfxCache(const Content* content, Assets* assets) { for (uint i = 0; i < contentIds->countBlockDefs(); i++) { Block* def = contentIds->getBlockDef(i); for (uint side = 0; side < 6; side++) { - string tex = def->textureFaces[side]; + std::string tex = def->textureFaces[side]; if (atlas->has(tex)) { sideregions[i * 6 + side] = atlas->get(tex); } else { @@ -28,7 +26,6 @@ ContentGfxCache::ContentGfxCache(const Content* content, Assets* assets) { } } -ContentGfxCache::~ContentGfxCache() -{ +ContentGfxCache::~ContentGfxCache() { delete[] sideregions; } diff --git a/src/frontend/InventoryView.cpp b/src/frontend/InventoryView.cpp new file mode 100644 index 000000000..6685535fb --- /dev/null +++ b/src/frontend/InventoryView.cpp @@ -0,0 +1,104 @@ +#include "InventoryView.h" + +#include + +#include "BlocksPreview.h" +#include "../window/Events.h" +#include "../assets/Assets.h" +#include "../graphics/Shader.h" +#include "../graphics/Batch2D.h" +#include "../graphics/GfxContext.h" +#include "../content/Content.h" +#include "../maths/voxmaths.h" +#include "../objects/Player.h" +#include "../voxels/Block.h" + +InventoryView::InventoryView( + int columns, + Player* player, + const Assets* assets, + const ContentIndices* indices, + const ContentGfxCache* cache, + std::vector blocks) + : player(player), + assets(assets), + indices(indices), + cache(cache), + blocks(blocks), + invColumns(columns) { + blocksPreview = new BlocksPreview(assets->getShader("ui3d"), + assets->getAtlas("blocks"), + cache); +} + +void InventoryView::setPosition(int x, int y) { + this->invX = x; + this->invY = y; +} + +int InventoryView::getWidth() const { + return invColumns * iconSize + (invColumns-1) * interval + padX * 2; +} + +int InventoryView::getHeight() const { + uint inv_rows = ceildiv(blocks.size(), invColumns); + return inv_rows * iconSize + (inv_rows-1) * interval + padY * 2; +} + +void InventoryView::actAndDraw(const GfxContext* ctx) { + Shader* uiShader = assets->getShader("ui"); + + auto viewport = ctx->getViewport(); + uint inv_w = getWidth(); + uint inv_h = getHeight(); + int xs = invX + padX; + int ys = invY + padY; + + glm::vec4 tint (1.0f); + int mx = Events::cursor.x; + int my = Events::cursor.y; + + // background + auto batch = ctx->getBatch2D(); + batch->texture(nullptr); + batch->color = glm::vec4(0.0f, 0.0f, 0.0f, 0.5f); + batch->rect(invX, invY, inv_w, inv_h); + batch->render(); + + // blocks & items + if (Events::scroll) { + inventoryScroll -= Events::scroll * (iconSize+interval); + } + inventoryScroll = std::min(inventoryScroll, int(inv_h-viewport.getHeight())); + inventoryScroll = std::max(inventoryScroll, 0); + blocksPreview->begin(&ctx->getViewport()); + { + Window::clearDepth(); + GfxContext subctx = ctx->sub(); + subctx.depthTest(true); + subctx.cullFace(true); + uint index = 0; + for (uint i = 0; i < blocks.size(); i++) { + Block* cblock = indices->getBlockDef(blocks[i]); + int x = xs + (iconSize+interval) * (index % invColumns); + int y = ys + (iconSize+interval) * (index / invColumns) - inventoryScroll; + if (y < -int(iconSize+interval) || y >= int(viewport.getHeight())) { + index++; + continue; + } + if (mx > x && mx < x + (int)iconSize && my > y && my < y + (int)iconSize) { + tint.r *= 1.2f; + tint.g *= 1.2f; + tint.b *= 1.2f; + if (Events::jclicked(mousecode::BUTTON_1)) { + player->chosenBlock = blocks[i]; + } + } else { + tint = glm::vec4(1.0f); + } + blocksPreview->draw(cblock, x, y, iconSize, tint); + index++; + } + } + uiShader->use(); +} diff --git a/src/frontend/InventoryView.h b/src/frontend/InventoryView.h new file mode 100644 index 000000000..792fec428 --- /dev/null +++ b/src/frontend/InventoryView.h @@ -0,0 +1,45 @@ +#ifndef FRONTEND_INVENTORY_VIEW_H_ +#define FRONTEND_INVENTORY_VIEW_H_ + +#include + +#include "../typedefs.h" + +class Player; +class Assets; +class GfxContext; +class ContentIndices; +class BlocksPreview; +class ContentGfxCache; + +class InventoryView { + Player* player; + const Assets* assets; + const ContentIndices* indices; + const ContentGfxCache* const cache; + std::vector blocks; + BlocksPreview* blocksPreview; + + int inventoryScroll = 0; + int invColumns; + uint iconSize = 48; + uint interval = 4; + int padX = interval; + int padY = interval; + int invX = 0; + int invY = 0; +public: + InventoryView( + int columns, + Player* player, + const Assets* assets, + const ContentIndices* indices, + const ContentGfxCache* cache, + std::vector blocks); + void setPosition(int x, int y); + void actAndDraw(const GfxContext* ctx); + int getWidth() const; + int getHeight() const; +}; + +#endif // FRONTEND_INVENTORY_VIEW_H_ diff --git a/src/frontend/gui/controls.cpp b/src/frontend/gui/controls.cpp index 95ebf1c19..b4445d2f0 100644 --- a/src/frontend/gui/controls.cpp +++ b/src/frontend/gui/controls.cpp @@ -2,6 +2,7 @@ #include +#include "../../window/Events.h" #include "../../assets/Assets.h" #include "../../graphics/Batch2D.h" #include "../../graphics/Font.h" @@ -21,7 +22,9 @@ const uint KEY_BACKSPACE = 259; using namespace gui; Label::Label(wstring text, string fontName) - : UINode(vec2(), vec2(text.length() * 8, 15)), text_(text), fontName_(fontName) { + : UINode(vec2(), vec2(text.length() * 8, 15)), + text_(text), + fontName_(fontName) { } Label& Label::text(wstring text) { @@ -175,6 +178,13 @@ void TextBox::keyPressed(int key) { defocus(); break; } + // Pasting text from clipboard + if (key == keycode::V && Events::pressed(keycode::LEFT_CONTROL)) { + const char* text = Window::getClipboardText(); + if (text) { + input += util::str2wstr_utf8(text); + } + } } shared_ptr TextBox::getAt(vec2 pos, shared_ptr self) { diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index b86c21b01..7f441af50 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -38,6 +38,7 @@ #include "screens.h" #include "WorldRenderer.h" #include "BlocksPreview.h" +#include "InventoryView.h" #include "../engine.h" #include "../core_defs.h" @@ -59,13 +60,28 @@ HudRenderer::HudRenderer(Engine* engine, const ContentGfxCache* cache) : level(level), assets(engine->getAssets()), - batch(new Batch2D(1024)), gui(engine->getGUI()), cache(cache) { auto menu = gui->getMenu(); blocksPreview = new BlocksPreview(assets->getShader("ui3d"), assets->getAtlas("blocks"), cache); + auto content = level->content; + auto indices = content->indices; + std::vector blocks; + for (blockid_t id = 1; id < indices->countBlockDefs(); id++) { + const Block* def = indices->getBlockDef(id); + if (def->hidden) + continue; + blocks.push_back(id); + } + contentAccess.reset(new InventoryView( + 8, + level->player, + assets, + indices, + cache, + blocks)); uicamera = new Camera(vec3(), 1); uicamera->perspective = false; @@ -201,7 +217,6 @@ HudRenderer::HudRenderer(Engine* engine, HudRenderer::~HudRenderer() { gui->remove(debugPanel); delete blocksPreview; - delete batch; delete uicamera; } @@ -211,72 +226,6 @@ void HudRenderer::drawDebug(int fps){ fpsMax = max(fps, fpsMax); } -/* Inventory temporary replaced with blocks access panel */ -void HudRenderer::drawContentAccess(const GfxContext& ctx, Player* player) { - const Content* content = level->content; - const ContentIndices* contentIds = content->indices; - - const Viewport& viewport = ctx.getViewport(); - const uint width = viewport.getWidth(); - Shader* uiShader = assets->getShader("ui"); - - uint count = contentIds->countBlockDefs(); - uint icon_size = 48; - uint interval = 4; - uint inv_cols = 8; - uint inv_rows = ceildiv(count-1, inv_cols); - int pad_x = interval; - int pad_y = interval; - uint inv_w = inv_cols * icon_size + (inv_cols-1) * interval + pad_x * 2; - uint inv_h = inv_rows * icon_size + (inv_rows-1) * interval + pad_x * 2; - int inv_x = (width - (inv_w)); - int inv_y = 0; - int xs = inv_x + pad_x; - int ys = inv_y + pad_y; - - vec4 tint = vec4(1.0f); - int mx = Events::cursor.x; - int my = Events::cursor.y; - - // background - batch->texture(nullptr); - batch->color = vec4(0.0f, 0.0f, 0.0f, 0.5f); - batch->rect(inv_x, inv_y, inv_w, inv_h); - batch->render(); - - // blocks & items - blocksPreview->begin(&ctx.getViewport()); - { - Window::clearDepth(); - GfxContext subctx = ctx.sub(); - subctx.depthTest(true); - subctx.cullFace(true); - uint index = 0; - for (uint i = 0; i < count-1; i++) { - Block* cblock = contentIds->getBlockDef(i+1); - if (cblock == nullptr) - break; - if (cblock->hidden) - continue; - int x = xs + (icon_size+interval) * (index % inv_cols); - int y = ys + (icon_size+interval) * (index / inv_cols); - if (mx > x && mx < x + (int)icon_size && my > y && my < y + (int)icon_size) { - tint.r *= 1.2f; - tint.g *= 1.2f; - tint.b *= 1.2f; - if (Events::jclicked(mousecode::BUTTON_1)) { - player->chosenBlock = i+1; - } - } else { - tint = vec4(1.0f); - } - blocksPreview->draw(cblock, x, y, icon_size, tint); - index++; - } - } - uiShader->use(); -} - void HudRenderer::update() { auto menu = gui->getMenu(); if (pause && menu->current().panel == nullptr) { @@ -319,6 +268,7 @@ void HudRenderer::draw(const GfxContext& ctx){ uishader->use(); uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView()); + auto batch = ctx.getBatch2D(); batch->begin(); // Chosen block preview @@ -358,7 +308,8 @@ void HudRenderer::draw(const GfxContext& ctx){ batch->rect(0, 0, width, height); } if (inventoryOpen) { - drawContentAccess(ctx, player); + contentAccess->setPosition(viewport.getWidth()-contentAccess->getWidth(), 0); + contentAccess->actAndDraw(&ctx); } batch->render(); } @@ -369,4 +320,4 @@ bool HudRenderer::isInventoryOpen() const { bool HudRenderer::isPause() const { return pause; -} \ No newline at end of file +} diff --git a/src/frontend/hud.h b/src/frontend/hud.h index b7df12670..e2c7e2fac 100644 --- a/src/frontend/hud.h +++ b/src/frontend/hud.h @@ -8,7 +8,6 @@ #include "../graphics/GfxContext.h" -class Batch2D; class Camera; class Level; class Block; @@ -17,8 +16,8 @@ class Player; class Level; class Engine; class ContentGfxCache; -class WorldRenderer; class BlocksPreview; +class InventoryView; namespace gui { class GUI; @@ -28,7 +27,6 @@ namespace gui { class HudRenderer { Level* level; Assets* assets; - Batch2D* batch; Camera* uicamera; BlocksPreview* blocksPreview; @@ -39,6 +37,7 @@ class HudRenderer { bool inventoryOpen = false; bool pause = false; + std::unique_ptr contentAccess; std::shared_ptr debugPanel; gui::GUI* gui; const ContentGfxCache* const cache; @@ -49,7 +48,6 @@ public: ~HudRenderer(); void update(); - void drawContentAccess(const GfxContext& ctx, Player* player); void draw(const GfxContext& context); void drawDebug(int fps); diff --git a/src/frontend/menu.cpp b/src/frontend/menu.cpp index 6484bc0cf..e5600e500 100644 --- a/src/frontend/menu.cpp +++ b/src/frontend/menu.cpp @@ -14,7 +14,9 @@ #include "../util/stringutil.h" #include "../files/engine_paths.h" #include "../files/WorldConverter.h" +#include "../files/WorldFiles.h" #include "../world/World.h" +#include "../world/Level.h" #include "../window/Events.h" #include "../window/Window.h" #include "../engine.h" @@ -175,8 +177,18 @@ void open_world(std::string name, Engine* engine) { show_convert_request(engine, content, lut, folder); } } else { - Level* level = World::load(folder, settings, content, packs); - engine->setScreen(std::make_shared(engine, level)); + // TODO: remove in 0.18 + 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(engine, level)); + } } } diff --git a/src/frontend/screens.cpp b/src/frontend/screens.cpp index 73edad59c..f14e9e25c 100644 --- a/src/frontend/screens.cpp +++ b/src/frontend/screens.cpp @@ -41,20 +41,24 @@ using glm::vec3; using glm::vec4; using std::shared_ptr; +Screen::Screen(Engine* engine) : engine(engine), batch(new Batch2D(1024)) { +} + +Screen::~Screen() { +} + MenuScreen::MenuScreen(Engine* engine_) : Screen(engine_) { auto menu = engine->getGUI()->getMenu(); menus::refresh_menus(engine, menu); menu->reset(); menu->set("main"); - batch = new Batch2D(1024); uicamera = new Camera(vec3(), Window::height); uicamera->perspective = false; uicamera->flipped = true; } MenuScreen::~MenuScreen() { - delete batch; delete uicamera; } @@ -155,7 +159,7 @@ void LevelScreen::draw(float delta) { Camera* camera = level->player->currentViewCamera; Viewport viewport(Window::width, Window::height); - GfxContext ctx(nullptr, viewport, nullptr); + GfxContext ctx(nullptr, viewport, batch.get()); worldRenderer->draw(ctx, camera); diff --git a/src/frontend/screens.h b/src/frontend/screens.h index e8b3f9636..73991d8d7 100644 --- a/src/frontend/screens.h +++ b/src/frontend/screens.h @@ -18,15 +18,15 @@ class LevelController; class Screen { protected: Engine* engine; + std::unique_ptr batch; public: - Screen(Engine* engine) : engine(engine) {}; - virtual ~Screen() {}; + Screen(Engine* engine); + virtual ~Screen(); virtual void update(float delta) = 0; virtual void draw(float delta) = 0; }; class MenuScreen : public Screen { - Batch2D* batch; Camera* uicamera; public: MenuScreen(Engine* engine); @@ -42,6 +42,7 @@ class LevelScreen : public Screen { WorldRenderer* worldRenderer; HudRenderer* hud; ContentGfxCache* cache; + bool hudVisible = true; void updateHotkeys(); public: diff --git a/src/graphics/ImageData.cpp b/src/graphics/ImageData.cpp index a70f24fa7..8911884b4 100644 --- a/src/graphics/ImageData.cpp +++ b/src/graphics/ImageData.cpp @@ -82,9 +82,39 @@ void ImageData::flipY() { } void ImageData::blit(const ImageData* image, int x, int y) { - if (format != image->format) { - throw std::runtime_error("mismatching format"); + if (format == image->format) { + blitMatchingFormat(image, x, y); + return; } + if (format == ImageFormat::rgba8888 && + image->format == ImageFormat::rgb888) { + blitRGB_on_RGBA(image, x, y); + return; + } + throw std::runtime_error("mismatching format"); +} + +void ImageData::blitRGB_on_RGBA(const ImageData* image, int x, int y) { + ubyte* pixels = static_cast(data); + ubyte* source = static_cast(image->getData()); + uint srcwidth = image->getWidth(); + uint srcheight = image->getHeight(); + + for (uint srcy = max(0, -y); (int)srcy < min(srcheight, height-y); srcy++) { + for (uint srcx = max(0, -x); (int)srcx < min(srcwidth, width-x); srcx++) { + uint dstx = srcx + x; + uint dsty = srcy + y; + uint dstidx = (dsty * width + dstx) * 4; + uint srcidx = (srcy * srcwidth + srcx) * 3; + for (uint c = 0; c < 3; c++) { + pixels[dstidx + c] = source[srcidx + c]; + } + pixels[dstidx + 3] = 255; + } + } +} + +void ImageData::blitMatchingFormat(const ImageData* image, int x, int y) { uint comps; switch (format) { case ImageFormat::rgb888: comps = 3; break; diff --git a/src/graphics/ImageData.h b/src/graphics/ImageData.h index b7f73c01f..4defdb74b 100644 --- a/src/graphics/ImageData.h +++ b/src/graphics/ImageData.h @@ -21,6 +21,8 @@ public: void flipX(); void flipY(); + void blitRGB_on_RGBA(const ImageData* image, int x, int y); + void blitMatchingFormat(const ImageData* image, int x, int y); void blit(const ImageData* image, int x, int y); void extrude(int x, int y, int w, int h); void fixAlphaColor(); diff --git a/src/logic/BlocksController.cpp b/src/logic/BlocksController.cpp index 77f8bb664..ac74f6142 100644 --- a/src/logic/BlocksController.cpp +++ b/src/logic/BlocksController.cpp @@ -70,7 +70,7 @@ void BlocksController::updateBlock(int x, int y, int z) { if (vox == nullptr) return; const Block* def = level->content->indices->getBlockDef(vox->id); - if (def->grounded && !chunks->isSolid(x, y-1, z)) { + if (def->grounded && !chunks->isSolidBlock(x, y-1, z)) { breakBlock(nullptr, def, x, y, z); return; } diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index a72ab4958..2dc7faa72 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -281,7 +281,7 @@ void PlayerController::updateInteraction(){ if (!level->physics->isBlockInside(x,y,z, player->hitbox) || !def->obstacle){ Block* def = contentIds->getBlockDef(chosenBlock); - if (def->grounded && !chunks->isSolid(x, y-1, z)) { + if (def->grounded && !chunks->isSolidBlock(x, y-1, z)) { chosenBlock = 0; } if (chosenBlock != vox->id) { diff --git a/src/logic/scripting/api_lua.cpp b/src/logic/scripting/api_lua.cpp index 90134fcfd..1e2048695 100644 --- a/src/logic/scripting/api_lua.cpp +++ b/src/logic/scripting/api_lua.cpp @@ -23,7 +23,7 @@ int l_is_solid_at(lua_State* L) { int y = lua_tointeger(L, 2); int z = lua_tointeger(L, 3); - lua_pushboolean(L, scripting::level->chunks->isSolid(x, y, z)); + lua_pushboolean(L, scripting::level->chunks->isSolidBlock(x, y, z)); return 1; } @@ -60,6 +60,13 @@ int l_get_block(lua_State* L) { 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_player_pos(lua_State* L) { glm::vec3 pos = scripting::level->player->hitbox->position; lua_pushnumber(L, pos.x); @@ -103,12 +110,13 @@ int l_get_block_states(lua_State* L) { return 1; } + int l_is_replaceable_at(lua_State* L) { int x = lua_tointeger(L, 1); int y = lua_tointeger(L, 2); int z = lua_tointeger(L, 3); - lua_pushboolean(L, scripting::level->chunks->isReplaceable(x, y, z)); + lua_pushboolean(L, scripting::level->chunks->isReplaceableBlock(x, y, z)); return 1; } @@ -227,6 +235,7 @@ inline int lua_pushivec3(lua_State* L, int x, int y, int z) { 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); @@ -288,6 +297,9 @@ void apilua::create_funcs(lua_State* L) { lua_addfunc(L, l_is_replaceable_at, "is_replaceable_at"); lua_addfunc(L, l_set_block, "set_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_set_player_pos, "set_player_pos"); lua_addfunc(L, l_get_player_rot, "get_player_rot"); @@ -306,4 +318,6 @@ void apilua::create_funcs(lua_State* L) { 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_block_custom_bits, "get_block_custom_bits"); + lua_addfunc(L, l_set_block_custom_bits, "set_block_custom_bits"); } diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index da4fdbd7f..e4e1c3551 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -53,10 +53,14 @@ void scripting::initialize(EnginePaths* paths) { if (L == nullptr) { throw std::runtime_error("could not to initialize Lua"); } + + // Allowed standard libraries luaopen_base(L); luaopen_math(L); - luaopen_table(L); luaopen_string(L); + luaopen_table(L); + + // io-manipulations will be implemented via api functions std::cout << LUA_VERSION << std::endl; # ifdef LUAJIT_VERSION diff --git a/src/maths/aabb.h b/src/maths/aabb.h index 7f790b59f..93b90e0f7 100644 --- a/src/maths/aabb.h +++ b/src/maths/aabb.h @@ -48,7 +48,7 @@ struct AABB { } /* Check if given point is inside */ - inline bool inside(const glm::vec3 pos) const { + inline bool contains(const glm::vec3 pos) const { const glm::vec3 p = min(); const glm::vec3 s = size(); return !(pos.x < p.x || pos.y < p.y || pos.z < p.z || diff --git a/src/maths/rays.cpp b/src/maths/rays.cpp index 2e358bcf1..d898ac4b8 100644 --- a/src/maths/rays.cpp +++ b/src/maths/rays.cpp @@ -4,8 +4,7 @@ #include "glm/glm.hpp" -std::unordered_map Ray::raysBoxCache_ = {}; -const rayvec3 X_AXIS = rayvec3(1,0,0), Y_AXIS = rayvec3(0,1,0), Z_AXIS = rayvec3(0,0,1); +static const rayvec3 X_AXIS = rayvec3(1,0,0), Y_AXIS = rayvec3(0,1,0), Z_AXIS = rayvec3(0,0,1); Ray::Ray(const rayvec3& origin, const rayvec3& dir) : origin(origin), dir(dir) {} @@ -17,21 +16,21 @@ AABBFaces::AABBFaces(const rayvec3& parentBoxPos, const AABB& parentBox){ rayvec2 yzMax = rayvec2(parentBoxPos.y + pbMax.y, parentBoxPos.z + pbMax.z ), xzMax = rayvec2(parentBoxPos.x + pbMax.x, parentBoxPos.z + pbMax.z ), xyMax = rayvec2(parentBoxPos.x + pbMax.x, parentBoxPos.y + pbMax.y ); - faces[0] = {pbRealPos, yzMax}; //in order of AABBFaces::KINDS_ORDER! + faces[0] = { parentBoxPos + rayvec3(pbMax.x, pbMin.y, pbMin.z), yzMax }; - faces[1] = {parentBoxPos + rayvec3(pbMax.x, pbMin.y, pbMin.z), yzMax}; + faces[1] = {pbRealPos, yzMax}; - faces[2] = {pbRealPos, xzMax}; + faces[2] = { parentBoxPos + rayvec3(pbMin.x, pbMax.y, pbMin.z), xzMax }; - faces[3] = {parentBoxPos + rayvec3(pbMin.x, pbMax.y, pbMin.z), xzMax}; + faces[3] = {pbRealPos, xzMax}; - faces[4] = {pbRealPos, xyMax}; + faces[4] = { parentBoxPos + rayvec3(pbMin.x, pbMin.y, pbMax.z), xyMax }; + + faces[5] = {pbRealPos, xyMax}; - faces[5] = {parentBoxPos + rayvec3(pbMin.x, pbMin.y, pbMax.z), xyMax}; } -template <> -RayRelation Ray::intersectAAFace( +RayRelation Ray::intersectYZFace( const rayvec3& faceMin, const rayvec2& faceOppositeCorner, //y and z global coords of opposite corner glm::ivec3& normal_ret, @@ -59,8 +58,7 @@ RayRelation Ray::intersectAAFace( return RayRelation::None; } -template <> -RayRelation Ray::intersectAAFace( +RayRelation Ray::intersectXZFace( const rayvec3& faceMin, const rayvec2& faceOppositeCorner, //x and z global coords of opposite corner glm::ivec3& normal_ret, @@ -88,8 +86,7 @@ RayRelation Ray::intersectAAFace( return RayRelation::None; } -template <> -RayRelation Ray::intersectAAFace( +RayRelation Ray::intersectXYFace( const rayvec3& faceMin, const rayvec2& faceOppositeCorner, //x and y global coords of opposite corner glm::ivec3& normal_ret, @@ -117,8 +114,7 @@ RayRelation Ray::intersectAAFace( return RayRelation::None; } -template <> -RayRelation Ray::isIntersectsAAFace( +RayRelation Ray::isIntersectsYZFace( const rayvec3& faceMin, const rayvec2& faceOppositeCorner ){ @@ -141,8 +137,7 @@ RayRelation Ray::isIntersectsAAFace( return RayRelation::None; } -template <> -RayRelation Ray::isIntersectsAAFace( +RayRelation Ray::isIntersectsXZFace( const rayvec3& faceMin, const rayvec2& faceOppositeCorner ) { @@ -165,8 +160,7 @@ RayRelation Ray::isIntersectsAAFace( return RayRelation::None; } -template <> -RayRelation Ray::isIntersectsAAFace( +RayRelation Ray::isIntersectsXYFace( const rayvec3& faceMin, const rayvec2& faceOppositeCorner ) { @@ -195,29 +189,15 @@ RayRelation Ray::intersectAABB( float maxDist, glm::ivec3& normal_ret, scalar_t& distance_ret){ - if constexpr (IS_RAYS_BOX_CACHE_ON){ - - if (raysBoxCache_.find(boxPos) != raysBoxCache_.end()){ - const AABBFaces& boxFaces = raysBoxCache_[boxPos]; - return intersectAABBFaces(boxFaces, maxDist, normal_ret, distance_ret); - } else { - const AABBFaces& boxFaces = AABBFaces(boxPos, box); - raysBoxCache_[boxPos] = boxFaces; - return intersectAABBFaces(boxFaces, maxDist, normal_ret, distance_ret); - } - - } else { - const AABBFaces& boxFaces = AABBFaces(boxPos, box); - return intersectAABBFaces(boxFaces, maxDist, normal_ret, distance_ret); - } - + const AABBFaces& boxFaces = AABBFaces(boxPos, box); + return intersectAABBFaces(boxFaces, maxDist, normal_ret, distance_ret); } RayRelation Ray::intersectAABBFaces( const AABBFaces& boxFaces, float maxDist, glm::ivec3& normal_ret, - scalar_t& distance_ret){//TODO: points returning + scalar_t& distance_ret){ scalar_t faceDist; distance_ret = maxDist; @@ -225,7 +205,7 @@ RayRelation Ray::intersectAABBFaces( //unsigned char intersectedCount = 0; //this code is very uncomfortable, DONT LEARN IT! bool isIntersect = false; - if (intersectAAFace( + if (intersectYZFace( boxFaces.faces[0].first, boxFaces.faces[0].second, bufNormal, faceDist ) > RayRelation::None && faceDist < distance_ret){ isIntersect = true; @@ -233,7 +213,7 @@ RayRelation Ray::intersectAABBFaces( distance_ret = faceDist; } - if (intersectAAFace( + if (intersectYZFace( boxFaces.faces[1].first, boxFaces.faces[1].second, bufNormal, faceDist ) > RayRelation::None && faceDist < distance_ret) { isIntersect = true; @@ -241,7 +221,7 @@ RayRelation Ray::intersectAABBFaces( distance_ret = faceDist; } - if (intersectAAFace( + if (intersectXZFace( boxFaces.faces[2].first, boxFaces.faces[2].second, bufNormal, faceDist ) > RayRelation::None && faceDist < distance_ret) { isIntersect = true; @@ -249,7 +229,7 @@ RayRelation Ray::intersectAABBFaces( distance_ret = faceDist; } - if (intersectAAFace( + if (intersectXZFace( boxFaces.faces[3].first, boxFaces.faces[3].second, bufNormal, faceDist ) > RayRelation::None && faceDist < distance_ret) { isIntersect = true; @@ -257,7 +237,7 @@ RayRelation Ray::intersectAABBFaces( distance_ret = faceDist; } - if (intersectAAFace( + if (intersectXYFace( boxFaces.faces[4].first, boxFaces.faces[4].second, bufNormal, faceDist ) > RayRelation::None && faceDist < distance_ret) { isIntersect = true; @@ -265,7 +245,7 @@ RayRelation Ray::intersectAABBFaces( distance_ret = faceDist; } - if (intersectAAFace( + if (intersectXYFace( boxFaces.faces[5].first, boxFaces.faces[5].second, bufNormal, faceDist ) > RayRelation::None && faceDist < distance_ret) { isIntersect = true; diff --git a/src/maths/rays.h b/src/maths/rays.h index 47e8d5d7f..1ee94e8b7 100644 --- a/src/maths/rays.h +++ b/src/maths/rays.h @@ -8,7 +8,6 @@ #include "glm/gtx/hash.hpp" #include -#include typedef glm::highp_dvec3 rayvec3; typedef glm::highp_dvec2 rayvec2; @@ -17,31 +16,18 @@ typedef double scalar_t; enum class RayRelation{ Embed=2, Intersect=1, Parallel=0, None=0 }; -enum class AAFaceKind : unsigned char{ - Xperp=0, Yperp=1, Zperp=2 //perpendicular faces to corresponding axis -}; - -const unsigned char AABBFACES_COUNT = 6; class AABBFaces{ + static const unsigned char AABBFACES_COUNT = 6; public: std::array, AABBFACES_COUNT> faces; // every face is min-point and opposite corner point - static constexpr std::array KINDS_ORDER = { - AAFaceKind::Xperp, AAFaceKind::Xperp, - AAFaceKind::Yperp, AAFaceKind::Yperp, - AAFaceKind::Zperp, AAFaceKind::Zperp}; - AABBFaces(){}; AABBFaces(const rayvec3& parentBoxPos, const AABB& parentBox); }; class Ray{ -protected: - static const bool IS_RAYS_BOX_CACHE_ON = false; // Now not working properly because not observe updates - static std::unordered_map raysBoxCache_; //[boxPos]: faces array - public: rayvec3 origin; rayvec3 dir; @@ -49,39 +35,32 @@ public: Ray(const rayvec3& rayOrigin, const rayvec3& rayDir); -//optimized, NOT returns intersectPoint coordinates and normal vector - template - RayRelation isIntersectsAAFace( - const rayvec3& faceMin, - const rayvec2& faceOppositeCorner - ); - -//returns only normal - template - RayRelation intersectAAFace( - const rayvec3& faceMin, - const rayvec2& faceOppositeCorner, - glm::ivec3& normal_ret - ); + RayRelation isIntersectsYZFace( + const rayvec3& faceMin, + const rayvec2& faceOppositeCorner); + RayRelation isIntersectsXZFace( + const rayvec3& faceMin, + const rayvec2& faceOppositeCorner); + RayRelation isIntersectsXYFace( + const rayvec3& faceMin, + const rayvec2& faceOppositeCorner); //returns normal and distance - template - RayRelation intersectAAFace( - const rayvec3& faceMin, - const rayvec2& faceOppositeCorner, - glm::ivec3& normal_ret, - scalar_t& distance_ret - ); - -// returns normal, distance and intersection point - template - RayRelation intersectAAFace( - const rayvec3& faceMin, - const rayvec2& faceOppositeCorner, - glm::ivec3& normal_ret, - scalar_t& distance_ret, - rayvec3& intersectPoint_ret - ); + RayRelation intersectYZFace( + const rayvec3& faceMin, + const rayvec2& faceOppositeCorner, + glm::ivec3& normal_ret, + scalar_t& distance_ret); + RayRelation intersectXZFace( + const rayvec3& faceMin, + const rayvec2& faceOppositeCorner, + glm::ivec3& normal_ret, + scalar_t& distance_ret); + RayRelation intersectXYFace( + const rayvec3& faceMin, + const rayvec2& faceOppositeCorner, + glm::ivec3& normal_ret, + scalar_t& distance_ret); RayRelation intersectAABB( const rayvec3& boxPos, diff --git a/src/physics/PhysicsSolver.cpp b/src/physics/PhysicsSolver.cpp index a8b8f09ae..6171412bf 100644 --- a/src/physics/PhysicsSolver.cpp +++ b/src/physics/PhysicsSolver.cpp @@ -46,7 +46,7 @@ void PhysicsSolver::step( hitbox->grounded = false; for (float x = (px-half.x+E); x <= (px+half.x-E); x+=s){ for (float z = (pos.z-half.z+E); z <= (pos.z+half.z-E); z+=s){ - if (chunks->isObstacle(x,y,z)){ + if (chunks->isObstacleAt(x,y,z)){ hitbox->grounded = true; break; } @@ -58,7 +58,7 @@ void PhysicsSolver::step( hitbox->grounded = false; for (float x = (pos.x-half.x+E); x <= (pos.x+half.x-E); x+=s){ for (float z = (pz-half.z+E); z <= (pz+half.z-E); z+=s){ - if (chunks->isObstacle(x,y,z)){ + if (chunks->isObstacleAt(x,y,z)){ hitbox->grounded = true; break; } @@ -88,7 +88,7 @@ void PhysicsSolver::colisionCalc( for (float y = (pos.y-half.y+E); y <= (pos.y+half.y-E); y+=s){ for (float z = (pos.z-half.z+E); z <= (pos.z+half.z-E); z+=s){ float x = (pos.x-half.x-E); - if ((aabb = chunks->isObstacle(x,y,z))){ + if ((aabb = chunks->isObstacleAt(x,y,z))){ vel.x *= 0.0f; pos.x = floor(x) + aabb->max().x + half.x + E; break; @@ -100,7 +100,7 @@ void PhysicsSolver::colisionCalc( for (float y = (pos.y-half.y+E); y <= (pos.y+half.y-E); y+=s){ for (float z = (pos.z-half.z+E); z <= (pos.z+half.z-E); z+=s){ float x = (pos.x+half.x+E); - if ((aabb = chunks->isObstacle(x,y,z))){ + if ((aabb = chunks->isObstacleAt(x,y,z))){ vel.x *= 0.0f; pos.x = floor(x) - half.x + aabb->min().x - E; break; @@ -113,7 +113,7 @@ void PhysicsSolver::colisionCalc( for (float y = (pos.y-half.y+E); y <= (pos.y+half.y-E); y+=s){ for (float x = (pos.x-half.x+E); x <= (pos.x+half.x-E); x+=s){ float z = (pos.z-half.z-E); - if ((aabb = chunks->isObstacle(x,y,z))){ + if ((aabb = chunks->isObstacleAt(x,y,z))){ vel.z *= 0.0f; pos.z = floor(z) + aabb->max().z + half.z + E; break; @@ -126,7 +126,7 @@ void PhysicsSolver::colisionCalc( for (float y = (pos.y-half.y+E); y <= (pos.y+half.y-E); y+=s){ for (float x = (pos.x-half.x+E); x <= (pos.x+half.x-E); x+=s){ float z = (pos.z+half.z+E); - if ((aabb = chunks->isObstacle(x,y,z))){ + if ((aabb = chunks->isObstacleAt(x,y,z))){ vel.z *= 0.0f; pos.z = floor(z) - half.z + aabb->min().z - E; break; @@ -139,7 +139,7 @@ void PhysicsSolver::colisionCalc( for (float x = (pos.x-half.x+E); x <= (pos.x+half.x-E); x+=s){ for (float z = (pos.z-half.z+E); z <= (pos.z+half.z-E); z+=s){ float y = (pos.y-half.y-E); - if ((aabb = chunks->isObstacle(x,y,z))){ + if ((aabb = chunks->isObstacleAt(x,y,z))){ vel.y *= 0.0f; pos.y = floor(y) + aabb->max().y + half.y; hitbox->grounded = true; @@ -152,7 +152,7 @@ void PhysicsSolver::colisionCalc( for (float x = (pos.x-half.x+E); x <= (pos.x+half.x-E); x+=s){ for (float z = (pos.z-half.z+E); z <= (pos.z+half.z-E); z+=s){ float y = (pos.y+half.y+E); - if ((aabb = chunks->isObstacle(x,y,z))){ + if ((aabb = chunks->isObstacleAt(x,y,z))){ vel.y *= 0.0f; pos.y = floor(y) - half.y + aabb->min().y - E; break; diff --git a/src/typedefs.h b/src/typedefs.h index f3ae879bd..369fdaf45 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -10,11 +10,8 @@ typedef uint16_t u_short16; typedef uint32_t u_int32; typedef uint64_t u_long64; -// typedef unsigned int uint; -// typedef unsigned short ushort; -// typedef unsigned char ubyte; - typedef uint16_t blockid_t; +typedef uint16_t blockstate_t; typedef uint16_t light_t; #endif diff --git a/src/util/command_line.cpp b/src/util/command_line.cpp index 05b093521..097b58c3d 100644 --- a/src/util/command_line.cpp +++ b/src/util/command_line.cpp @@ -4,42 +4,36 @@ namespace fs = std::filesystem; -using std::filesystem::path; -using std::string; -using std::cout; -using std::cerr; -using std::endl; - bool parse_cmdline(int argc, char** argv, EnginePaths& paths) { ArgsReader reader(argc, argv); reader.skip(); while (reader.hasNext()) { - string token = reader.next(); + std::string token = reader.next(); if (reader.isKeywordArg()) { if (token == "--res") { token = reader.next(); - if (!fs::is_directory(path(token))) { + if (!fs::is_directory(fs::path(token))) { throw std::runtime_error(token+" is not a directory"); } - paths.setResources(path(token)); - cout << "resources folder: " << token << std::endl; + paths.setResources(fs::path(token)); + std::cout << "resources folder: " << token << std::endl; } else if (token == "--dir") { token = reader.next(); - if (!fs::is_directory(path(token))) { - fs::create_directories(path(token)); + if (!fs::is_directory(fs::path(token))) { + fs::create_directories(fs::path(token)); } - paths.setUserfiles(path(token)); - cout << "userfiles folder: " << token << endl; + paths.setUserfiles(fs::path(token)); + std::cout << "userfiles folder: " << token << std::endl; } else if (token == "--help" || token == "-h") { - cout << "VoxelEngine command-line arguments:" << endl; - cout << " --res [path] - set resources directory" << endl; - cout << " --dir [path] - set userfiles directory" << endl; + std::cout << "VoxelEngine command-line arguments:" << std::endl; + std::cout << " --res [path] - set resources directory" << std::endl; + std::cout << " --dir [path] - set userfiles directory" << std::endl; return false; } else { - cerr << "unknown argument " << token << endl; + std::cerr << "unknown argument " << token << std::endl; } } else { - cerr << "unexpected token" << endl; + std::cerr << "unexpected token" << std::endl; } } return true; diff --git a/src/util/stringutil.cpp b/src/util/stringutil.cpp index 30cef9d45..b423f6245 100644 --- a/src/util/stringutil.cpp +++ b/src/util/stringutil.cpp @@ -6,17 +6,11 @@ #include #include -using std::vector; -using std::string; -using std::stringstream; -using std::wstring; -using std::wstringstream; - -wstring util::lfill(wstring s, uint length, wchar_t c) { +std::wstring util::lfill(std::wstring s, uint length, wchar_t c) { if (s.length() >= length) { return s; } - wstringstream ss; + std::wstringstream ss; for (uint i = 0; i < length-s.length(); i++) { ss << c; } @@ -24,11 +18,11 @@ wstring util::lfill(wstring s, uint length, wchar_t c) { return ss.str(); } -wstring util::rfill(wstring s, uint length, wchar_t c) { +std::wstring util::rfill(std::wstring s, uint length, wchar_t c) { if (s.length() >= length) { return s; } - wstringstream ss; + std::wstringstream ss; ss << s; for (uint i = 0; i < length-s.length(); i++) { ss << c; @@ -103,8 +97,8 @@ extern uint32_t util::decode_utf8(uint& size, const char* chr) { return code; } -string util::wstr2str_utf8(const wstring ws) { - vector chars; +std::string util::wstr2str_utf8(const std::wstring ws) { + std::vector chars; char buffer[4]; for (wchar_t wc : ws) { uint size = encode_utf8((uint)wc, (u_char8*)buffer); @@ -112,21 +106,21 @@ string util::wstr2str_utf8(const wstring ws) { chars.push_back(buffer[i]); } } - return string(chars.data(), chars.size()); + return std::string(chars.data(), chars.size()); } -wstring util::str2wstr_utf8(const string s) { - vector chars; +std::wstring util::str2wstr_utf8(const std::string s) { + std::vector chars; size_t pos = 0; uint size = 0; while (pos < s.length()) { chars.push_back(decode_utf8(size, &s.at(pos))); pos += size; } - return wstring(chars.data(), chars.size()); + return std::wstring(chars.data(), chars.size()); } -bool util::is_integer(string text) { +bool util::is_integer(std::string text) { for (char c : text) { if (c < '0' || c > '9') return false; @@ -134,7 +128,7 @@ bool util::is_integer(string text) { return true; } -bool util::is_integer(wstring text) { +bool util::is_integer(std::wstring text) { for (wchar_t c : text) { if (c < L'0' || c > L'9') return false; diff --git a/src/voxels/Block.cpp b/src/voxels/Block.cpp index 3b148d985..0b3491bd8 100644 --- a/src/voxels/Block.cpp +++ b/src/voxels/Block.cpp @@ -23,13 +23,13 @@ void CoordSystem::transform(AABB& aabb) const { aabb.b += fix; } -const BlockRotProfile BlockRotProfile::PIPE {"pipe", {//TODO consexpr or init-time fix calculations +const BlockRotProfile BlockRotProfile::PIPE {"pipe", { { { 1, 0, 0 }, { 0, 0, 1 }, { 0, -1, 0 }}, // North { { 0, 0, 1 }, {-1, 0, 0 }, { 0, -1, 0 }}, // East - { { -1, 0, 0 }, { 0, 0,-1 }, { 0, -1, 0 }}, // South - { { 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }}, // West - { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }}, // Up - { { 1, 0, 0 }, { 0,-1, 0 }, { 0, 0,-1 }}, // Down + { {-1, 0, 0 }, { 0, 0,-1 }, { 0, -1, 0 }}, // South + { { 0, 0,-1 }, { 1, 0, 0 }, { 0, -1, 0 }}, // West + { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }}, // Up + { { 1, 0, 0 }, { 0,-1, 0 }, { 0, 0,-1 }}, // Down }}; const BlockRotProfile BlockRotProfile::PANE {"pane", { diff --git a/src/voxels/Block.h b/src/voxels/Block.h index 98214be76..80b6d35c8 100644 --- a/src/voxels/Block.h +++ b/src/voxels/Block.h @@ -47,7 +47,7 @@ struct CoordSystem { }; struct BlockRotProfile { - static const int MAX_COUNT = 16; + static const int MAX_COUNT = 8; std::string name; CoordSystem variants[MAX_COUNT]; diff --git a/src/voxels/Chunk.cpp b/src/voxels/Chunk.cpp index 611108c6e..f0c7b6747 100644 --- a/src/voxels/Chunk.cpp +++ b/src/voxels/Chunk.cpp @@ -1,4 +1,7 @@ #include "Chunk.h" + +#include + #include "voxel.h" #include "../content/ContentLUT.h" #include "../lighting/Lightmap.h" @@ -22,7 +25,7 @@ Chunk::~Chunk(){ bool Chunk::isEmpty(){ 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 (id != -1) return false; @@ -34,14 +37,14 @@ bool Chunk::isEmpty(){ } 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) { bottom = i / (CHUNK_D * CHUNK_W); break; } } - for (int i = CHUNK_VOL - 1; i > -1; i--) { + for (int i = CHUNK_VOL - 1; i >= 0; i--) { if (voxels[i].id != 0) { top = i / (CHUNK_D * CHUNK_W) + 1; break; @@ -51,7 +54,7 @@ void Chunk::updateHeights() { Chunk* Chunk::clone() const { 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->lightmap->set(lightmap); return other; @@ -59,32 +62,68 @@ Chunk* Chunk::clone() const { /** 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 */ u_char8* Chunk::encode() const { u_char8* buffer = new u_char8[CHUNK_DATA_LEN]; for (size_t i = 0; i < CHUNK_VOL; i++) { - ((u_short16*)buffer)[i] = voxels[i].id; - ((u_short16*)buffer)[CHUNK_VOL + i] = voxels[i].states; + 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; } /** - @return true if all is fine -*/ +/** + * @return true if all is fine + **/ bool Chunk::decode(u_char8* data) { for (size_t i = 0; i < CHUNK_VOL; i++) { voxel& vox = voxels[i]; - vox.id = ((u_short16*)data)[i]; - vox.states = ((u_short16*)data)[CHUNK_VOL + i]; + + u_char8 bid1 = data[i]; + u_char8 bid2 = data[CHUNK_VOL + i]; + + u_char8 bst1 = data[CHUNK_VOL*2 + i]; + u_char8 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; } -void Chunk::convert(u_char8* data, const ContentLUT* lut) { +/* + * Convert chunk voxels data from 16 bit to 32 bit + */ +void Chunk::fromOld(u_char8* data) { for (size_t i = 0; i < CHUNK_VOL; i++) { - blockid_t id = ((u_short16*)data)[i]; - ((u_short16*)data)[i] = lut->getBlockId(id); + data[i + CHUNK_VOL*3] = data[i + CHUNK_VOL]; + data[i + CHUNK_VOL] = data[i]; + data[i + CHUNK_VOL*2] = 0; + data[i] = 0; + } +} + +void Chunk::convert(u_char8* 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; } } diff --git a/src/voxels/Chunk.h b/src/voxels/Chunk.h index 36d38683d..768f552f0 100644 --- a/src/voxels/Chunk.h +++ b/src/voxels/Chunk.h @@ -78,6 +78,7 @@ public: u_char8* encode() const; bool decode(u_char8* data); + static void fromOld(u_char8* data); static void convert(u_char8* data, const ContentLUT* lut); }; diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index def75ccbe..cded6e86f 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -45,17 +45,15 @@ Chunks::~Chunks(){ chunks[i] = nullptr; } delete[] chunks; + delete[] chunksSecond; } voxel* Chunks::get(int x, int y, int z){ x -= ox * CHUNK_W; z -= oz * CHUNK_D; - int cx = x / CHUNK_W; - int cy = y / CHUNK_H; - int cz = z / CHUNK_D; - if (x < 0) cx--; - if (y < 0) cy--; - if (z < 0) cz--; + int cx = floordiv(x, CHUNK_W); + int cy = floordiv(y, CHUNK_H); + int cz = floordiv(z, CHUNK_D); if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= 1 || cz >= d) return nullptr; shared_ptr chunk = chunks[cz * w + cx]; // chunks is 2D-array @@ -67,7 +65,7 @@ voxel* Chunks::get(int x, int y, int z){ return &chunk->voxels[(ly * CHUNK_D + lz) * CHUNK_W + lx]; } -const AABB* Chunks::isObstacle(float x, float y, float z){ +const AABB* Chunks::isObstacleAt(float x, float y, float z){ int ix = floor(x); int iy = floor(y); int iz = floor(z); @@ -82,7 +80,7 @@ const AABB* Chunks::isObstacle(float x, float y, float z){ if (def->rt.solid) { return &hitbox; } else { - if (hitbox.inside({x - ix, y - iy, z - iz})) + if (hitbox.contains({x - ix, y - iy, z - iz})) return &hitbox; return nullptr; } @@ -90,20 +88,27 @@ const AABB* Chunks::isObstacle(float x, float y, float z){ return nullptr; } -bool Chunks::isSolid(int x, int y, int z) { +bool Chunks::isSolidBlock(int x, int y, int z) { voxel* v = get(x, y, z); if (v == nullptr) return false; return contentIds->getBlockDef(v->id)->rt.solid; } -bool Chunks::isReplaceable(int x, int y, int z) { +bool Chunks::isReplaceableBlock(int x, int y, int z) { voxel* v = get(x, y, z); if (v == nullptr) return false; return contentIds->getBlockDef(v->id)->replaceable; } +bool Chunks::isObstacleBlock(int x, int y, int z) { + voxel* v = get(x, y, z); + if (v == nullptr) + return false; + return contentIds->getBlockDef(v->id)->obstacle; +} + u_char8 Chunks::getLight(int x, int y, int z, int channel){ x -= ox * CHUNK_W; z -= oz * CHUNK_D; @@ -233,7 +238,7 @@ voxel* Chunks::rayCast(vec3 start, while (t <= maxDist){ voxel* voxel = get(ix, iy, iz); - if (!voxel){ return nullptr; } + if (voxel == nullptr){ return nullptr; } const Block* def = contentIds->getBlockDef(voxel->id); if (def->selectable){ @@ -338,7 +343,7 @@ vec3 Chunks::rayCastToObstacle(vec3 start, vec3 dir, float maxDist) { while (t <= maxDist) { voxel* voxel = get(ix, iy, iz); - if (!voxel) { return vec3(px + t * dx, py + t * dy, pz + t * dz); } + if (voxel == nullptr) { return vec3(px + t * dx, py + t * dy, pz + t * dz); } const Block* def = contentIds->getBlockDef(voxel->id); if (def->obstacle) { diff --git a/src/voxels/Chunks.h b/src/voxels/Chunks.h index 58299ef55..9462e7840 100644 --- a/src/voxels/Chunks.h +++ b/src/voxels/Chunks.h @@ -53,9 +53,10 @@ public: glm::vec3 rayCastToObstacle(glm::vec3 start, glm::vec3 dir, float maxDist); - const AABB* isObstacle(float x, float y, float z); - bool isSolid(int x, int y, int z); - bool isReplaceable(int x, int y, int z); + const AABB* isObstacleAt(float x, float y, float z); + bool isSolidBlock(int x, int y, int z); + bool isReplaceableBlock(int x, int y, int z); + bool isObstacleBlock(int x, int y, int z); // does not move chunks inside void _setOffset(int x, int z); diff --git a/src/voxels/ChunksStorage.cpp b/src/voxels/ChunksStorage.cpp index ba55fbfda..f901b84fd 100644 --- a/src/voxels/ChunksStorage.cpp +++ b/src/voxels/ChunksStorage.cpp @@ -43,27 +43,28 @@ void ChunksStorage::remove(int x, int z) { } } +void verifyLoadedChunk(ContentIndices* indices, Chunk* chunk) { + for (size_t i = 0; i < CHUNK_VOL; i++) { + blockid_t id = chunk->voxels[i].id; + if (indices->getBlockDef(id) == nullptr) { + std::cout << "corruped block detected at " << i << " of chunk "; + std::cout << chunk->x << "x" << chunk->z; + std::cout << " -> " << (int)id << std::endl; + chunk->voxels[i].id = 11; + } + } +} + std::shared_ptr ChunksStorage::create(int x, int z) { World* world = level->world; - auto chunk = shared_ptr(new Chunk(x, z)); + auto chunk = std::make_shared(x, z); store(chunk); - unique_ptr data(world->wfile->getChunk(chunk->x, chunk->z)); + std::unique_ptr data(world->wfile->getChunk(chunk->x, chunk->z)); if (data) { chunk->decode(data.get()); chunk->setLoaded(true); - } - - // Verifying and converting data - ContentIndices* indices = level->content->indices; - for (size_t i = 0; i < CHUNK_VOL; i++) { - blockid_t id = chunk->voxels[i].id; - if (indices->getBlockDef(id) == nullptr) { - std::cout << "corruped block detected at " << i << " of chunk "; - std::cout << chunk->x << "x" << chunk->z; - std::cout << " -> " << (int)id << std::endl; - chunk->voxels[i].id = 11; - } + verifyLoadedChunk(level->content->indices, chunk.get()); } light_t* lights = world->wfile->getLights(chunk->x, chunk->z); diff --git a/src/window/Window.cpp b/src/window/Window.cpp index 5a378e817..d1f06c862 100644 --- a/src/window/Window.cpp +++ b/src/window/Window.cpp @@ -298,6 +298,10 @@ ImageData* Window::takeScreenshot() { return new ImageData(ImageFormat::rgb888, width, height, data); } +const char* Window::getClipboardText() { + return glfwGetClipboardString(window); +} + bool Window::tryToMaximize(GLFWwindow* window, GLFWmonitor* monitor) { glm::ivec4 windowFrame(0); glm::ivec4 workArea(0); diff --git a/src/window/Window.h b/src/window/Window.h index b4bb87865..4fb7ed347 100644 --- a/src/window/Window.h +++ b/src/window/Window.h @@ -49,6 +49,7 @@ public: static void clearDepth(); static void setBgColor(glm::vec3 color); static double time(); + static const char* getClipboardText(); static DisplaySettings* getSettings(); static glm::vec2 size() {