diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index 1d27e06e..0334db9a 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -117,11 +117,12 @@ void AssetsLoader::processPreloadList(AssetType tag, dynamic::List* list) { auto value = list->get(i); switch (value->type) { case dynamic::valtype::string: - processPreload(tag, *value->value.str, nullptr); + processPreload(tag, std::get(value->value), nullptr); break; case dynamic::valtype::map: { - auto name = value->value.map->getStr("name"); - processPreload(tag, name, value->value.map); + auto map = std::get(value->value); + auto name = map->getStr("name"); + processPreload(tag, name, map); break; } default: diff --git a/src/coders/binary_json.cpp b/src/coders/binary_json.cpp index 04d91dfa..bed39be2 100644 --- a/src/coders/binary_json.cpp +++ b/src/coders/binary_json.cpp @@ -10,20 +10,22 @@ using namespace dynamic; static void to_binary(ByteBuilder& builder, const Value* value) { switch (value->type) { + case valtype::none: + throw std::runtime_error("none value is not implemented"); case valtype::map: { - std::vector bytes = to_binary(value->value.map); + std::vector bytes = to_binary(std::get(value->value)); builder.put(bytes.data(), bytes.size()); break; } case valtype::list: builder.put(BJSON_TYPE_LIST); - for (auto& element : value->value.list->values) { + for (auto& element : std::get(value->value)->values) { to_binary(builder, element.get()); } builder.put(BJSON_END); break; case valtype::integer: { - int64_t val = value->value.integer; + auto val = std::get(value->value); if (val >= 0 && val <= 255) { builder.put(BJSON_TYPE_BYTE); builder.put(val); @@ -41,14 +43,14 @@ static void to_binary(ByteBuilder& builder, const Value* value) { } case valtype::number: builder.put(BJSON_TYPE_NUMBER); - builder.putFloat64(value->value.decimal); + builder.putFloat64(std::get(value->value)); break; case valtype::boolean: - builder.put(BJSON_TYPE_FALSE + value->value.boolean); + builder.put(BJSON_TYPE_FALSE + std::get(value->value)); break; case valtype::string: builder.put(BJSON_TYPE_STRING); - builder.put(*value->value.str); + builder.put(std::get(value->value)); break; } } @@ -88,40 +90,40 @@ static Value* value_from_binary(ByteReader& reader) { case BJSON_TYPE_DOCUMENT: type = valtype::map; reader.getInt32(); - val.map = object_from_binary(reader); + val = object_from_binary(reader); break; case BJSON_TYPE_LIST: type = valtype::list; - val.list = array_from_binary(reader); + val = array_from_binary(reader); break; case BJSON_TYPE_BYTE: type = valtype::integer; - val.integer = reader.get(); + val = reader.get(); break; case BJSON_TYPE_INT16: type = valtype::integer; - val.integer = reader.getInt16(); + val = reader.getInt16(); break; case BJSON_TYPE_INT32: type = valtype::integer; - val.integer = reader.getInt32(); + val = reader.getInt32(); break; case BJSON_TYPE_INT64: type = valtype::integer; - val.integer = reader.getInt64(); + val = reader.getInt64(); break; case BJSON_TYPE_NUMBER: type = valtype::number; - val.decimal = reader.getFloat64(); + val = reader.getFloat64(); break; case BJSON_TYPE_FALSE: case BJSON_TYPE_TRUE: type = valtype::boolean; - val.boolean = typecode - BJSON_TYPE_FALSE; + val = typecode - BJSON_TYPE_FALSE; break; case BJSON_TYPE_STRING: type = valtype::string; - val.str = new std::string(reader.getString()); + val = reader.getString(); break; default: throw std::runtime_error( @@ -166,8 +168,8 @@ std::unique_ptr json::from_binary(const ubyte* src, size_t size) { if (value->type != valtype::map) { throw std::runtime_error("root value is not an object"); } - std::unique_ptr obj (value->value.map); - value->value.map = nullptr; + std::unique_ptr obj (std::get(value->value)); + value->value = (Map*)nullptr; return obj; } } diff --git a/src/coders/json.cpp b/src/coders/json.cpp index 31440b7d..315e103e 100644 --- a/src/coders/json.cpp +++ b/src/coders/json.cpp @@ -42,10 +42,11 @@ void stringify(const Value* value, const std::string& indentstr, bool nice) { if (value->type == valtype::map) { - stringifyObj(value->value.map, ss, indent, indentstr, nice); + auto map = std::get(value->value); + stringifyObj(map, ss, indent, indentstr, nice); } else if (value->type == valtype::list) { - auto list = value->value.list; + auto list = std::get(value->value); if (list->size() == 0) { ss << "[]"; return; @@ -66,14 +67,14 @@ void stringify(const Value* value, } ss << ']'; } else if (value->type == valtype::boolean) { - ss << (value->value.boolean ? "true" : "false"); + ss << (std::get(value->value) ? "true" : "false"); } else if (value->type == valtype::number) { ss << std::setprecision(15); - ss << value->value.decimal; + ss << std::get(value->value); } else if (value->type == valtype::integer) { - ss << value->value.integer; + ss << std::get(value->value); } else if (value->type == valtype::string) { - ss << escape_string(*value->value.str); + ss << escape_string(std::get(value->value)); } } @@ -189,10 +190,10 @@ Value* Parser::parseValue() { number_u num; valtype type; if (parseNumber(next == '-' ? -1 : 1, num)) { - val.integer = num.ival; + val = num.ival; type = valtype::integer; } else { - val.decimal = num.fval; + val = num.fval; type = valtype::number; } return new Value(type, val); @@ -200,43 +201,43 @@ Value* Parser::parseValue() { if (is_identifier_start(next)) { std::string literal = parseName(); if (literal == "true") { - val.boolean = true; + val = true; return new Value(valtype::boolean, val); } else if (literal == "false") { - val.boolean = false; + val = false; return new Value(valtype::boolean, val); } else if (literal == "inf") { - val.decimal = INFINITY; + val = INFINITY; return new Value(valtype::number, val); } else if (literal == "nan") { - val.decimal = NAN; + val = NAN; return new Value(valtype::number, val); } throw error("invalid literal "); } if (next == '{') { - val.map = parseObject(); + val = parseObject(); return new Value(valtype::map, val); } if (next == '[') { - val.list = parseList(); + val = parseList(); return new Value(valtype::list, val); } if (is_digit(next)) { number_u num; valtype type; if (parseNumber(1, num)) { - val.integer = num.ival; + val = num.ival; type = valtype::integer; } else { - val.decimal = num.fval; + val = num.fval; type = valtype::number; } return new Value(type, val); } if (next == '"' || next == '\'') { pos++; - val.str = new std::string(parseString(next)); + val = parseString(next); return new Value(valtype::string, val); } throw error("unexpected character '"+std::string({next})+"'"); diff --git a/src/data/dynamic.cpp b/src/data/dynamic.cpp index e7f1a10c..a6329da0 100644 --- a/src/data/dynamic.cpp +++ b/src/data/dynamic.cpp @@ -10,34 +10,34 @@ List::~List() { std::string List::str(size_t index) const { const auto& val = values[index]; switch (val->type) { - case valtype::string: return *val->value.str; - case valtype::boolean: return val->value.boolean ? "true" : "false"; - case valtype::number: return std::to_string(val->value.decimal); - case valtype::integer: return std::to_string(val->value.integer); + case valtype::string: return std::get(val->value); + case valtype::boolean: return std::get(val->value) ? "true" : "false"; + case valtype::number: return std::to_string(std::get(val->value)); + case valtype::integer: return std::to_string(std::get(val->value)); default: throw std::runtime_error("type error"); } } -double List::num(size_t index) const { +number_t List::num(size_t index) const { const auto& val = values[index]; switch (val->type) { - case valtype::number: return val->value.decimal; - case valtype::integer: return val->value.integer; - case valtype::string: return std::stoll(*val->value.str); - case valtype::boolean: return val->value.boolean; + case valtype::number: return std::get(val->value); + case valtype::integer: return std::get(val->value); + case valtype::string: return std::stoll(std::get(val->value)); + case valtype::boolean: return std::get(val->value); default: throw std::runtime_error("type error"); } } -int64_t List::integer(size_t index) const { +integer_t List::integer(size_t index) const { const auto& val = values[index]; switch (val->type) { - case valtype::number: return val->value.decimal; - case valtype::integer: return val->value.integer; - case valtype::string: return std::stoll(*val->value.str); - case valtype::boolean: return val->value.boolean; + case valtype::number: return std::get(val->value); + case valtype::integer: return std::get(val->value); + case valtype::string: return std::stoll(std::get(val->value)); + case valtype::boolean: return std::get(val->value); default: throw std::runtime_error("type error"); } @@ -47,21 +47,21 @@ Map* List::map(size_t index) const { if (values[index]->type != valtype::map) { throw std::runtime_error("type error"); } - return values[index]->value.map; + return std::get(values[index]->value); } List* List::list(size_t index) const { if (values[index]->type != valtype::list) { throw std::runtime_error("type error"); } - return values[index]->value.list; + return std::get(values[index]->value); } bool List::flag(size_t index) const { const auto& val = values[index]; switch (val->type) { - case valtype::integer: return val->value.integer; - case valtype::boolean: return val->value.boolean; + case valtype::integer: return std::get(val->value); + case valtype::boolean: return std::get(val->value); default: throw std::runtime_error("type error"); } @@ -75,9 +75,7 @@ Value* List::getValueWriteable(size_t index) const { } List& List::put(std::string value) { - valvalue val; - val.str = new std::string(value); - values.push_back(std::make_unique(valtype::string, val)); + values.push_back(std::make_unique(valtype::string, value)); return *this; } @@ -90,9 +88,7 @@ List& List::put(int value) { } List& List::put(int64_t value) { - valvalue val; - val.integer = value; - values.push_back(std::make_unique(valtype::integer, val)); + values.push_back(std::make_unique(valtype::integer, value)); return *this; } @@ -101,9 +97,7 @@ List& List::put(uint64_t value) { } List& List::put(double value) { - valvalue val; - val.decimal = value; - values.push_back(std::make_unique(valtype::number, val)); + values.push_back(std::make_unique(valtype::number, value)); return *this; } @@ -112,23 +106,17 @@ List& List::put(float value) { } List& List::put(bool value) { - valvalue val; - val.boolean = value; - values.push_back(std::make_unique(valtype::boolean, val)); + values.push_back(std::make_unique(valtype::boolean, value)); return *this; } List& List::put(Map* value) { - valvalue val; - val.map = value; - values.push_back(std::make_unique(valtype::map, val)); + values.push_back(std::make_unique(valtype::map, value)); return *this; } List& List::put(List* value) { - valvalue val; - val.list = value; - values.push_back(std::make_unique(valtype::list, val)); + values.push_back(std::make_unique(valtype::list, value)); return *this; } @@ -189,38 +177,38 @@ std::string Map::getStr(std::string key, const std::string& def) const { return def; auto& val = found->second; switch (val->type) { - case valtype::string: return *val->value.str; - case valtype::boolean: return val->value.boolean ? "true" : "false"; - case valtype::number: return std::to_string(val->value.decimal); - case valtype::integer: return std::to_string(val->value.integer); + case valtype::string: return std::get(val->value); + case valtype::boolean: return std::get(val->value) ? "true" : "false"; + case valtype::number: return std::to_string(std::get(val->value)); + case valtype::integer: return std::to_string(std::get(val->value)); default: throw std::runtime_error("type error"); } } -double Map::getNum(std::string key, double def) const { +number_t Map::getNum(std::string key, double def) const { auto found = values.find(key); if (found == values.end()) return def; auto& val = found->second; switch (val->type) { - case valtype::number: return val->value.decimal; - case valtype::integer: return val->value.integer; - case valtype::string: return std::stoull(*val->value.str); - case valtype::boolean: return val->value.boolean; + case valtype::number: return std::get(val->value); + case valtype::integer: return std::get(val->value); + case valtype::string: return std::stoull(std::get(val->value)); + case valtype::boolean: return std::get(val->value); default: throw std::runtime_error("type error"); } } -int64_t Map::getInt(std::string key, int64_t def) const { +integer_t Map::getInt(std::string key, integer_t def) const { auto found = values.find(key); if (found == values.end()) return def; auto& val = found->second; switch (val->type) { - case valtype::number: return val->value.decimal; - case valtype::integer: return val->value.integer; - case valtype::string: return std::stoull(*val->value.str); - case valtype::boolean: return val->value.boolean; + case valtype::number: return std::get(val->value); + case valtype::integer: return std::get(val->value); + case valtype::string: return std::stoull(std::get(val->value)); + case valtype::boolean: return std::get(val->value); default: throw std::runtime_error("type error"); } } @@ -231,8 +219,8 @@ bool Map::getBool(std::string key, bool def) const { return def; auto& val = found->second; switch (val->type) { - case valtype::integer: return val->value.integer; - case valtype::boolean: return val->value.boolean; + case valtype::integer: return std::get(val->value); + case valtype::boolean: return std::get(val->value); default: throw std::runtime_error("type error"); } } @@ -271,7 +259,7 @@ Map* Map::map(std::string key) const { auto& val = found->second; if (val->type != valtype::map) return nullptr; - return val->value.map; + return std::get(val->value); } return nullptr; } @@ -279,7 +267,7 @@ Map* Map::map(std::string key) const { List* Map::list(std::string key) const { auto found = values.find(key); if (found != values.end()) - return found->second->value.list; + return std::get(found->second->value); return nullptr; } @@ -296,9 +284,7 @@ Map& Map::put(std::string key, int value) { } Map& Map::put(std::string key, int64_t value) { - valvalue val; - val.integer = value; - values[key] = std::make_unique(valtype::integer, val); + values[key] = std::make_unique(valtype::integer, value); return *this; } @@ -311,16 +297,12 @@ Map& Map::put(std::string key, float value) { } Map& Map::put(std::string key, double value) { - valvalue val; - val.decimal = value; - values[key] = std::make_unique(valtype::number, val); + values[key] = std::make_unique(valtype::number, value); return *this; } Map& Map::put(std::string key, std::string value){ - valvalue val; - val.str = new std::string(value); - values[key] = std::make_unique(valtype::string, val); + values[key] = std::make_unique(valtype::string, value); return *this; } @@ -329,23 +311,17 @@ Map& Map::put(std::string key, const char* value) { } Map& Map::put(std::string key, Map* value){ - valvalue val; - val.map = value; - values[key] = std::make_unique(valtype::map, val); + values[key] = std::make_unique(valtype::map, value); return *this; } Map& Map::put(std::string key, List* value){ - valvalue val; - val.list = value; - values[key] = std::make_unique(valtype::list, val); + values[key] = std::make_unique(valtype::list, value); return *this; } Map& Map::put(std::string key, bool value){ - valvalue val; - val.boolean = value; - values[key] = std::make_unique(valtype::boolean, val); + values[key] = std::make_unique(valtype::boolean, value); return *this; } @@ -370,9 +346,8 @@ Value::Value(valtype type, valvalue value) : type(type), value(value) { Value::~Value() { switch (type) { - case valtype::map: delete value.map; break; - case valtype::list: delete value.list; break; - case valtype::string: delete value.str; break; + case valtype::map: delete std::get(value); break; + case valtype::list: delete std::get(value); break; default: break; } diff --git a/src/data/dynamic.h b/src/data/dynamic.h index be8a2e39..513d812f 100644 --- a/src/data/dynamic.h +++ b/src/data/dynamic.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "../typedefs.h" @@ -12,18 +13,21 @@ namespace dynamic { class List; class Value; + using number_t = double; + using integer_t = int64_t; + enum class valtype { - map, list, number, integer, string, boolean + none, map, list, number, integer, string, boolean }; - union valvalue { - Map* map; - List* list; - std::string* str; - double decimal; - int64_t integer; - uint64_t boolean; - }; + using valvalue = std::variant< + Map*, + List*, + std::string, + number_t, + bool, + integer_t + >; class Value { public: @@ -39,8 +43,8 @@ namespace dynamic { ~List(); std::string str(size_t index) const; - double num(size_t index) const; - int64_t integer(size_t index) const; + number_t num(size_t index) const; + integer_t integer(size_t index) const; Map* map(size_t index) const; List* list(size_t index) const; bool flag(size_t index) const; @@ -78,13 +82,13 @@ namespace dynamic { ~Map(); std::string getStr(std::string key) const; - double getNum(std::string key) const; - int64_t getInt(std::string key) const; + number_t getNum(std::string key) const; + integer_t getInt(std::string key) const; bool getBool(std::string key) const; std::string getStr(std::string key, const std::string& def) const; - double getNum(std::string key, double def) const; - int64_t getInt(std::string key, int64_t def) const; + number_t getNum(std::string key, double def) const; + integer_t getInt(std::string key, integer_t def) const; bool getBool(std::string key, bool def) const; void str(std::string key, std::string& dst) const; diff --git a/src/engine.cpp b/src/engine.cpp index 420182f1..7bc8e7e1 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -52,7 +52,7 @@ void addWorldGenerators() { } Engine::Engine(EngineSettings& settings, EnginePaths* paths) - : settings(settings), paths(paths) + : settings(settings), settingsHandler(settings), paths(paths) { if (Window::initialize(settings.display)){ throw initialize_error("could not initialize window"); @@ -335,3 +335,7 @@ void Engine::postRunnable(runnable callback) { std::lock_guard lock(postRunnablesMutex); postRunnables.push(callback); } + +SettingsHandler& Engine::getSettingsHandler() { + return settingsHandler; +} diff --git a/src/engine.h b/src/engine.h index 419a9ecf..dc210475 100644 --- a/src/engine.h +++ b/src/engine.h @@ -9,6 +9,7 @@ #include "content/Content.h" #include "content/ContentPack.h" #include "files/engine_paths.h" +#include "files/settings_io.h" #include #include @@ -37,6 +38,7 @@ public: class Engine { EngineSettings& settings; + SettingsHandler settingsHandler; EnginePaths* paths; std::unique_ptr assets = nullptr; @@ -118,6 +120,8 @@ public: /// @brief Enqueue function call to the end of current frame in draw thread void postRunnable(runnable callback); + + SettingsHandler& getSettingsHandler(); }; #endif // SRC_ENGINE_H_ diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp index 86654f93..2db9b695 100644 --- a/src/files/WorldFiles.cpp +++ b/src/files/WorldFiles.cpp @@ -608,7 +608,7 @@ void WorldFiles::removePack(const World* world, const std::string& id) { if (name.find(prefix) != 0) continue; auto value = blocks->getValueWriteable(i); - *value->value.str = "core:air"; + value->value = "core:air"; } auto items = root->list("items"); @@ -617,7 +617,7 @@ void WorldFiles::removePack(const World* world, const std::string& id) { if (name.find(prefix) != 0) continue; auto value = items->getValueWriteable(i); - *value->value.str = "core:empty"; + value->value = "core:empty"; } files::write_json(getIndicesFile(), root.get()); } diff --git a/src/files/settings_io.cpp b/src/files/settings_io.cpp index db31dc35..79d5472c 100644 --- a/src/files/settings_io.cpp +++ b/src/files/settings_io.cpp @@ -9,7 +9,33 @@ #include "../coders/toml.h" #include "../coders/json.h" -#include "../data/dynamic.h" +SettingsHandler::SettingsHandler(EngineSettings& settings) { + map.emplace("audio.volume-master", &settings.audio.volumeMaster); + map.emplace("audio.volume-regular", &settings.audio.volumeRegular); + map.emplace("audio.volume-ui", &settings.audio.volumeUI); + map.emplace("audio.volume-ambient", &settings.audio.volumeAmbient); + map.emplace("audio.volume-music", &settings.audio.volumeMusic); + + map.emplace("camera.sensitivity", &settings.camera.sensitivity); +} + +dynamic::Value SettingsHandler::getValue(std::string name) const { + using dynamic::valtype; + + auto found = map.find(name); + if (found == map.end()) { + return dynamic::Value(valtype::none, 0); + } + auto setting = found->second; + if (auto number = dynamic_cast*>(setting)) { + return dynamic::Value(valtype::number, number->get()); + } else if (auto number = dynamic_cast*>(setting)) { + return dynamic::Value(valtype::number, number->get()); + } + + return dynamic::Value(valtype::none, 0); +} + toml::Wrapper* create_wrapper(EngineSettings& settings) { std::unique_ptr wrapper (new toml::Wrapper()); @@ -38,7 +64,7 @@ toml::Wrapper* create_wrapper(EngineSettings& settings) { camera.add("fov-effects", &settings.camera.fovEvents); camera.add("fov", &settings.camera.fov); camera.add("shaking", &settings.camera.shaking); - camera.add("sensitivity", &settings.camera.sensitivity); + camera.add("sensitivity", &*settings.camera.sensitivity); toml::Section& graphics = wrapper->add("graphics"); graphics.add("gamma", &settings.graphics.gamma); diff --git a/src/files/settings_io.h b/src/files/settings_io.h index 57a38151..5fd2d648 100644 --- a/src/files/settings_io.h +++ b/src/files/settings_io.h @@ -2,14 +2,24 @@ #define FILES_SETTINGS_IO_H_ #include +#include #include "../settings.h" +#include "../data/dynamic.h" namespace toml { class Wrapper; } +class SettingsHandler { + std::unordered_map map; +public: + SettingsHandler(EngineSettings& settings); + + dynamic::Value getValue(std::string name) const; +}; + extern std::string write_controls(); extern toml::Wrapper* create_wrapper(EngineSettings& settings); extern void load_controls(std::string filename, std::string source); -#endif // FILES_SETTINGS_IO_H_ \ No newline at end of file +#endif // FILES_SETTINGS_IO_H_ diff --git a/src/frontend/locale/langs.cpp b/src/frontend/locale/langs.cpp index 944db1ef..45d103a1 100644 --- a/src/frontend/locale/langs.cpp +++ b/src/frontend/locale/langs.cpp @@ -78,7 +78,7 @@ void langs::loadLocalesInfo(const fs::path& resdir, std::string& fallback) { std::string name; if (langInfo->type == dynamic::valtype::map) { - name = langInfo->value.map->getStr("name", "none"); + name = std::get(langInfo->value)->getStr("name", "none"); } else { continue; } diff --git a/src/frontend/menu/menu_settings.cpp b/src/frontend/menu/menu_settings.cpp index 49fadfa6..5510e4f9 100644 --- a/src/frontend/menu/menu_settings.cpp +++ b/src/frontend/menu/menu_settings.cpp @@ -51,14 +51,14 @@ static void create_controls_panel(Engine* engine) { /* Camera sensitivity setting track bar */{ panel->add(menus::create_label([=]() { - float s = engine->getSettings().camera.sensitivity; + float s = engine->getSettings().camera.sensitivity.get(); return langs::get(L"Mouse Sensitivity", L"settings")+L": "+ util::to_wstring(s, 1); })); auto trackbar = std::make_shared(0.1, 10.0, 2.0, 0.1, 4); trackbar->setSupplier([=]() { - return engine->getSettings().camera.sensitivity; + return engine->getSettings().camera.sensitivity.get(); }); trackbar->setConsumer([=](double value) { engine->getSettings().camera.sensitivity = value; diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 02bde1ea..6917d784 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -50,8 +50,8 @@ void CameraControl::updateMouse(PlayerInput& input) { glm::vec2& cam = player->cam; float sensitivity = (input.zoom - ? settings.sensitivity / 4.f - : settings.sensitivity); + ? settings.sensitivity.get() / 4.f + : settings.sensitivity.get()); cam -= glm::degrees(Events::delta / (float)Window::height * sensitivity); diff --git a/src/settings.h b/src/settings.h index 65d56f99..2b74c4b8 100644 --- a/src/settings.h +++ b/src/settings.h @@ -2,6 +2,7 @@ #define SRC_SETTINGS_H_ #include +#include #include "data/setting.h" #include "constants.h" @@ -52,7 +53,7 @@ struct CameraSettings { /// @brief Camera field of view float fov = 90.0f; /// @brief Camera sensitivity - float sensitivity = 2.0f; + NumberSetting sensitivity {2.0f, 0.1f, 10.0f}; }; struct GraphicsSettings { @@ -62,7 +63,7 @@ struct GraphicsSettings { float gamma = 1.0f; /// @brief Enable blocks backlight to prevent complete darkness bool backlight = true; - /// @brief Enable chunks frustum culling */ + /// @brief Enable chunks frustum culling bool frustumCulling = true; int skyboxResolution = 64 + 32; };