1
0
Fork 0
Univerxel/src/client/config.hpp

226 lines
9.2 KiB
C++

#pragma once
#include <toml.h>
#include <glm/vec4.hpp>
#include <limits.h>
#include <iomanip>
#include "world/Universe.hpp"
#include "render/Renderer.hpp"
#include "contouring/index.hpp"
#include "control/Camera.hpp"
namespace config::client {
inline glm::vec4 fromHex(const std::string& str) {
std::array<int, 3> rgb = {UCHAR_MAX};
sscanf(str.c_str() + 1, "%02X%02X%02X", (unsigned int *)&rgb[0], (unsigned int *)&rgb[1], (unsigned int *)&rgb[2]);
return glm::vec4(rgb[0] * 1.f / UCHAR_MAX, rgb[1] * 1.f / UCHAR_MAX, rgb[2] * 1.f / UCHAR_MAX, 1);
}
inline std::string toHexa(const glm::vec4& rgb) {
std::ostringstream sstr;
sstr << std::hex << std::setw(2) << std::setfill('0') <<
static_cast<int>(rgb.x * UCHAR_MAX) << static_cast<int>(rgb.y * UCHAR_MAX) << static_cast<int>(rgb.z * UCHAR_MAX) << std::endl;
return sstr.str();
}
struct options {
public:
options(toml::node_view<toml::node> config) {
assert(config["enabled"]);
window.targetFPS = config["window"]["target_fps"].value_or(window.targetFPS);
window.samples = config["window"]["samples"].value_or(window.samples);
window.fullscreen = config["window"]["fullscreen"].value_or(window.fullscreen);
renderer.inFlightFrames = config["window"]["parallel_frames"].value_or(renderer.inFlightFrames);
preferVulkan = config["render"]["prefer_vulkan"].value_or(preferVulkan);
renderer.textures = config["render"]["textures"].value_or(renderer.textures);
renderer.mipMapLOD = config["render"]["texture_quality"].value_or(renderer.mipMapLOD);
renderer.anisotropy = config["render"]["texture_angular_quality"].value_or(renderer.anisotropy);
renderer.voxel.pbr = config["render"]["pbr"].value_or(renderer.voxel.pbr);
renderer.voxel.triplanar = config["render"]["triplanar"].value_or(renderer.voxel.triplanar);
renderer.voxel.stochastic = config["render"]["stochastic"].value_or(renderer.voxel.stochastic);
renderer.voxel.geometry = config["render"]["geometry"].value_or(renderer.voxel.geometry);
renderer.voxel.blend = config["render"]["blend"].value_or(renderer.voxel.blend);
renderer.voxel.fog = config["render"]["fog"].value_or(renderer.voxel.fog);
const std::string fog = config["render"]["fog_color"].value_or(std::string{"#000000"});
renderer.clear_color = fromHex(fog);
renderer.skybox = config["render"]["skybox"].value_or(renderer.skybox);
renderer.voxel.curvature = config["render"]["curvature"].value_or(renderer.voxel.curvature);
renderer.voxel.curv_depth = config["render"]["curvature_depth"].value_or(renderer.voxel.curv_depth);
culling = config["render"]["culling"].value_or(culling);
contouring.idx = contouring::idxByName(config["contouring"]["mode"].value_or(std::string("")));
for(const auto& name: contouring::names) {
contouring.data.emplace(name, config["contouring"]["options"][name].value_or(std::string("")));
}
camera.far = config["camera"]["far"].value_or(camera.far);
camera.near = config["camera"]["near"].value_or(camera.near);
camera.fov = config["camera"]["fov"].value_or(camera.fov);
control.sensibility = config["control"]["sensibility"].value_or(control.sensibility);
control.speed = config["control"]["speed"].value_or(control.speed);
control.collide = config["control"]["collide"].value_or(control.collide);
world.loadDistance = config["world"]["load_distance"].value_or(world.loadDistance);
world.keepDistance = config["world"]["keep_distance"].value_or(world.keepDistance);
voxel_density = config["world"]["voxel_density"].value_or(voxel_density);
#ifndef STANDALONE
const auto useLocal = config["connection"]["use_local"].value_or(true);
#else
const auto useLocal = false;
#endif
if(!useLocal) {
world::client::Universe::connection ct;
ct.address = config["connection"]["address"].value_or(ct.address);
ct.port = config["connection"]["port"].value_or(ct.port);
connection = ct;
}
editor.visible = config["editor"]["visible"].value_or(editor.visible);
editor.tool.radius = config["editor"]["tool"]["radius"].value_or(editor.tool.radius);
editor.tool.material = config["editor"]["tool"]["material"].value_or(editor.tool.material);
editor.tool.emptyAir = config["editor"]["tool"]["empty_air"].value_or(editor.tool.emptyAir);
debugMenu.bar = config["debug_menu"]["bar"].value_or(debugMenu.bar);
debugMenu.render = config["debug_menu"]["render"].value_or(debugMenu.render);
debugMenu.world = config["debug_menu"]["world"].value_or(debugMenu.world);
debugMenu.contouring = config["debug_menu"]["contouring"].value_or(debugMenu.contouring);
debugMenu.controls = config["debug_menu"]["controls"].value_or(debugMenu.controls);
overlay.visible = config["overlay"]["visible"].value_or(overlay.visible);
overlay.corner = config["overlay"]["corner"].value_or(overlay.corner);
}
toml::table save() {
auto config = toml::table();
config.insert_or_assign("enabled", true);
config.insert_or_assign("window", toml::table({
{"target_fps", window.targetFPS},
{"samples", window.samples},
{"fullscreen", window.fullscreen},
{"parallel_frames", renderer.inFlightFrames}
}));
config.insert_or_assign("render", toml::table({
{"prefer_vulkan", preferVulkan},
{"textures", renderer.textures},
{"texture_quality", renderer.mipMapLOD},
{"texture_angular_quality", renderer.anisotropy},
{"pbr", renderer.voxel.pbr},
{"triplanar", renderer.voxel.triplanar},
{"stochastic", renderer.voxel.stochastic},
{"geometry", renderer.voxel.geometry},
{"blend", renderer.voxel.blend},
{"fog", renderer.voxel.fog},
{"fog_color", toHexa(renderer.clear_color)},
{"skybox", renderer.skybox},
{"curvature", renderer.voxel.curvature},
{"curvature_depth", renderer.voxel.curv_depth},
{"culling", culling}
}));
config.insert_or_assign("contouring", toml::table({
{"mode", contouring::names[contouring.idx]},
{"options", toml::table()}
}));
for(const auto& [key, val]: contouring.data) {
if(!val.empty())
config["contouring"]["options"].as_table()->insert_or_assign(key, val);
}
config.insert_or_assign("camera", toml::table({
{"far", camera.far},
{"near", camera.near},
{"fov", camera.fov}
}));
config.insert_or_assign("control", toml::table({
{"sensibility", control.sensibility},
{"speed", control.speed},
{"collide", control.collide}
}));
config.insert_or_assign("world", toml::table({
{"load_distance", world.loadDistance},
{"keep_distance", world.keepDistance},
{"voxel_density", voxel_density}
}));
if(connection.has_value()) {
const auto &ct = connection.value();
config.insert_or_assign("connection", toml::table({
#ifndef STANDALONE
{"use_local", false},
#endif
{"address", ct.address},
{"port", ct.port}
}));
} else {
config.insert_or_assign("connection", toml::table({{"use_local", true}}));
}
config.insert_or_assign("editor", toml::table({
{"visible", editor.visible},
{"tool", toml::table({
{"radius", editor.tool.radius},
{"material", editor.tool.material},
{"empty_air", editor.tool.emptyAir}
})}
}));
config.insert_or_assign("debug_menu", toml::table({
{"bar", debugMenu.bar},
{"render", debugMenu.render},
{"world", debugMenu.world},
{"contouring", debugMenu.contouring},
{"controls", debugMenu.controls}
}));
config.insert_or_assign("overlay", toml::table({
{"visible", overlay.visible},
{"corner", overlay.corner}
}));
return config;
}
world::client::Universe::options world;
int voxel_density = 1;
struct {
bool bar = false;
bool render = false;
bool world = false;
bool contouring = false;
bool controls = false;
} debugMenu;
struct {
int targetFPS = 60;
int samples = -1;
bool fullscreen = false;
} window;
bool preferVulkan = true;
render::renderOptions renderer;
int culling = 0;
struct {
int idx;
std::map<std::string, std::string> data;
} contouring;
Controllable::options control;
Camera::options camera;
struct {
bool visible = false;
struct {
int radius = 2;
unsigned short material = 5;
bool emptyAir = true;
} tool;
} editor;
struct {
bool visible = true;
int corner = 3;
} overlay;
std::optional<world::client::Universe::connection> connection = {};
};
}