mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-11 05:51:51 +00:00
commit
3542a00445
43 changed files with 620 additions and 449 deletions
|
|
@ -30,8 +30,12 @@ endif()
|
||||||
|
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
if((CMAKE_BUILD_TYPE EQUAL "Release") OR (CMAKE_BUILD_TYPE EQUAL "RelWithDebInfo"))
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE /W4 /MT /O2)
|
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")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /source-charset:UTF-8")
|
||||||
else()
|
else()
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -lstdc++fs
|
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 |
|
|
@ -12,9 +12,6 @@
|
||||||
"ru_RU": {
|
"ru_RU": {
|
||||||
"name": "Русский"
|
"name": "Русский"
|
||||||
},
|
},
|
||||||
"su_SU": {
|
|
||||||
"name": "Советский"
|
|
||||||
},
|
|
||||||
"uk_UA": {
|
"uk_UA": {
|
||||||
"name": "Українська"
|
"name": "Українська"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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=Сменить Режим Камеры
|
|
||||||
|
|
@ -8,8 +8,6 @@
|
||||||
#include "../graphics/Texture.h"
|
#include "../graphics/Texture.h"
|
||||||
#include "../files/files.h"
|
#include "../files/files.h"
|
||||||
|
|
||||||
using std::unique_ptr;
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#define LIBPNG
|
#define LIBPNG
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -18,10 +16,8 @@ using std::unique_ptr;
|
||||||
#include <png.h>
|
#include <png.h>
|
||||||
|
|
||||||
// returns 0 if all-right, 1 otherwise
|
// returns 0 if all-right, 1 otherwise
|
||||||
int _png_write(const char* filename, uint width, uint height, const u_char8* data, bool alpha) {
|
int _png_write(const char* filename, u_int width, u_int height, const u_char8* data, bool alpha) {
|
||||||
png_structp png_ptr = nullptr;
|
u_int pixsize = alpha ? 4 : 3;
|
||||||
png_infop info_ptr = nullptr;
|
|
||||||
uint pixsize = alpha ? 4 : 3;
|
|
||||||
|
|
||||||
// Open file for writing (binary mode)
|
// Open file for writing (binary mode)
|
||||||
FILE* fp = fopen(filename, "wb");
|
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
|
// 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) {
|
if (png_ptr == nullptr) {
|
||||||
fprintf(stderr, "Could not allocate write struct\n");
|
fprintf(stderr, "Could not allocate write struct\n");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
@ -41,7 +37,7 @@ int _png_write(const char* filename, uint width, uint height, const u_char8* dat
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize info structure
|
// 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) {
|
if (info_ptr == nullptr) {
|
||||||
fprintf(stderr, "Could not allocate info struct\n");
|
fprintf(stderr, "Could not allocate info struct\n");
|
||||||
fclose(fp);
|
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);
|
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
|
// Write image data
|
||||||
for (uint y = 0; y < height; y++) {
|
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){
|
ImageData* _png_load(const char* file){
|
||||||
FILE *f = nullptr;
|
|
||||||
bool is_png = false;
|
|
||||||
int bit_depth, color_type, row_bytes;
|
int bit_depth, color_type, row_bytes;
|
||||||
png_infop info_ptr, end_info;
|
|
||||||
png_uint_32 t_width, t_height;
|
png_uint_32 t_width, t_height;
|
||||||
png_byte header[8], *image_data;
|
png_byte header[8];
|
||||||
png_bytepp row_pointers;
|
|
||||||
png_structp png_ptr;
|
|
||||||
|
|
||||||
|
FILE *f = nullptr;
|
||||||
if ((f = fopen(file, "r")) == nullptr) {
|
if ((f = fopen(file, "r")) == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -112,28 +104,28 @@ ImageData* _png_load(const char* file){
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_png = (png_sig_cmp(header, 0, 8) == 0);
|
bool is_png = (png_sig_cmp(header, 0, 8) == 0);
|
||||||
if (!is_png) {
|
if (!is_png) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return nullptr;
|
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);
|
nullptr, nullptr);
|
||||||
if (png_ptr == nullptr) {
|
if (png_ptr == nullptr) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
info_ptr = png_create_info_struct(png_ptr);
|
png_info* info_ptr = png_create_info_struct(png_ptr);
|
||||||
if (info_ptr == nullptr) {
|
if (info_ptr == nullptr) {
|
||||||
png_destroy_read_struct( &png_ptr, (png_infopp) nullptr,
|
png_destroy_read_struct(&png_ptr, (png_info**) nullptr,
|
||||||
(png_infopp) nullptr );
|
(png_info**) nullptr);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
end_info = png_create_info_struct(png_ptr);
|
png_info* end_info = png_create_info_struct(png_ptr);
|
||||||
if (end_info == nullptr) {
|
if (end_info == nullptr) {
|
||||||
png_destroy_read_struct(&png_ptr, (png_infopp) nullptr,
|
png_destroy_read_struct(&png_ptr, (png_info**) nullptr,
|
||||||
(png_infopp) nullptr);
|
(png_info**) nullptr);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -144,33 +136,34 @@ ImageData* _png_load(const char* file){
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
png_init_io( png_ptr, f );
|
png_init_io(png_ptr, f);
|
||||||
png_set_sig_bytes( png_ptr, 8 );
|
png_set_sig_bytes(png_ptr, 8);
|
||||||
png_read_info( png_ptr, info_ptr );
|
png_read_info(png_ptr, info_ptr);
|
||||||
png_get_IHDR( png_ptr, info_ptr, &t_width, &t_height, &bit_depth,
|
png_get_IHDR(png_ptr, info_ptr, &t_width, &t_height, &bit_depth,
|
||||||
&color_type, nullptr, nullptr, nullptr );
|
&color_type, nullptr, nullptr, nullptr);
|
||||||
png_read_update_info( png_ptr, info_ptr );
|
png_read_update_info(png_ptr, info_ptr);
|
||||||
row_bytes = png_get_rowbytes( png_ptr, info_ptr );
|
row_bytes = png_get_rowbytes(png_ptr, info_ptr);
|
||||||
image_data = new png_byte[row_bytes * t_height];
|
|
||||||
|
std::unique_ptr<png_byte[]> image_data (new png_byte[row_bytes * t_height]);
|
||||||
if (!image_data) {
|
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);
|
fclose(f);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
row_pointers = (png_bytepp) malloc( t_height * sizeof(png_bytep) );
|
|
||||||
if ( row_pointers == nullptr ) {
|
std::unique_ptr<png_byte*[]> row_pointers (new png_byte*[t_height]);
|
||||||
png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
|
if (row_pointers == nullptr) {
|
||||||
delete[] image_data;
|
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
for (uint i = 0; i < t_height; ++i ) {
|
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;
|
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:
|
case PNG_COLOR_TYPE_RGBA:
|
||||||
format = ImageFormat::rgba8888;
|
format = ImageFormat::rgba8888;
|
||||||
break;
|
break;
|
||||||
|
|
@ -178,18 +171,15 @@ ImageData* _png_load(const char* file){
|
||||||
format = ImageFormat::rgb888;
|
format = ImageFormat::rgb888;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf( "Color type %d not supported!\n",
|
printf("Color type %d not supported!\n",
|
||||||
png_get_color_type( png_ptr, info_ptr ) );
|
png_get_color_type(png_ptr, info_ptr));
|
||||||
png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
|
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||||
delete[] image_data;
|
|
||||||
free( row_pointers );
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return nullptr;
|
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 );
|
png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
|
||||||
free( row_pointers );
|
fclose(f);
|
||||||
fclose( f );
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
@ -335,7 +325,7 @@ ImageData* _png_load(const char* file){
|
||||||
flipped[(ihdr.height-i-1)*rowsize+j] = out[i*rowsize+j];
|
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);
|
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) {
|
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){
|
if (image == nullptr){
|
||||||
std::cerr << "Could not load texture " << filename << std::endl;
|
std::cerr << "Could not load texture " << filename << std::endl;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,17 @@
|
||||||
#include "typedefs.h"
|
#include "typedefs.h"
|
||||||
|
|
||||||
const int ENGINE_VERSION_MAJOR = 0;
|
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_W = 16;
|
||||||
const int CHUNK_H = 256;
|
const int CHUNK_H = 256;
|
||||||
const int CHUNK_D = 16;
|
const int CHUNK_D = 16;
|
||||||
|
|
||||||
|
const uint VOXEL_USER_BITS = 8;
|
||||||
|
constexpr uint VOXEL_USER_BITS_OFFSET = sizeof(blockstate_t)*8-VOXEL_USER_BITS;
|
||||||
|
|
||||||
/* Chunk volume (count of voxels per Chunk) */
|
/* Chunk volume (count of voxels per Chunk) */
|
||||||
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) */
|
/* 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();
|
const blockid_t BLOCK_VOID = std::numeric_limits<blockid_t>::max();
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,15 @@
|
||||||
#include "../content/ContentLUT.h"
|
#include "../content/ContentLUT.h"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
using std::string;
|
|
||||||
using std::unique_ptr;
|
|
||||||
using fs::path;
|
|
||||||
|
|
||||||
WorldConverter::WorldConverter(path folder,
|
WorldConverter::WorldConverter(fs::path folder,
|
||||||
const Content* content,
|
const Content* content,
|
||||||
const ContentLUT* lut)
|
const ContentLUT* lut)
|
||||||
: lut(lut), content(content) {
|
: lut(lut), content(content) {
|
||||||
DebugSettings settings;
|
DebugSettings settings;
|
||||||
wfile = new WorldFiles(folder, settings);
|
wfile = new WorldFiles(folder, settings);
|
||||||
|
|
||||||
path regionsFolder = wfile->getRegionsFolder();
|
fs::path regionsFolder = wfile->getRegionsFolder();
|
||||||
if (!fs::is_directory(regionsFolder)) {
|
if (!fs::is_directory(regionsFolder)) {
|
||||||
std::cerr << "nothing to convert" << std::endl;
|
std::cerr << "nothing to convert" << std::endl;
|
||||||
return;
|
return;
|
||||||
|
|
@ -41,13 +38,13 @@ void WorldConverter::convertNext() {
|
||||||
if (!hasNext()) {
|
if (!hasNext()) {
|
||||||
throw std::runtime_error("no more regions to convert");
|
throw std::runtime_error("no more regions to convert");
|
||||||
}
|
}
|
||||||
path regfile = regions.front();
|
fs::path regfile = regions.front();
|
||||||
regions.pop();
|
regions.pop();
|
||||||
if (!fs::is_regular_file(regfile))
|
if (!fs::is_regular_file(regfile))
|
||||||
return;
|
return;
|
||||||
int x, y;
|
int x, z;
|
||||||
string name = regfile.stem().string();
|
std::string name = regfile.stem().string();
|
||||||
if (!WorldFiles::parseRegionFilename(name, x, y)) {
|
if (!WorldFiles::parseRegionFilename(name, x, z)) {
|
||||||
std::cerr << "could not parse name " << name << std::endl;
|
std::cerr << "could not parse name " << name << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -55,11 +52,16 @@ void WorldConverter::convertNext() {
|
||||||
for (uint cz = 0; cz < REGION_SIZE; cz++) {
|
for (uint cz = 0; cz < REGION_SIZE; cz++) {
|
||||||
for (uint cx = 0; cx < REGION_SIZE; cx++) {
|
for (uint cx = 0; cx < REGION_SIZE; cx++) {
|
||||||
int gx = cx + x * REGION_SIZE;
|
int gx = cx + x * REGION_SIZE;
|
||||||
int gz = cz + y * REGION_SIZE;
|
int gz = cz + z * REGION_SIZE;
|
||||||
unique_ptr<u_char8[]> data (wfile->getChunk(gx, gz));
|
std::unique_ptr<u_char8[]> data (wfile->getChunk(gx, gz));
|
||||||
if (data == nullptr)
|
if (data == nullptr)
|
||||||
continue;
|
continue;
|
||||||
Chunk::convert(data.get(), lut);
|
if (wfile->getVoxelRegionVersion(x, z) != REGION_FORMAT_VERSION) {
|
||||||
|
Chunk::fromOld(data.get());
|
||||||
|
}
|
||||||
|
if (lut) {
|
||||||
|
Chunk::convert(data.get(), lut);
|
||||||
|
}
|
||||||
wfile->put(gx, gz, data.get());
|
wfile->put(gx, gz, data.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,27 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
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() {
|
WorldRegion::WorldRegion() {
|
||||||
chunksData = new u_char8*[REGION_CHUNKS_COUNT]{};
|
chunksData = new u_char8*[REGION_CHUNKS_COUNT]{};
|
||||||
sizes = new uint32_t[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;
|
return decompressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WorldFiles::getVoxelRegionVersion(int x, int z) {
|
||||||
|
regfile* rf = getRegFile(glm::ivec3(x, z, REGION_LAYER_VOXELS), getRegionsFolder());
|
||||||
|
if (rf == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return rf->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WorldFiles::getVoxelRegionsVersion() {
|
||||||
|
fs::path regionsFolder = getRegionsFolder();
|
||||||
|
if (!fs::is_directory(regionsFolder)) {
|
||||||
|
return REGION_FORMAT_VERSION;
|
||||||
|
}
|
||||||
|
for (auto file : fs::directory_iterator(regionsFolder)) {
|
||||||
|
int x;
|
||||||
|
int z;
|
||||||
|
if (!parseRegionFilename(file.path().stem().string(), x, z)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
regfile* rf = getRegFile(glm::ivec3(x, z, REGION_LAYER_VOXELS), regionsFolder);
|
||||||
|
return rf->version;
|
||||||
|
}
|
||||||
|
return REGION_FORMAT_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compress and store chunk voxels data in region
|
* Compress and store chunk voxels data in region
|
||||||
* @param x chunk.x
|
* @param x chunk.x
|
||||||
|
|
@ -172,8 +215,7 @@ fs::path WorldFiles::getLightsFolder() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path WorldFiles::getRegionFilename(int x, int z) const {
|
fs::path WorldFiles::getRegionFilename(int x, int z) const {
|
||||||
std::string filename = std::to_string(x) + "_" + std::to_string(z) + ".bin";
|
return fs::path(std::to_string(x) + "_" + std::to_string(z) + ".bin");
|
||||||
return fs::path(filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -236,7 +278,6 @@ u_char8* WorldFiles::getData(regionsmap& regions, const fs::path& folder,
|
||||||
int localZ = z - (regionZ * REGION_SIZE);
|
int localZ = z - (regionZ * REGION_SIZE);
|
||||||
|
|
||||||
WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ);
|
WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ);
|
||||||
|
|
||||||
u_char8* data = region->getChunkData(localX, localZ);
|
u_char8* data = region->getChunkData(localX, localZ);
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
|
|
@ -252,7 +293,8 @@ u_char8* WorldFiles::getData(regionsmap& regions, const fs::path& folder,
|
||||||
return nullptr;
|
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);
|
const auto found = openRegFiles.find(coord);
|
||||||
if (found != openRegFiles.end()) {
|
if (found != openRegFiles.end()) {
|
||||||
return found->second.get();
|
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)) {
|
if (!fs::is_regular_file(filename)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
openRegFiles[coord] = std::make_unique<files::rafile>(filename);
|
openRegFiles[coord] = std::make_unique<regfile>(filename);
|
||||||
return openRegFiles[coord].get();
|
return openRegFiles[coord].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,26 +327,27 @@ u_char8* WorldFiles::readChunkData(int x,
|
||||||
int chunkIndex = localZ * REGION_SIZE + localX;
|
int chunkIndex = localZ * REGION_SIZE + localX;
|
||||||
|
|
||||||
glm::ivec3 coord(regionX, regionZ, layer);
|
glm::ivec3 coord(regionX, regionZ, layer);
|
||||||
files::rafile* file = WorldFiles::getRegFile(coord, folder);
|
regfile* rfile = WorldFiles::getRegFile(coord, folder);
|
||||||
if (file == nullptr) {
|
if (rfile == nullptr) {
|
||||||
return 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;
|
size_t table_offset = file_size - REGION_CHUNKS_COUNT * 4;
|
||||||
|
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
file->seekg(table_offset + chunkIndex * 4);
|
file.seekg(table_offset + chunkIndex * 4);
|
||||||
file->read((char*)(&offset), 4);
|
file.read((char*)(&offset), 4);
|
||||||
offset = dataio::read_int32_big((const u_char8*)(&offset), 0);
|
offset = dataio::read_int32_big((const u_char8*)(&offset), 0);
|
||||||
if (offset == 0){
|
if (offset == 0){
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
file->seekg(offset);
|
file.seekg(offset);
|
||||||
file->read((char*)(&offset), 4);
|
file.read((char*)(&offset), 4);
|
||||||
length = dataio::read_int32_big((const u_char8*)(&offset), 0);
|
length = dataio::read_int32_big((const u_char8*)(&offset), 0);
|
||||||
u_char8* data = new u_char8[length];
|
u_char8* data = new u_char8[length];
|
||||||
file->read((char*)data, length);
|
file.read((char*)data, length);
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
std::cerr << "ERROR: failed to read data of chunk x("<< x <<"), z("<< z <<")" << std::endl;
|
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);
|
openRegFiles.erase(regcoord);
|
||||||
}
|
}
|
||||||
|
|
||||||
char header[10] = REGION_FORMAT_MAGIC;
|
char header[REGION_HEADER_SIZE] = REGION_FORMAT_MAGIC;
|
||||||
header[8] = REGION_FORMAT_VERSION;
|
header[8] = REGION_FORMAT_VERSION;
|
||||||
header[9] = 0; // flags
|
header[9] = 0; // flags
|
||||||
std::ofstream file(filename, std::ios::out | std::ios::binary);
|
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]{};
|
char intbuf[4]{};
|
||||||
uint offsets[REGION_CHUNKS_COUNT]{};
|
uint offsets[REGION_CHUNKS_COUNT]{};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,13 @@
|
||||||
#include "../typedefs.h"
|
#include "../typedefs.h"
|
||||||
#include "../settings.h"
|
#include "../settings.h"
|
||||||
|
|
||||||
|
const uint REGION_HEADER_SIZE = 10;
|
||||||
const uint REGION_LAYER_VOXELS = 0;
|
const uint REGION_LAYER_VOXELS = 0;
|
||||||
const uint REGION_LAYER_LIGHTS = 1;
|
const uint REGION_LAYER_LIGHTS = 1;
|
||||||
const uint REGION_SIZE_BIT = 5;
|
const uint REGION_SIZE_BIT = 5;
|
||||||
const uint REGION_SIZE = (1 << (REGION_SIZE_BIT));
|
const uint REGION_SIZE = (1 << (REGION_SIZE_BIT));
|
||||||
const uint REGION_CHUNKS_COUNT = ((REGION_SIZE) * (REGION_SIZE));
|
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 WORLD_FORMAT_VERSION = 1;
|
||||||
const uint MAX_OPEN_REGION_FILES = 16;
|
const uint MAX_OPEN_REGION_FILES = 16;
|
||||||
|
|
||||||
|
|
@ -33,6 +34,12 @@ class Content;
|
||||||
class ContentIndices;
|
class ContentIndices;
|
||||||
class World;
|
class World;
|
||||||
|
|
||||||
|
class illegal_region_format : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
illegal_region_format(const std::string& message)
|
||||||
|
: std::runtime_error(message) {}
|
||||||
|
};
|
||||||
|
|
||||||
class WorldRegion {
|
class WorldRegion {
|
||||||
u_char8** chunksData;
|
u_char8** chunksData;
|
||||||
uint32_t* sizes;
|
uint32_t* sizes;
|
||||||
|
|
@ -52,9 +59,16 @@ public:
|
||||||
uint32_t* getSizes() const;
|
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;
|
typedef std::unordered_map<glm::ivec2, std::unique_ptr<WorldRegion>> regionsmap;
|
||||||
class WorldFiles {
|
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);
|
void writeWorldInfo(const World* world);
|
||||||
std::filesystem::path getLightsFolder() const;
|
std::filesystem::path getLightsFolder() const;
|
||||||
|
|
@ -98,8 +112,8 @@ class WorldFiles {
|
||||||
const std::filesystem::path& folder,
|
const std::filesystem::path& folder,
|
||||||
int x, int z, int layer);
|
int x, int z, int layer);
|
||||||
|
|
||||||
files::rafile* getRegFile(glm::ivec3 coord,
|
regfile* getRegFile(glm::ivec3 coord,
|
||||||
const std::filesystem::path& folder);
|
const std::filesystem::path& folder);
|
||||||
public:
|
public:
|
||||||
static bool parseRegionFilename(const std::string& name, int& x, int& y);
|
static bool parseRegionFilename(const std::string& name, int& x, int& y);
|
||||||
std::filesystem::path getRegionsFolder() const;
|
std::filesystem::path getRegionsFolder() const;
|
||||||
|
|
@ -117,6 +131,9 @@ public:
|
||||||
void put(Chunk* chunk);
|
void put(Chunk* chunk);
|
||||||
void put(int x, int z, const u_char8* voxelData);
|
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);
|
u_char8* getChunk(int x, int z);
|
||||||
light_t* getLights(int x, int z);
|
light_t* getLights(int x, int z);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
using std::string;
|
|
||||||
|
|
||||||
void BinaryWriter::put(u_char8 b) {
|
void BinaryWriter::put(u_char8 b) {
|
||||||
buffer.push_back(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();
|
size_t len = s.length();
|
||||||
if (len > INT16_MAX) {
|
if (len > INT16_MAX) {
|
||||||
throw std::domain_error("length > 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);
|
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();
|
size_t len = s.length();
|
||||||
if (len > 255) {
|
if (len > 255) {
|
||||||
throw std::domain_error("length > 255");
|
throw std::domain_error("length > 255");
|
||||||
|
|
@ -144,22 +142,22 @@ float BinaryReader::getFloat32() {
|
||||||
return value.valfloat;
|
return value.valfloat;
|
||||||
}
|
}
|
||||||
|
|
||||||
string BinaryReader::getString() {
|
std::string BinaryReader::getString() {
|
||||||
uint16_t length = (uint16_t)getInt16();
|
uint16_t length = (uint16_t)getInt16();
|
||||||
if (pos+length > size) {
|
if (pos+length > size) {
|
||||||
throw std::underflow_error("unexpected end");
|
throw std::underflow_error("unexpected end");
|
||||||
}
|
}
|
||||||
pos += length;
|
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();
|
u_char8 length = get();
|
||||||
if (pos+length > size) {
|
if (pos+length > size) {
|
||||||
throw std::underflow_error("unexpected end");
|
throw std::underflow_error("unexpected end");
|
||||||
}
|
}
|
||||||
pos += length;
|
pos += length;
|
||||||
return string((const char*)(data+pos-length), length);
|
return std::string((const char*)(data+pos-length), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BinaryReader::hasNext() const {
|
bool BinaryReader::hasNext() const {
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,6 @@
|
||||||
#include "../coders/toml.h"
|
#include "../coders/toml.h"
|
||||||
#include "../coders/json.h"
|
#include "../coders/json.h"
|
||||||
|
|
||||||
using std::string;
|
|
||||||
|
|
||||||
toml::Wrapper* create_wrapper(EngineSettings& settings) {
|
toml::Wrapper* create_wrapper(EngineSettings& settings) {
|
||||||
std::unique_ptr<toml::Wrapper> wrapper (new toml::Wrapper());
|
std::unique_ptr<toml::Wrapper> wrapper (new toml::Wrapper());
|
||||||
toml::Section& display = wrapper->add("display");
|
toml::Section& display = wrapper->add("display");
|
||||||
|
|
@ -47,7 +45,7 @@ toml::Wrapper* create_wrapper(EngineSettings& settings) {
|
||||||
return wrapper.release();
|
return wrapper.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
string write_controls() {
|
std::string write_controls() {
|
||||||
json::JObject* obj = new json::JObject();
|
json::JObject* obj = new json::JObject();
|
||||||
for (auto& entry : Events::bindings) {
|
for (auto& entry : Events::bindings) {
|
||||||
const auto& binding = entry.second;
|
const auto& binding = entry.second;
|
||||||
|
|
@ -64,7 +62,7 @@ string write_controls() {
|
||||||
return json::stringify(obj, true, " ");
|
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);
|
json::JObject* obj = json::parse(filename, source);
|
||||||
for (auto& entry : Events::bindings) {
|
for (auto& entry : Events::bindings) {
|
||||||
auto& binding = entry.second;
|
auto& binding = entry.second;
|
||||||
|
|
@ -73,7 +71,7 @@ void load_controls(string filename, string source) {
|
||||||
if (jentry == nullptr)
|
if (jentry == nullptr)
|
||||||
continue;
|
continue;
|
||||||
inputtype type;
|
inputtype type;
|
||||||
string typestr;
|
std::string typestr;
|
||||||
jentry->str("type", typestr);
|
jentry->str("type", typestr);
|
||||||
|
|
||||||
if (typestr == "keyboard") {
|
if (typestr == "keyboard") {
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,6 @@
|
||||||
#include "../voxels/Block.h"
|
#include "../voxels/Block.h"
|
||||||
#include "ContentGfxCache.h"
|
#include "ContentGfxCache.h"
|
||||||
|
|
||||||
using glm::vec4;
|
|
||||||
using glm::vec3;
|
|
||||||
|
|
||||||
BlocksPreview::BlocksPreview(Shader* shader,
|
BlocksPreview::BlocksPreview(Shader* shader,
|
||||||
Atlas* atlas,
|
Atlas* atlas,
|
||||||
const ContentGfxCache* cache)
|
const ContentGfxCache* cache)
|
||||||
|
|
@ -31,19 +28,21 @@ void BlocksPreview::begin(const Viewport* viewport) {
|
||||||
glm::ortho(0.0f, float(viewport->getWidth()),
|
glm::ortho(0.0f, float(viewport->getWidth()),
|
||||||
0.0f, float(viewport->getHeight()),
|
0.0f, float(viewport->getHeight()),
|
||||||
-1000.0f, 1000.0f) *
|
-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();
|
atlas->getTexture()->bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw one block preview at given screen position */
|
/* 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 width = viewport->getWidth();
|
||||||
uint height = viewport->getHeight();
|
uint height = viewport->getHeight();
|
||||||
|
|
||||||
y = height - y - 1;
|
y = height - y - 1;
|
||||||
x += 2;
|
x += 2;
|
||||||
y -= 35;
|
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;
|
blockid_t id = def->rt.id;
|
||||||
const UVRegion texfaces[6]{ cache->getRegion(id, 0), cache->getRegion(id, 1),
|
const UVRegion texfaces[6]{ cache->getRegion(id, 0), cache->getRegion(id, 1),
|
||||||
cache->getRegion(id, 2), cache->getRegion(id, 3),
|
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...
|
// something went wrong...
|
||||||
break;
|
break;
|
||||||
case BlockModel::block:
|
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;
|
break;
|
||||||
case BlockModel::aabb:
|
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;
|
break;
|
||||||
case BlockModel::xsprite: {
|
case BlockModel::xsprite: {
|
||||||
//batch->xSprite(size, size, texfaces[0], tint, !def->rt.emissive);
|
glm::vec3 right = glm::normalize(glm::vec3(1.f, 0.f, -1.f));
|
||||||
vec3 right = glm::normalize(vec3(1.f, 0.f, -1.f));
|
batch->sprite(right*float(size)*0.43f+glm::vec3(0, size*0.4f, 0),
|
||||||
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(0.f, 1.f, 0.f),
|
||||||
|
right,
|
||||||
|
size*0.5f, size*0.6f,
|
||||||
|
texfaces[0],
|
||||||
|
tint);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@
|
||||||
#include "../graphics/Atlas.h"
|
#include "../graphics/Atlas.h"
|
||||||
#include "../voxels/Block.h"
|
#include "../voxels/Block.h"
|
||||||
|
|
||||||
using std::string;
|
|
||||||
|
|
||||||
ContentGfxCache::ContentGfxCache(const Content* content, Assets* assets) {
|
ContentGfxCache::ContentGfxCache(const Content* content, Assets* assets) {
|
||||||
const ContentIndices* contentIds = content->indices;
|
const ContentIndices* contentIds = content->indices;
|
||||||
sideregions = new UVRegion[contentIds->countBlockDefs() * 6];
|
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++) {
|
for (uint i = 0; i < contentIds->countBlockDefs(); i++) {
|
||||||
Block* def = contentIds->getBlockDef(i);
|
Block* def = contentIds->getBlockDef(i);
|
||||||
for (uint side = 0; side < 6; side++) {
|
for (uint side = 0; side < 6; side++) {
|
||||||
string tex = def->textureFaces[side];
|
std::string tex = def->textureFaces[side];
|
||||||
if (atlas->has(tex)) {
|
if (atlas->has(tex)) {
|
||||||
sideregions[i * 6 + side] = atlas->get(tex);
|
sideregions[i * 6 + side] = atlas->get(tex);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -28,7 +26,6 @@ ContentGfxCache::ContentGfxCache(const Content* content, Assets* assets) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentGfxCache::~ContentGfxCache()
|
ContentGfxCache::~ContentGfxCache() {
|
||||||
{
|
|
||||||
delete[] sideregions;
|
delete[] sideregions;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
104
src/frontend/InventoryView.cpp
Normal file
104
src/frontend/InventoryView.cpp
Normal 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();
|
||||||
|
}
|
||||||
45
src/frontend/InventoryView.h
Normal file
45
src/frontend/InventoryView.h
Normal 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_
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "../../window/Events.h"
|
||||||
#include "../../assets/Assets.h"
|
#include "../../assets/Assets.h"
|
||||||
#include "../../graphics/Batch2D.h"
|
#include "../../graphics/Batch2D.h"
|
||||||
#include "../../graphics/Font.h"
|
#include "../../graphics/Font.h"
|
||||||
|
|
@ -21,7 +22,9 @@ const uint KEY_BACKSPACE = 259;
|
||||||
using namespace gui;
|
using namespace gui;
|
||||||
|
|
||||||
Label::Label(wstring text, string fontName)
|
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) {
|
Label& Label::text(wstring text) {
|
||||||
|
|
@ -175,6 +178,13 @@ void TextBox::keyPressed(int key) {
|
||||||
defocus();
|
defocus();
|
||||||
break;
|
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) {
|
shared_ptr<UINode> TextBox::getAt(vec2 pos, shared_ptr<UINode> self) {
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
#include "screens.h"
|
#include "screens.h"
|
||||||
#include "WorldRenderer.h"
|
#include "WorldRenderer.h"
|
||||||
#include "BlocksPreview.h"
|
#include "BlocksPreview.h"
|
||||||
|
#include "InventoryView.h"
|
||||||
#include "../engine.h"
|
#include "../engine.h"
|
||||||
#include "../core_defs.h"
|
#include "../core_defs.h"
|
||||||
|
|
||||||
|
|
@ -59,13 +60,28 @@ HudRenderer::HudRenderer(Engine* engine,
|
||||||
const ContentGfxCache* cache)
|
const ContentGfxCache* cache)
|
||||||
: level(level),
|
: level(level),
|
||||||
assets(engine->getAssets()),
|
assets(engine->getAssets()),
|
||||||
batch(new Batch2D(1024)),
|
|
||||||
gui(engine->getGUI()),
|
gui(engine->getGUI()),
|
||||||
cache(cache) {
|
cache(cache) {
|
||||||
auto menu = gui->getMenu();
|
auto menu = gui->getMenu();
|
||||||
blocksPreview = new BlocksPreview(assets->getShader("ui3d"),
|
blocksPreview = new BlocksPreview(assets->getShader("ui3d"),
|
||||||
assets->getAtlas("blocks"),
|
assets->getAtlas("blocks"),
|
||||||
cache);
|
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 = new Camera(vec3(), 1);
|
||||||
uicamera->perspective = false;
|
uicamera->perspective = false;
|
||||||
|
|
@ -201,7 +217,6 @@ HudRenderer::HudRenderer(Engine* engine,
|
||||||
HudRenderer::~HudRenderer() {
|
HudRenderer::~HudRenderer() {
|
||||||
gui->remove(debugPanel);
|
gui->remove(debugPanel);
|
||||||
delete blocksPreview;
|
delete blocksPreview;
|
||||||
delete batch;
|
|
||||||
delete uicamera;
|
delete uicamera;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,72 +226,6 @@ void HudRenderer::drawDebug(int fps){
|
||||||
fpsMax = max(fps, fpsMax);
|
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() {
|
void HudRenderer::update() {
|
||||||
auto menu = gui->getMenu();
|
auto menu = gui->getMenu();
|
||||||
if (pause && menu->current().panel == nullptr) {
|
if (pause && menu->current().panel == nullptr) {
|
||||||
|
|
@ -319,6 +268,7 @@ void HudRenderer::draw(const GfxContext& ctx){
|
||||||
uishader->use();
|
uishader->use();
|
||||||
uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView());
|
uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView());
|
||||||
|
|
||||||
|
auto batch = ctx.getBatch2D();
|
||||||
batch->begin();
|
batch->begin();
|
||||||
|
|
||||||
// Chosen block preview
|
// Chosen block preview
|
||||||
|
|
@ -358,7 +308,8 @@ void HudRenderer::draw(const GfxContext& ctx){
|
||||||
batch->rect(0, 0, width, height);
|
batch->rect(0, 0, width, height);
|
||||||
}
|
}
|
||||||
if (inventoryOpen) {
|
if (inventoryOpen) {
|
||||||
drawContentAccess(ctx, player);
|
contentAccess->setPosition(viewport.getWidth()-contentAccess->getWidth(), 0);
|
||||||
|
contentAccess->actAndDraw(&ctx);
|
||||||
}
|
}
|
||||||
batch->render();
|
batch->render();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include "../graphics/GfxContext.h"
|
#include "../graphics/GfxContext.h"
|
||||||
|
|
||||||
class Batch2D;
|
|
||||||
class Camera;
|
class Camera;
|
||||||
class Level;
|
class Level;
|
||||||
class Block;
|
class Block;
|
||||||
|
|
@ -17,8 +16,8 @@ class Player;
|
||||||
class Level;
|
class Level;
|
||||||
class Engine;
|
class Engine;
|
||||||
class ContentGfxCache;
|
class ContentGfxCache;
|
||||||
class WorldRenderer;
|
|
||||||
class BlocksPreview;
|
class BlocksPreview;
|
||||||
|
class InventoryView;
|
||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
class GUI;
|
class GUI;
|
||||||
|
|
@ -28,7 +27,6 @@ namespace gui {
|
||||||
class HudRenderer {
|
class HudRenderer {
|
||||||
Level* level;
|
Level* level;
|
||||||
Assets* assets;
|
Assets* assets;
|
||||||
Batch2D* batch;
|
|
||||||
Camera* uicamera;
|
Camera* uicamera;
|
||||||
BlocksPreview* blocksPreview;
|
BlocksPreview* blocksPreview;
|
||||||
|
|
||||||
|
|
@ -39,6 +37,7 @@ class HudRenderer {
|
||||||
bool inventoryOpen = false;
|
bool inventoryOpen = false;
|
||||||
bool pause = false;
|
bool pause = false;
|
||||||
|
|
||||||
|
std::unique_ptr<InventoryView> contentAccess;
|
||||||
std::shared_ptr<gui::UINode> debugPanel;
|
std::shared_ptr<gui::UINode> debugPanel;
|
||||||
gui::GUI* gui;
|
gui::GUI* gui;
|
||||||
const ContentGfxCache* const cache;
|
const ContentGfxCache* const cache;
|
||||||
|
|
@ -49,7 +48,6 @@ public:
|
||||||
~HudRenderer();
|
~HudRenderer();
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
void drawContentAccess(const GfxContext& ctx, Player* player);
|
|
||||||
void draw(const GfxContext& context);
|
void draw(const GfxContext& context);
|
||||||
void drawDebug(int fps);
|
void drawDebug(int fps);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@
|
||||||
#include "../util/stringutil.h"
|
#include "../util/stringutil.h"
|
||||||
#include "../files/engine_paths.h"
|
#include "../files/engine_paths.h"
|
||||||
#include "../files/WorldConverter.h"
|
#include "../files/WorldConverter.h"
|
||||||
|
#include "../files/WorldFiles.h"
|
||||||
#include "../world/World.h"
|
#include "../world/World.h"
|
||||||
|
#include "../world/Level.h"
|
||||||
#include "../window/Events.h"
|
#include "../window/Events.h"
|
||||||
#include "../window/Window.h"
|
#include "../window/Window.h"
|
||||||
#include "../engine.h"
|
#include "../engine.h"
|
||||||
|
|
@ -175,8 +177,18 @@ void open_world(std::string name, Engine* engine) {
|
||||||
show_convert_request(engine, content, lut, folder);
|
show_convert_request(engine, content, lut, folder);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Level* level = World::load(folder, settings, content, packs);
|
// TODO: remove in 0.18
|
||||||
engine->setScreen(std::make_shared<LevelScreen>(engine, level));
|
int version;
|
||||||
|
{
|
||||||
|
WorldFiles wfile(folder, settings.debug);
|
||||||
|
version = wfile.getVoxelRegionsVersion();
|
||||||
|
}
|
||||||
|
if (version != REGION_FORMAT_VERSION) {
|
||||||
|
show_convert_request(engine, content, lut, folder);
|
||||||
|
} else {
|
||||||
|
Level* level = World::load(folder, settings, content, packs);
|
||||||
|
engine->setScreen(std::make_shared<LevelScreen>(engine, level));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,20 +41,24 @@ using glm::vec3;
|
||||||
using glm::vec4;
|
using glm::vec4;
|
||||||
using std::shared_ptr;
|
using std::shared_ptr;
|
||||||
|
|
||||||
|
Screen::Screen(Engine* engine) : engine(engine), batch(new Batch2D(1024)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen::~Screen() {
|
||||||
|
}
|
||||||
|
|
||||||
MenuScreen::MenuScreen(Engine* engine_) : Screen(engine_) {
|
MenuScreen::MenuScreen(Engine* engine_) : Screen(engine_) {
|
||||||
auto menu = engine->getGUI()->getMenu();
|
auto menu = engine->getGUI()->getMenu();
|
||||||
menus::refresh_menus(engine, menu);
|
menus::refresh_menus(engine, menu);
|
||||||
menu->reset();
|
menu->reset();
|
||||||
menu->set("main");
|
menu->set("main");
|
||||||
|
|
||||||
batch = new Batch2D(1024);
|
|
||||||
uicamera = new Camera(vec3(), Window::height);
|
uicamera = new Camera(vec3(), Window::height);
|
||||||
uicamera->perspective = false;
|
uicamera->perspective = false;
|
||||||
uicamera->flipped = true;
|
uicamera->flipped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuScreen::~MenuScreen() {
|
MenuScreen::~MenuScreen() {
|
||||||
delete batch;
|
|
||||||
delete uicamera;
|
delete uicamera;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,7 +159,7 @@ void LevelScreen::draw(float delta) {
|
||||||
Camera* camera = level->player->currentViewCamera;
|
Camera* camera = level->player->currentViewCamera;
|
||||||
|
|
||||||
Viewport viewport(Window::width, Window::height);
|
Viewport viewport(Window::width, Window::height);
|
||||||
GfxContext ctx(nullptr, viewport, nullptr);
|
GfxContext ctx(nullptr, viewport, batch.get());
|
||||||
|
|
||||||
worldRenderer->draw(ctx, camera);
|
worldRenderer->draw(ctx, camera);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,15 @@ class LevelController;
|
||||||
class Screen {
|
class Screen {
|
||||||
protected:
|
protected:
|
||||||
Engine* engine;
|
Engine* engine;
|
||||||
|
std::unique_ptr<Batch2D> batch;
|
||||||
public:
|
public:
|
||||||
Screen(Engine* engine) : engine(engine) {};
|
Screen(Engine* engine);
|
||||||
virtual ~Screen() {};
|
virtual ~Screen();
|
||||||
virtual void update(float delta) = 0;
|
virtual void update(float delta) = 0;
|
||||||
virtual void draw(float delta) = 0;
|
virtual void draw(float delta) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MenuScreen : public Screen {
|
class MenuScreen : public Screen {
|
||||||
Batch2D* batch;
|
|
||||||
Camera* uicamera;
|
Camera* uicamera;
|
||||||
public:
|
public:
|
||||||
MenuScreen(Engine* engine);
|
MenuScreen(Engine* engine);
|
||||||
|
|
@ -42,6 +42,7 @@ class LevelScreen : public Screen {
|
||||||
WorldRenderer* worldRenderer;
|
WorldRenderer* worldRenderer;
|
||||||
HudRenderer* hud;
|
HudRenderer* hud;
|
||||||
ContentGfxCache* cache;
|
ContentGfxCache* cache;
|
||||||
|
|
||||||
bool hudVisible = true;
|
bool hudVisible = true;
|
||||||
void updateHotkeys();
|
void updateHotkeys();
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -82,9 +82,39 @@ void ImageData::flipY() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageData::blit(const ImageData* image, int x, int y) {
|
void ImageData::blit(const ImageData* image, int x, int y) {
|
||||||
if (format != image->format) {
|
if (format == image->format) {
|
||||||
throw std::runtime_error("mismatching 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;
|
uint comps;
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case ImageFormat::rgb888: comps = 3; break;
|
case ImageFormat::rgb888: comps = 3; break;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ public:
|
||||||
void flipX();
|
void flipX();
|
||||||
void flipY();
|
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 blit(const ImageData* image, int x, int y);
|
||||||
void extrude(int x, int y, int w, int h);
|
void extrude(int x, int y, int w, int h);
|
||||||
void fixAlphaColor();
|
void fixAlphaColor();
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ void BlocksController::updateBlock(int x, int y, int z) {
|
||||||
if (vox == nullptr)
|
if (vox == nullptr)
|
||||||
return;
|
return;
|
||||||
const Block* def = level->content->indices->getBlockDef(vox->id);
|
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);
|
breakBlock(nullptr, def, x, y, z);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ void PlayerController::updateInteraction(){
|
||||||
if (!level->physics->isBlockInside(x,y,z, player->hitbox)
|
if (!level->physics->isBlockInside(x,y,z, player->hitbox)
|
||||||
|| !def->obstacle){
|
|| !def->obstacle){
|
||||||
Block* def = contentIds->getBlockDef(chosenBlock);
|
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;
|
chosenBlock = 0;
|
||||||
}
|
}
|
||||||
if (chosenBlock != vox->id) {
|
if (chosenBlock != vox->id) {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ int l_is_solid_at(lua_State* L) {
|
||||||
int y = lua_tointeger(L, 2);
|
int y = lua_tointeger(L, 2);
|
||||||
int z = lua_tointeger(L, 3);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,6 +60,13 @@ int l_get_block(lua_State* L) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int lua_pushivec3(lua_State* L, int x, int y, int z) {
|
||||||
|
lua_pushinteger(L, x);
|
||||||
|
lua_pushinteger(L, y);
|
||||||
|
lua_pushinteger(L, z);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
int l_get_player_pos(lua_State* L) {
|
int l_get_player_pos(lua_State* L) {
|
||||||
glm::vec3 pos = scripting::level->player->hitbox->position;
|
glm::vec3 pos = scripting::level->player->hitbox->position;
|
||||||
lua_pushnumber(L, pos.x);
|
lua_pushnumber(L, pos.x);
|
||||||
|
|
@ -103,12 +110,13 @@ int l_get_block_states(lua_State* L) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int l_is_replaceable_at(lua_State* L) {
|
int l_is_replaceable_at(lua_State* L) {
|
||||||
int x = lua_tointeger(L, 1);
|
int x = lua_tointeger(L, 1);
|
||||||
int y = lua_tointeger(L, 2);
|
int y = lua_tointeger(L, 2);
|
||||||
int z = lua_tointeger(L, 3);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,6 +235,7 @@ inline int lua_pushivec3(lua_State* L, int x, int y, int z) {
|
||||||
lua_pushinteger(L, z);
|
lua_pushinteger(L, z);
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
int l_get_block_x(lua_State* L) {
|
int l_get_block_x(lua_State* L) {
|
||||||
int x = lua_tointeger(L, 1);
|
int x = lua_tointeger(L, 1);
|
||||||
int y = lua_tointeger(L, 2);
|
int y = lua_tointeger(L, 2);
|
||||||
|
|
@ -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_is_replaceable_at, "is_replaceable_at");
|
||||||
lua_addfunc(L, l_set_block, "set_block");
|
lua_addfunc(L, l_set_block, "set_block");
|
||||||
lua_addfunc(L, l_get_block, "get_block");
|
lua_addfunc(L, l_get_block, "get_block");
|
||||||
|
lua_addfunc(L, l_get_block_x, "get_block_X");
|
||||||
|
lua_addfunc(L, l_get_block_y, "get_block_Y");
|
||||||
|
lua_addfunc(L, l_get_block_z, "get_block_Z");
|
||||||
lua_addfunc(L, l_get_player_pos, "get_player_pos");
|
lua_addfunc(L, l_get_player_pos, "get_player_pos");
|
||||||
lua_addfunc(L, l_set_player_pos, "set_player_pos");
|
lua_addfunc(L, l_set_player_pos, "set_player_pos");
|
||||||
lua_addfunc(L, l_get_player_rot, "get_player_rot");
|
lua_addfunc(L, l_get_player_rot, "get_player_rot");
|
||||||
|
|
@ -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_x, "get_block_X");
|
||||||
lua_addfunc(L, l_get_block_y, "get_block_Y");
|
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_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");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,14 @@ void scripting::initialize(EnginePaths* paths) {
|
||||||
if (L == nullptr) {
|
if (L == nullptr) {
|
||||||
throw std::runtime_error("could not to initialize Lua");
|
throw std::runtime_error("could not to initialize Lua");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allowed standard libraries
|
||||||
luaopen_base(L);
|
luaopen_base(L);
|
||||||
luaopen_math(L);
|
luaopen_math(L);
|
||||||
luaopen_table(L);
|
|
||||||
luaopen_string(L);
|
luaopen_string(L);
|
||||||
|
luaopen_table(L);
|
||||||
|
|
||||||
|
// io-manipulations will be implemented via api functions
|
||||||
|
|
||||||
std::cout << LUA_VERSION << std::endl;
|
std::cout << LUA_VERSION << std::endl;
|
||||||
# ifdef LUAJIT_VERSION
|
# ifdef LUAJIT_VERSION
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ struct AABB {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if given point is inside */
|
/* 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 p = min();
|
||||||
const glm::vec3 s = size();
|
const glm::vec3 s = size();
|
||||||
return !(pos.x < p.x || pos.y < p.y || pos.z < p.z ||
|
return !(pos.x < p.x || pos.y < p.y || pos.z < p.z ||
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,7 @@
|
||||||
|
|
||||||
#include "glm/glm.hpp"
|
#include "glm/glm.hpp"
|
||||||
|
|
||||||
std::unordered_map<rayvec3, AABBFaces> Ray::raysBoxCache_ = {};
|
static const rayvec3 X_AXIS = rayvec3(1,0,0), Y_AXIS = rayvec3(0,1,0), Z_AXIS = rayvec3(0,0,1);
|
||||||
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) {}
|
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 ),
|
rayvec2 yzMax = rayvec2(parentBoxPos.y + pbMax.y, parentBoxPos.z + pbMax.z ),
|
||||||
xzMax = rayvec2(parentBoxPos.x + pbMax.x, parentBoxPos.z + pbMax.z ),
|
xzMax = rayvec2(parentBoxPos.x + pbMax.x, parentBoxPos.z + pbMax.z ),
|
||||||
xyMax = rayvec2(parentBoxPos.x + pbMax.x, parentBoxPos.y + pbMax.y );
|
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::intersectYZFace(
|
||||||
RayRelation Ray::intersectAAFace<AAFaceKind::Xperp>(
|
|
||||||
const rayvec3& faceMin,
|
const rayvec3& faceMin,
|
||||||
const rayvec2& faceOppositeCorner, //y and z global coords of opposite corner
|
const rayvec2& faceOppositeCorner, //y and z global coords of opposite corner
|
||||||
glm::ivec3& normal_ret,
|
glm::ivec3& normal_ret,
|
||||||
|
|
@ -59,8 +58,7 @@ RayRelation Ray::intersectAAFace<AAFaceKind::Xperp>(
|
||||||
return RayRelation::None;
|
return RayRelation::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
RayRelation Ray::intersectXZFace(
|
||||||
RayRelation Ray::intersectAAFace<AAFaceKind::Yperp>(
|
|
||||||
const rayvec3& faceMin,
|
const rayvec3& faceMin,
|
||||||
const rayvec2& faceOppositeCorner, //x and z global coords of opposite corner
|
const rayvec2& faceOppositeCorner, //x and z global coords of opposite corner
|
||||||
glm::ivec3& normal_ret,
|
glm::ivec3& normal_ret,
|
||||||
|
|
@ -88,8 +86,7 @@ RayRelation Ray::intersectAAFace<AAFaceKind::Yperp>(
|
||||||
return RayRelation::None;
|
return RayRelation::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
RayRelation Ray::intersectXYFace(
|
||||||
RayRelation Ray::intersectAAFace<AAFaceKind::Zperp>(
|
|
||||||
const rayvec3& faceMin,
|
const rayvec3& faceMin,
|
||||||
const rayvec2& faceOppositeCorner, //x and y global coords of opposite corner
|
const rayvec2& faceOppositeCorner, //x and y global coords of opposite corner
|
||||||
glm::ivec3& normal_ret,
|
glm::ivec3& normal_ret,
|
||||||
|
|
@ -117,8 +114,7 @@ RayRelation Ray::intersectAAFace<AAFaceKind::Zperp>(
|
||||||
return RayRelation::None;
|
return RayRelation::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
RayRelation Ray::isIntersectsYZFace(
|
||||||
RayRelation Ray::isIntersectsAAFace<AAFaceKind::Xperp>(
|
|
||||||
const rayvec3& faceMin,
|
const rayvec3& faceMin,
|
||||||
const rayvec2& faceOppositeCorner
|
const rayvec2& faceOppositeCorner
|
||||||
){
|
){
|
||||||
|
|
@ -141,8 +137,7 @@ RayRelation Ray::isIntersectsAAFace<AAFaceKind::Xperp>(
|
||||||
return RayRelation::None;
|
return RayRelation::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
RayRelation Ray::isIntersectsXZFace(
|
||||||
RayRelation Ray::isIntersectsAAFace<AAFaceKind::Yperp>(
|
|
||||||
const rayvec3& faceMin,
|
const rayvec3& faceMin,
|
||||||
const rayvec2& faceOppositeCorner
|
const rayvec2& faceOppositeCorner
|
||||||
) {
|
) {
|
||||||
|
|
@ -165,8 +160,7 @@ RayRelation Ray::isIntersectsAAFace<AAFaceKind::Yperp>(
|
||||||
return RayRelation::None;
|
return RayRelation::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
RayRelation Ray::isIntersectsXYFace(
|
||||||
RayRelation Ray::isIntersectsAAFace<AAFaceKind::Zperp>(
|
|
||||||
const rayvec3& faceMin,
|
const rayvec3& faceMin,
|
||||||
const rayvec2& faceOppositeCorner
|
const rayvec2& faceOppositeCorner
|
||||||
) {
|
) {
|
||||||
|
|
@ -195,29 +189,15 @@ RayRelation Ray::intersectAABB(
|
||||||
float maxDist,
|
float maxDist,
|
||||||
glm::ivec3& normal_ret,
|
glm::ivec3& normal_ret,
|
||||||
scalar_t& distance_ret){
|
scalar_t& distance_ret){
|
||||||
if constexpr (IS_RAYS_BOX_CACHE_ON){
|
const AABBFaces& boxFaces = AABBFaces(boxPos, box);
|
||||||
|
return intersectAABBFaces(boxFaces, maxDist, normal_ret, distance_ret);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RayRelation Ray::intersectAABBFaces(
|
RayRelation Ray::intersectAABBFaces(
|
||||||
const AABBFaces& boxFaces,
|
const AABBFaces& boxFaces,
|
||||||
float maxDist,
|
float maxDist,
|
||||||
glm::ivec3& normal_ret,
|
glm::ivec3& normal_ret,
|
||||||
scalar_t& distance_ret){//TODO: points returning
|
scalar_t& distance_ret){
|
||||||
|
|
||||||
scalar_t faceDist;
|
scalar_t faceDist;
|
||||||
distance_ret = maxDist;
|
distance_ret = maxDist;
|
||||||
|
|
@ -225,7 +205,7 @@ RayRelation Ray::intersectAABBFaces(
|
||||||
//unsigned char intersectedCount = 0; //this code is very uncomfortable, DONT LEARN IT!
|
//unsigned char intersectedCount = 0; //this code is very uncomfortable, DONT LEARN IT!
|
||||||
bool isIntersect = false;
|
bool isIntersect = false;
|
||||||
|
|
||||||
if (intersectAAFace<AABBFaces::KINDS_ORDER[0]>(
|
if (intersectYZFace(
|
||||||
boxFaces.faces[0].first, boxFaces.faces[0].second, bufNormal, faceDist
|
boxFaces.faces[0].first, boxFaces.faces[0].second, bufNormal, faceDist
|
||||||
) > RayRelation::None && faceDist < distance_ret){
|
) > RayRelation::None && faceDist < distance_ret){
|
||||||
isIntersect = true;
|
isIntersect = true;
|
||||||
|
|
@ -233,7 +213,7 @@ RayRelation Ray::intersectAABBFaces(
|
||||||
distance_ret = faceDist;
|
distance_ret = faceDist;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intersectAAFace<AABBFaces::KINDS_ORDER[1]>(
|
if (intersectYZFace(
|
||||||
boxFaces.faces[1].first, boxFaces.faces[1].second, bufNormal, faceDist
|
boxFaces.faces[1].first, boxFaces.faces[1].second, bufNormal, faceDist
|
||||||
) > RayRelation::None && faceDist < distance_ret) {
|
) > RayRelation::None && faceDist < distance_ret) {
|
||||||
isIntersect = true;
|
isIntersect = true;
|
||||||
|
|
@ -241,7 +221,7 @@ RayRelation Ray::intersectAABBFaces(
|
||||||
distance_ret = faceDist;
|
distance_ret = faceDist;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intersectAAFace<AABBFaces::KINDS_ORDER[2]>(
|
if (intersectXZFace(
|
||||||
boxFaces.faces[2].first, boxFaces.faces[2].second, bufNormal, faceDist
|
boxFaces.faces[2].first, boxFaces.faces[2].second, bufNormal, faceDist
|
||||||
) > RayRelation::None && faceDist < distance_ret) {
|
) > RayRelation::None && faceDist < distance_ret) {
|
||||||
isIntersect = true;
|
isIntersect = true;
|
||||||
|
|
@ -249,7 +229,7 @@ RayRelation Ray::intersectAABBFaces(
|
||||||
distance_ret = faceDist;
|
distance_ret = faceDist;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intersectAAFace<AABBFaces::KINDS_ORDER[3]>(
|
if (intersectXZFace(
|
||||||
boxFaces.faces[3].first, boxFaces.faces[3].second, bufNormal, faceDist
|
boxFaces.faces[3].first, boxFaces.faces[3].second, bufNormal, faceDist
|
||||||
) > RayRelation::None && faceDist < distance_ret) {
|
) > RayRelation::None && faceDist < distance_ret) {
|
||||||
isIntersect = true;
|
isIntersect = true;
|
||||||
|
|
@ -257,7 +237,7 @@ RayRelation Ray::intersectAABBFaces(
|
||||||
distance_ret = faceDist;
|
distance_ret = faceDist;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intersectAAFace<AABBFaces::KINDS_ORDER[4]>(
|
if (intersectXYFace(
|
||||||
boxFaces.faces[4].first, boxFaces.faces[4].second, bufNormal, faceDist
|
boxFaces.faces[4].first, boxFaces.faces[4].second, bufNormal, faceDist
|
||||||
) > RayRelation::None && faceDist < distance_ret) {
|
) > RayRelation::None && faceDist < distance_ret) {
|
||||||
isIntersect = true;
|
isIntersect = true;
|
||||||
|
|
@ -265,7 +245,7 @@ RayRelation Ray::intersectAABBFaces(
|
||||||
distance_ret = faceDist;
|
distance_ret = faceDist;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intersectAAFace<AABBFaces::KINDS_ORDER[5]>(
|
if (intersectXYFace(
|
||||||
boxFaces.faces[5].first, boxFaces.faces[5].second, bufNormal, faceDist
|
boxFaces.faces[5].first, boxFaces.faces[5].second, bufNormal, faceDist
|
||||||
) > RayRelation::None && faceDist < distance_ret) {
|
) > RayRelation::None && faceDist < distance_ret) {
|
||||||
isIntersect = true;
|
isIntersect = true;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
#include "glm/gtx/hash.hpp"
|
#include "glm/gtx/hash.hpp"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
typedef glm::highp_dvec3 rayvec3;
|
typedef glm::highp_dvec3 rayvec3;
|
||||||
typedef glm::highp_dvec2 rayvec2;
|
typedef glm::highp_dvec2 rayvec2;
|
||||||
|
|
@ -17,31 +16,18 @@ typedef double scalar_t;
|
||||||
enum class RayRelation{
|
enum class RayRelation{
|
||||||
Embed=2, Intersect=1, Parallel=0, None=0
|
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{
|
class AABBFaces{
|
||||||
|
static const unsigned char AABBFACES_COUNT = 6;
|
||||||
public:
|
public:
|
||||||
std::array<std::pair<rayvec3, rayvec2>, AABBFACES_COUNT> faces; // every face is min-point and opposite corner point
|
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(){};
|
||||||
AABBFaces(const rayvec3& parentBoxPos, const AABB& parentBox);
|
AABBFaces(const rayvec3& parentBoxPos, const AABB& parentBox);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Ray{
|
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:
|
public:
|
||||||
rayvec3 origin;
|
rayvec3 origin;
|
||||||
rayvec3 dir;
|
rayvec3 dir;
|
||||||
|
|
@ -49,39 +35,32 @@ public:
|
||||||
Ray(const rayvec3& rayOrigin,
|
Ray(const rayvec3& rayOrigin,
|
||||||
const rayvec3& rayDir);
|
const rayvec3& rayDir);
|
||||||
|
|
||||||
//optimized, NOT returns intersectPoint coordinates and normal vector
|
RayRelation isIntersectsYZFace(
|
||||||
template <AAFaceKind faceKind>
|
const rayvec3& faceMin,
|
||||||
RayRelation isIntersectsAAFace(
|
const rayvec2& faceOppositeCorner);
|
||||||
const rayvec3& faceMin,
|
RayRelation isIntersectsXZFace(
|
||||||
const rayvec2& faceOppositeCorner
|
const rayvec3& faceMin,
|
||||||
);
|
const rayvec2& faceOppositeCorner);
|
||||||
|
RayRelation isIntersectsXYFace(
|
||||||
//returns only normal
|
const rayvec3& faceMin,
|
||||||
template <AAFaceKind faceKind>
|
const rayvec2& faceOppositeCorner);
|
||||||
RayRelation intersectAAFace(
|
|
||||||
const rayvec3& faceMin,
|
|
||||||
const rayvec2& faceOppositeCorner,
|
|
||||||
glm::ivec3& normal_ret
|
|
||||||
);
|
|
||||||
|
|
||||||
//returns normal and distance
|
//returns normal and distance
|
||||||
template <AAFaceKind faceKind>
|
RayRelation intersectYZFace(
|
||||||
RayRelation intersectAAFace(
|
const rayvec3& faceMin,
|
||||||
const rayvec3& faceMin,
|
const rayvec2& faceOppositeCorner,
|
||||||
const rayvec2& faceOppositeCorner,
|
glm::ivec3& normal_ret,
|
||||||
glm::ivec3& normal_ret,
|
scalar_t& distance_ret);
|
||||||
scalar_t& distance_ret
|
RayRelation intersectXZFace(
|
||||||
);
|
const rayvec3& faceMin,
|
||||||
|
const rayvec2& faceOppositeCorner,
|
||||||
// returns normal, distance and intersection point
|
glm::ivec3& normal_ret,
|
||||||
template <AAFaceKind faceKind>
|
scalar_t& distance_ret);
|
||||||
RayRelation intersectAAFace(
|
RayRelation intersectXYFace(
|
||||||
const rayvec3& faceMin,
|
const rayvec3& faceMin,
|
||||||
const rayvec2& faceOppositeCorner,
|
const rayvec2& faceOppositeCorner,
|
||||||
glm::ivec3& normal_ret,
|
glm::ivec3& normal_ret,
|
||||||
scalar_t& distance_ret,
|
scalar_t& distance_ret);
|
||||||
rayvec3& intersectPoint_ret
|
|
||||||
);
|
|
||||||
|
|
||||||
RayRelation intersectAABB(
|
RayRelation intersectAABB(
|
||||||
const rayvec3& boxPos,
|
const rayvec3& boxPos,
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ void PhysicsSolver::step(
|
||||||
hitbox->grounded = false;
|
hitbox->grounded = false;
|
||||||
for (float x = (px-half.x+E); x <= (px+half.x-E); x+=s){
|
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){
|
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;
|
hitbox->grounded = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +58,7 @@ void PhysicsSolver::step(
|
||||||
hitbox->grounded = false;
|
hitbox->grounded = false;
|
||||||
for (float x = (pos.x-half.x+E); x <= (pos.x+half.x-E); x+=s){
|
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){
|
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;
|
hitbox->grounded = true;
|
||||||
break;
|
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 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){
|
for (float z = (pos.z-half.z+E); z <= (pos.z+half.z-E); z+=s){
|
||||||
float x = (pos.x-half.x-E);
|
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;
|
vel.x *= 0.0f;
|
||||||
pos.x = floor(x) + aabb->max().x + half.x + E;
|
pos.x = floor(x) + aabb->max().x + half.x + E;
|
||||||
break;
|
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 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){
|
for (float z = (pos.z-half.z+E); z <= (pos.z+half.z-E); z+=s){
|
||||||
float x = (pos.x+half.x+E);
|
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;
|
vel.x *= 0.0f;
|
||||||
pos.x = floor(x) - half.x + aabb->min().x - E;
|
pos.x = floor(x) - half.x + aabb->min().x - E;
|
||||||
break;
|
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 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){
|
for (float x = (pos.x-half.x+E); x <= (pos.x+half.x-E); x+=s){
|
||||||
float z = (pos.z-half.z-E);
|
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;
|
vel.z *= 0.0f;
|
||||||
pos.z = floor(z) + aabb->max().z + half.z + E;
|
pos.z = floor(z) + aabb->max().z + half.z + E;
|
||||||
break;
|
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 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){
|
for (float x = (pos.x-half.x+E); x <= (pos.x+half.x-E); x+=s){
|
||||||
float z = (pos.z+half.z+E);
|
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;
|
vel.z *= 0.0f;
|
||||||
pos.z = floor(z) - half.z + aabb->min().z - E;
|
pos.z = floor(z) - half.z + aabb->min().z - E;
|
||||||
break;
|
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 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){
|
for (float z = (pos.z-half.z+E); z <= (pos.z+half.z-E); z+=s){
|
||||||
float y = (pos.y-half.y-E);
|
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;
|
vel.y *= 0.0f;
|
||||||
pos.y = floor(y) + aabb->max().y + half.y;
|
pos.y = floor(y) + aabb->max().y + half.y;
|
||||||
hitbox->grounded = true;
|
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 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){
|
for (float z = (pos.z-half.z+E); z <= (pos.z+half.z-E); z+=s){
|
||||||
float y = (pos.y+half.y+E);
|
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;
|
vel.y *= 0.0f;
|
||||||
pos.y = floor(y) - half.y + aabb->min().y - E;
|
pos.y = floor(y) - half.y + aabb->min().y - E;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,8 @@ typedef uint16_t u_short16;
|
||||||
typedef uint32_t u_int32;
|
typedef uint32_t u_int32;
|
||||||
typedef uint64_t u_long64;
|
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 blockid_t;
|
||||||
|
typedef uint16_t blockstate_t;
|
||||||
typedef uint16_t light_t;
|
typedef uint16_t light_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -4,42 +4,36 @@
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
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) {
|
bool parse_cmdline(int argc, char** argv, EnginePaths& paths) {
|
||||||
ArgsReader reader(argc, argv);
|
ArgsReader reader(argc, argv);
|
||||||
reader.skip();
|
reader.skip();
|
||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
string token = reader.next();
|
std::string token = reader.next();
|
||||||
if (reader.isKeywordArg()) {
|
if (reader.isKeywordArg()) {
|
||||||
if (token == "--res") {
|
if (token == "--res") {
|
||||||
token = reader.next();
|
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");
|
throw std::runtime_error(token+" is not a directory");
|
||||||
}
|
}
|
||||||
paths.setResources(path(token));
|
paths.setResources(fs::path(token));
|
||||||
cout << "resources folder: " << token << std::endl;
|
std::cout << "resources folder: " << token << std::endl;
|
||||||
} else if (token == "--dir") {
|
} else if (token == "--dir") {
|
||||||
token = reader.next();
|
token = reader.next();
|
||||||
if (!fs::is_directory(path(token))) {
|
if (!fs::is_directory(fs::path(token))) {
|
||||||
fs::create_directories(path(token));
|
fs::create_directories(fs::path(token));
|
||||||
}
|
}
|
||||||
paths.setUserfiles(path(token));
|
paths.setUserfiles(fs::path(token));
|
||||||
cout << "userfiles folder: " << token << endl;
|
std::cout << "userfiles folder: " << token << std::endl;
|
||||||
} else if (token == "--help" || token == "-h") {
|
} else if (token == "--help" || token == "-h") {
|
||||||
cout << "VoxelEngine command-line arguments:" << endl;
|
std::cout << "VoxelEngine command-line arguments:" << std::endl;
|
||||||
cout << " --res [path] - set resources directory" << endl;
|
std::cout << " --res [path] - set resources directory" << std::endl;
|
||||||
cout << " --dir [path] - set userfiles directory" << endl;
|
std::cout << " --dir [path] - set userfiles directory" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
cerr << "unknown argument " << token << endl;
|
std::cerr << "unknown argument " << token << std::endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cerr << "unexpected token" << endl;
|
std::cerr << "unexpected token" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,11 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
using std::vector;
|
std::wstring util::lfill(std::wstring s, uint length, wchar_t c) {
|
||||||
using std::string;
|
|
||||||
using std::stringstream;
|
|
||||||
using std::wstring;
|
|
||||||
using std::wstringstream;
|
|
||||||
|
|
||||||
wstring util::lfill(wstring s, uint length, wchar_t c) {
|
|
||||||
if (s.length() >= length) {
|
if (s.length() >= length) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
wstringstream ss;
|
std::wstringstream ss;
|
||||||
for (uint i = 0; i < length-s.length(); i++) {
|
for (uint i = 0; i < length-s.length(); i++) {
|
||||||
ss << c;
|
ss << c;
|
||||||
}
|
}
|
||||||
|
|
@ -24,11 +18,11 @@ wstring util::lfill(wstring s, uint length, wchar_t c) {
|
||||||
return ss.str();
|
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) {
|
if (s.length() >= length) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
wstringstream ss;
|
std::wstringstream ss;
|
||||||
ss << s;
|
ss << s;
|
||||||
for (uint i = 0; i < length-s.length(); i++) {
|
for (uint i = 0; i < length-s.length(); i++) {
|
||||||
ss << c;
|
ss << c;
|
||||||
|
|
@ -103,8 +97,8 @@ extern uint32_t util::decode_utf8(uint& size, const char* chr) {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
string util::wstr2str_utf8(const wstring ws) {
|
std::string util::wstr2str_utf8(const std::wstring ws) {
|
||||||
vector<char> chars;
|
std::vector<char> chars;
|
||||||
char buffer[4];
|
char buffer[4];
|
||||||
for (wchar_t wc : ws) {
|
for (wchar_t wc : ws) {
|
||||||
uint size = encode_utf8((uint)wc, (u_char8*)buffer);
|
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]);
|
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) {
|
std::wstring util::str2wstr_utf8(const std::string s) {
|
||||||
vector<wchar_t> chars;
|
std::vector<wchar_t> chars;
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
uint size = 0;
|
uint size = 0;
|
||||||
while (pos < s.length()) {
|
while (pos < s.length()) {
|
||||||
chars.push_back(decode_utf8(size, &s.at(pos)));
|
chars.push_back(decode_utf8(size, &s.at(pos)));
|
||||||
pos += size;
|
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) {
|
for (char c : text) {
|
||||||
if (c < '0' || c > '9')
|
if (c < '0' || c > '9')
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -134,7 +128,7 @@ bool util::is_integer(string text) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool util::is_integer(wstring text) {
|
bool util::is_integer(std::wstring text) {
|
||||||
for (wchar_t c : text) {
|
for (wchar_t c : text) {
|
||||||
if (c < L'0' || c > L'9')
|
if (c < L'0' || c > L'9')
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,13 @@ void CoordSystem::transform(AABB& aabb) const {
|
||||||
aabb.b += fix;
|
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
|
{ { 1, 0, 0 }, { 0, 0, 1 }, { 0, -1, 0 }}, // North
|
||||||
{ { 0, 0, 1 }, {-1, 0, 0 }, { 0, -1, 0 }}, // East
|
{ { 0, 0, 1 }, {-1, 0, 0 }, { 0, -1, 0 }}, // East
|
||||||
{ { -1, 0, 0 }, { 0, 0,-1 }, { 0, -1, 0 }}, // South
|
{ {-1, 0, 0 }, { 0, 0,-1 }, { 0, -1, 0 }}, // South
|
||||||
{ { 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }}, // West
|
{ { 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 }}, // Up
|
||||||
{ { 1, 0, 0 }, { 0,-1, 0 }, { 0, 0,-1 }}, // Down
|
{ { 1, 0, 0 }, { 0,-1, 0 }, { 0, 0,-1 }}, // Down
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const BlockRotProfile BlockRotProfile::PANE {"pane", {
|
const BlockRotProfile BlockRotProfile::PANE {"pane", {
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ struct CoordSystem {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BlockRotProfile {
|
struct BlockRotProfile {
|
||||||
static const int MAX_COUNT = 16;
|
static const int MAX_COUNT = 8;
|
||||||
std::string name;
|
std::string name;
|
||||||
CoordSystem variants[MAX_COUNT];
|
CoordSystem variants[MAX_COUNT];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
#include "Chunk.h"
|
#include "Chunk.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "voxel.h"
|
#include "voxel.h"
|
||||||
#include "../content/ContentLUT.h"
|
#include "../content/ContentLUT.h"
|
||||||
#include "../lighting/Lightmap.h"
|
#include "../lighting/Lightmap.h"
|
||||||
|
|
@ -22,7 +25,7 @@ Chunk::~Chunk(){
|
||||||
|
|
||||||
bool Chunk::isEmpty(){
|
bool Chunk::isEmpty(){
|
||||||
int id = -1;
|
int id = -1;
|
||||||
for (int i = 0; i < CHUNK_VOL; i++){
|
for (size_t i = 0; i < CHUNK_VOL; i++){
|
||||||
if (voxels[i].id != id){
|
if (voxels[i].id != id){
|
||||||
if (id != -1)
|
if (id != -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -34,14 +37,14 @@ bool Chunk::isEmpty(){
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chunk::updateHeights() {
|
void Chunk::updateHeights() {
|
||||||
for (int i = 0; i < CHUNK_VOL; i++) {
|
for (size_t i = 0; i < CHUNK_VOL; i++) {
|
||||||
if (voxels[i].id != 0) {
|
if (voxels[i].id != 0) {
|
||||||
bottom = i / (CHUNK_D * CHUNK_W);
|
bottom = i / (CHUNK_D * CHUNK_W);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = CHUNK_VOL - 1; i > -1; i--) {
|
for (int i = CHUNK_VOL - 1; i >= 0; i--) {
|
||||||
if (voxels[i].id != 0) {
|
if (voxels[i].id != 0) {
|
||||||
top = i / (CHUNK_D * CHUNK_W) + 1;
|
top = i / (CHUNK_D * CHUNK_W) + 1;
|
||||||
break;
|
break;
|
||||||
|
|
@ -51,7 +54,7 @@ void Chunk::updateHeights() {
|
||||||
|
|
||||||
Chunk* Chunk::clone() const {
|
Chunk* Chunk::clone() const {
|
||||||
Chunk* other = new Chunk(x,z);
|
Chunk* other = new Chunk(x,z);
|
||||||
for (int i = 0; i < CHUNK_VOL; i++)
|
for (size_t i = 0; i < CHUNK_VOL; i++)
|
||||||
other->voxels[i] = voxels[i];
|
other->voxels[i] = voxels[i];
|
||||||
other->lightmap->set(lightmap);
|
other->lightmap->set(lightmap);
|
||||||
return other;
|
return other;
|
||||||
|
|
@ -59,32 +62,68 @@ Chunk* Chunk::clone() const {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Current chunk format:
|
Current chunk format:
|
||||||
[voxel_ids...][voxel_states...];
|
- byte-order: big-endian
|
||||||
|
- [don't panic!] first and second bytes are separated for RLE efficiency
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
uint8_t voxel_id_first_byte[CHUNK_VOL];
|
||||||
|
uint8_t voxel_id_second_byte[CHUNK_VOL];
|
||||||
|
uint8_t voxel_states_first_byte[CHUNK_VOL];
|
||||||
|
uint8_t voxel_states_second_byte[CHUNK_VOL];
|
||||||
|
```
|
||||||
|
|
||||||
|
Total size: (CHUNK_VOL * 4) bytes
|
||||||
*/
|
*/
|
||||||
u_char8* Chunk::encode() const {
|
u_char8* Chunk::encode() const {
|
||||||
u_char8* buffer = new u_char8[CHUNK_DATA_LEN];
|
u_char8* buffer = new u_char8[CHUNK_DATA_LEN];
|
||||||
for (size_t i = 0; i < CHUNK_VOL; i++) {
|
for (size_t i = 0; i < CHUNK_VOL; i++) {
|
||||||
((u_short16*)buffer)[i] = voxels[i].id;
|
buffer[i] = voxels[i].id >> 8;
|
||||||
((u_short16*)buffer)[CHUNK_VOL + i] = voxels[i].states;
|
buffer[CHUNK_VOL+i] = voxels[i].id & 0xFF;
|
||||||
|
buffer[CHUNK_VOL*2 + i] = voxels[i].states >> 8;
|
||||||
|
buffer[CHUNK_VOL*3 + i] = voxels[i].states & 0xFF;
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@return true if all is fine
|
/**
|
||||||
*/
|
* @return true if all is fine
|
||||||
|
**/
|
||||||
bool Chunk::decode(u_char8* data) {
|
bool Chunk::decode(u_char8* data) {
|
||||||
for (size_t i = 0; i < CHUNK_VOL; i++) {
|
for (size_t i = 0; i < CHUNK_VOL; i++) {
|
||||||
voxel& vox = voxels[i];
|
voxel& vox = voxels[i];
|
||||||
vox.id = ((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;
|
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++) {
|
for (size_t i = 0; i < CHUNK_VOL; i++) {
|
||||||
blockid_t id = ((u_short16*)data)[i];
|
data[i + CHUNK_VOL*3] = data[i + CHUNK_VOL];
|
||||||
((u_short16*)data)[i] = lut->getBlockId(id);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ public:
|
||||||
u_char8* encode() const;
|
u_char8* encode() const;
|
||||||
bool decode(u_char8* data);
|
bool decode(u_char8* data);
|
||||||
|
|
||||||
|
static void fromOld(u_char8* data);
|
||||||
static void convert(u_char8* data, const ContentLUT* lut);
|
static void convert(u_char8* data, const ContentLUT* lut);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,17 +45,15 @@ Chunks::~Chunks(){
|
||||||
chunks[i] = nullptr;
|
chunks[i] = nullptr;
|
||||||
}
|
}
|
||||||
delete[] chunks;
|
delete[] chunks;
|
||||||
|
delete[] chunksSecond;
|
||||||
}
|
}
|
||||||
|
|
||||||
voxel* Chunks::get(int x, int y, int z){
|
voxel* Chunks::get(int x, int y, int z){
|
||||||
x -= ox * CHUNK_W;
|
x -= ox * CHUNK_W;
|
||||||
z -= oz * CHUNK_D;
|
z -= oz * CHUNK_D;
|
||||||
int cx = x / CHUNK_W;
|
int cx = floordiv(x, CHUNK_W);
|
||||||
int cy = y / CHUNK_H;
|
int cy = floordiv(y, CHUNK_H);
|
||||||
int cz = z / CHUNK_D;
|
int cz = floordiv(z, CHUNK_D);
|
||||||
if (x < 0) cx--;
|
|
||||||
if (y < 0) cy--;
|
|
||||||
if (z < 0) cz--;
|
|
||||||
if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= 1 || cz >= d)
|
if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= 1 || cz >= d)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
shared_ptr<Chunk> chunk = chunks[cz * w + cx]; // chunks is 2D-array
|
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];
|
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 ix = floor(x);
|
||||||
int iy = floor(y);
|
int iy = floor(y);
|
||||||
int iz = floor(z);
|
int iz = floor(z);
|
||||||
|
|
@ -82,7 +80,7 @@ const AABB* Chunks::isObstacle(float x, float y, float z){
|
||||||
if (def->rt.solid) {
|
if (def->rt.solid) {
|
||||||
return &hitbox;
|
return &hitbox;
|
||||||
} else {
|
} else {
|
||||||
if (hitbox.inside({x - ix, y - iy, z - iz}))
|
if (hitbox.contains({x - ix, y - iy, z - iz}))
|
||||||
return &hitbox;
|
return &hitbox;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -90,20 +88,27 @@ const AABB* Chunks::isObstacle(float x, float y, float z){
|
||||||
return nullptr;
|
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);
|
voxel* v = get(x, y, z);
|
||||||
if (v == nullptr)
|
if (v == nullptr)
|
||||||
return false;
|
return false;
|
||||||
return contentIds->getBlockDef(v->id)->rt.solid;
|
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);
|
voxel* v = get(x, y, z);
|
||||||
if (v == nullptr)
|
if (v == nullptr)
|
||||||
return false;
|
return false;
|
||||||
return contentIds->getBlockDef(v->id)->replaceable;
|
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){
|
u_char8 Chunks::getLight(int x, int y, int z, int channel){
|
||||||
x -= ox * CHUNK_W;
|
x -= ox * CHUNK_W;
|
||||||
z -= oz * CHUNK_D;
|
z -= oz * CHUNK_D;
|
||||||
|
|
@ -233,7 +238,7 @@ voxel* Chunks::rayCast(vec3 start,
|
||||||
|
|
||||||
while (t <= maxDist){
|
while (t <= maxDist){
|
||||||
voxel* voxel = get(ix, iy, iz);
|
voxel* voxel = get(ix, iy, iz);
|
||||||
if (!voxel){ return nullptr; }
|
if (voxel == nullptr){ return nullptr; }
|
||||||
|
|
||||||
const Block* def = contentIds->getBlockDef(voxel->id);
|
const Block* def = contentIds->getBlockDef(voxel->id);
|
||||||
if (def->selectable){
|
if (def->selectable){
|
||||||
|
|
@ -338,7 +343,7 @@ vec3 Chunks::rayCastToObstacle(vec3 start, vec3 dir, float maxDist) {
|
||||||
|
|
||||||
while (t <= maxDist) {
|
while (t <= maxDist) {
|
||||||
voxel* voxel = get(ix, iy, iz);
|
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);
|
const Block* def = contentIds->getBlockDef(voxel->id);
|
||||||
if (def->obstacle) {
|
if (def->obstacle) {
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,10 @@ public:
|
||||||
|
|
||||||
glm::vec3 rayCastToObstacle(glm::vec3 start, glm::vec3 dir, float maxDist);
|
glm::vec3 rayCastToObstacle(glm::vec3 start, glm::vec3 dir, float maxDist);
|
||||||
|
|
||||||
const AABB* isObstacle(float x, float y, float z);
|
const AABB* isObstacleAt(float x, float y, float z);
|
||||||
bool isSolid(int x, int y, int z);
|
bool isSolidBlock(int x, int y, int z);
|
||||||
bool isReplaceable(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
|
// does not move chunks inside
|
||||||
void _setOffset(int x, int z);
|
void _setOffset(int x, int z);
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
std::shared_ptr<Chunk> ChunksStorage::create(int x, int z) {
|
||||||
World* world = level->world;
|
World* world = level->world;
|
||||||
|
|
||||||
auto chunk = shared_ptr<Chunk>(new Chunk(x, z));
|
auto chunk = std::make_shared<Chunk>(x, z);
|
||||||
store(chunk);
|
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) {
|
if (data) {
|
||||||
chunk->decode(data.get());
|
chunk->decode(data.get());
|
||||||
chunk->setLoaded(true);
|
chunk->setLoaded(true);
|
||||||
}
|
verifyLoadedChunk(level->content->indices, chunk.get());
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
light_t* lights = world->wfile->getLights(chunk->x, chunk->z);
|
light_t* lights = world->wfile->getLights(chunk->x, chunk->z);
|
||||||
|
|
|
||||||
|
|
@ -298,6 +298,10 @@ ImageData* Window::takeScreenshot() {
|
||||||
return new ImageData(ImageFormat::rgb888, width, height, data);
|
return new ImageData(ImageFormat::rgb888, width, height, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* Window::getClipboardText() {
|
||||||
|
return glfwGetClipboardString(window);
|
||||||
|
}
|
||||||
|
|
||||||
bool Window::tryToMaximize(GLFWwindow* window, GLFWmonitor* monitor) {
|
bool Window::tryToMaximize(GLFWwindow* window, GLFWmonitor* monitor) {
|
||||||
glm::ivec4 windowFrame(0);
|
glm::ivec4 windowFrame(0);
|
||||||
glm::ivec4 workArea(0);
|
glm::ivec4 workArea(0);
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ public:
|
||||||
static void clearDepth();
|
static void clearDepth();
|
||||||
static void setBgColor(glm::vec3 color);
|
static void setBgColor(glm::vec3 color);
|
||||||
static double time();
|
static double time();
|
||||||
|
static const char* getClipboardText();
|
||||||
static DisplaySettings* getSettings();
|
static DisplaySettings* getSettings();
|
||||||
|
|
||||||
static glm::vec2 size() {
|
static glm::vec2 size() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue