Merge pull request #92 from MihailRis/vixel-upd-2

Main
This commit is contained in:
alexei-zebra 2024-01-05 23:40:14 +03:00 • committed by GitHub
commit 3542a00445
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 620 additions and 449 deletions

View file

@ -30,8 +30,12 @@ endif()
if(MSVC)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>: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$<$<CONFIG:Release>: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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Before After
Before After

View file

@ -12,9 +12,6 @@
"ru_RU": {
"name": "Русский"
},
"su_SU": {
"name": "Советский"
},
"uk_UA": {
"name": "Українська"
}

View file

@ -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=Сменить Режим Камеры

View file

@ -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 <png.h>
// 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<png_byte[]> row(new png_byte[pixsize * width]);
std::unique_ptr<png_byte[]> 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<png_byte[]> 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<png_byte*[]> 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<ImageData> image (_png_load(filename.c_str()));
std::unique_ptr<ImageData> image (_png_load(filename.c_str()));
if (image == nullptr){
std::cerr << "Could not load texture " << filename << std::endl;
return nullptr;

View file

@ -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<blockid_t>::max();

View file

@ -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<u_char8[]> data (wfile->getChunk(gx, gz));
int gz = cz + z * REGION_SIZE;
std::unique_ptr<u_char8[]> 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());
}
}

View file

@ -23,9 +23,27 @@
#include <cstdint>
#include <fstream>
#include <sstream>
#include <cstring>
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<files::rafile>(filename);
openRegFiles[coord] = std::make_unique<regfile>(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]{};

View file

@ -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<glm::ivec2, std::unique_ptr<WorldRegion>> regionsmap;
class WorldFiles {
std::unordered_map<glm::ivec3, std::unique_ptr<files::rafile>> openRegFiles;
std::unordered_map<glm::ivec3, std::unique_ptr<regfile>> 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);

View file

@ -4,8 +4,6 @@
#include <limits>
#include <stdexcept>
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 {

View file

@ -9,8 +9,6 @@
#include "../coders/toml.h"
#include "../coders/json.h"
using std::string;
toml::Wrapper* create_wrapper(EngineSettings& settings) {
std::unique_ptr<toml::Wrapper> 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);
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -0,0 +1,104 @@
#include "InventoryView.h"
#include <glm/glm.hpp>
#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<blockid_t> 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();
}

View file

@ -0,0 +1,45 @@
#ifndef FRONTEND_INVENTORY_VIEW_H_
#define FRONTEND_INVENTORY_VIEW_H_
#include <vector>
#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<blockid_t> 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<blockid_t> blocks);
void setPosition(int x, int y);
void actAndDraw(const GfxContext* ctx);
int getWidth() const;
int getHeight() const;
};
#endif // FRONTEND_INVENTORY_VIEW_H_

View file

@ -2,6 +2,7 @@
#include <iostream>
#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<UINode> TextBox::getAt(vec2 pos, shared_ptr<UINode> self) {

View file

@ -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<blockid_t> 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;
}
}

View file

@ -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<InventoryView> contentAccess;
std::shared_ptr<gui::UINode> 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);

View file

@ -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<LevelScreen>(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<LevelScreen>(engine, level));
}
}
}

View file

@ -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);

View file

@ -18,15 +18,15 @@ class LevelController;
class Screen {
protected:
Engine* engine;
std::unique_ptr<Batch2D> 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:

View file

@ -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<ubyte*>(data);
ubyte* source = static_cast<ubyte*>(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;

View file

@ -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();

View file

@ -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;
}

View file

@ -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) {

View file

@ -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");
}

View file

@ -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

View file

@ -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 ||

View file

@ -4,8 +4,7 @@
#include "glm/glm.hpp"
std::unordered_map<rayvec3, AABBFaces> 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<AAFaceKind::Xperp>(
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<AAFaceKind::Xperp>(
return RayRelation::None;
}
template <>
RayRelation Ray::intersectAAFace<AAFaceKind::Yperp>(
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<AAFaceKind::Yperp>(
return RayRelation::None;
}
template <>
RayRelation Ray::intersectAAFace<AAFaceKind::Zperp>(
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<AAFaceKind::Zperp>(
return RayRelation::None;
}
template <>
RayRelation Ray::isIntersectsAAFace<AAFaceKind::Xperp>(
RayRelation Ray::isIntersectsYZFace(
const rayvec3& faceMin,
const rayvec2& faceOppositeCorner
){
@ -141,8 +137,7 @@ RayRelation Ray::isIntersectsAAFace<AAFaceKind::Xperp>(
return RayRelation::None;
}
template <>
RayRelation Ray::isIntersectsAAFace<AAFaceKind::Yperp>(
RayRelation Ray::isIntersectsXZFace(
const rayvec3& faceMin,
const rayvec2& faceOppositeCorner
) {
@ -165,8 +160,7 @@ RayRelation Ray::isIntersectsAAFace<AAFaceKind::Yperp>(
return RayRelation::None;
}
template <>
RayRelation Ray::isIntersectsAAFace<AAFaceKind::Zperp>(
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<AABBFaces::KINDS_ORDER[0]>(
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<AABBFaces::KINDS_ORDER[1]>(
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<AABBFaces::KINDS_ORDER[2]>(
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<AABBFaces::KINDS_ORDER[3]>(
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<AABBFaces::KINDS_ORDER[4]>(
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<AABBFaces::KINDS_ORDER[5]>(
if (intersectXYFace(
boxFaces.faces[5].first, boxFaces.faces[5].second, bufNormal, faceDist
) > RayRelation::None && faceDist < distance_ret) {
isIntersect = true;

View file

@ -8,7 +8,6 @@
#include "glm/gtx/hash.hpp"
#include <array>
#include <unordered_map>
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<std::pair<rayvec3, rayvec2>, AABBFACES_COUNT> faces; // every face is min-point and opposite corner point
static constexpr std::array<AAFaceKind,AABBFACES_COUNT> 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<rayvec3, AABBFaces> 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 <AAFaceKind faceKind>
RayRelation isIntersectsAAFace(
const rayvec3& faceMin,
const rayvec2& faceOppositeCorner
);
//returns only normal
template <AAFaceKind faceKind>
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 <AAFaceKind faceKind>
RayRelation intersectAAFace(
const rayvec3& faceMin,
const rayvec2& faceOppositeCorner,
glm::ivec3& normal_ret,
scalar_t& distance_ret
);
// returns normal, distance and intersection point
template <AAFaceKind faceKind>
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,

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -6,17 +6,11 @@
#include <stdexcept>
#include <algorithm>
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<char> chars;
std::string util::wstr2str_utf8(const std::wstring ws) {
std::vector<char> 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<wchar_t> chars;
std::wstring util::str2wstr_utf8(const std::string s) {
std::vector<wchar_t> 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;

View file

@ -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", {

View file

@ -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];

View file

@ -1,4 +1,7 @@
#include "Chunk.h"
#include <memory>
#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;
}
}

View file

@ -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);
};

View file

@ -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> 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) {

View file

@ -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);

View file

@ -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<Chunk> ChunksStorage::create(int x, int z) {
World* world = level->world;
auto chunk = shared_ptr<Chunk>(new Chunk(x, z));
auto chunk = std::make_shared<Chunk>(x, z);
store(chunk);
unique_ptr<u_char8> data(world->wfile->getChunk(chunk->x, chunk->z));
std::unique_ptr<u_char8[]> 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);

View file

@ -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);

View file

@ -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() {