1
0
Fork 0
Univerxel/src/state.h

202 lines
7.6 KiB
C++

#pragma once
#define UI_MARGIN 5
#define MIN_FPS 24
#define MAX_FPS 240
#include <toml.h>
#include <fstream>
#include <filesystem>
#include <optional>
#include "data/glm.hpp"
#include "data/circular_buffer.hpp"
#include "render/Renderer.hpp"
#include "world/Universe.hpp"
#include "control/Camera.hpp"
#include "contouring/index.hpp"
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();
}
/// Savable game options
struct options {
const char *PATH = "config.toml";
/// Load from PATH
options() {
auto config = std::filesystem::exists(PATH) ? toml::parse_file(PATH) : toml::table();
target_fps = config["window"]["fps"].value_or(60);
samples = config["window"]["samples"].value_or(-1);
fullscreen = config["window"]["fullscreen"].value_or(false);
renderer.textures = config["render"]["textures"].value_or(renderer.textures);
renderer.mipMapLOD = config["render"]["texture_quality"].value_or(renderer.mipMapLOD);
renderer.main.pbr = config["render"]["pbr"].value_or(renderer.main.pbr);
renderer.main.triplanar = config["render"]["triplanar"].value_or(renderer.main.triplanar);
renderer.main.geometry = config["render"]["geometry"].value_or(renderer.main.geometry);
renderer.main.blend = config["render"]["blend"].value_or(renderer.main.blend);
renderer.main.fog = config["render"]["fog"].value_or(renderer.main.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);
world.loadDistance = config["world"]["load_distance"].value_or(world.loadDistance);
world.keepDistance = config["world"]["keep_distance"].value_or(world.keepDistance);
world.folderPath = config["world"]["path"].value_or(world.folderPath);
voxel_density = config["world"]["voxel_density"].value_or(1);
culling = config["mesh"]["culling"].value_or(true);
contouring_idx = contouring::idxByName(config["mesh"]["mode"].value_or(std::string("")));
for(const auto& name: contouring::names) {
contouring_data.emplace(name, config["mesh"]["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);
overlay_show = config["overlay"]["visible"].value_or(true);
overlay_corner = config["overlay"]["corner"].value_or(3);
//TODO: console
show_debug_menu = config["show_debug"]["menu"].value_or(false);
show_debug_render = config["show_debug"]["render"].value_or(false);
show_debug_world = config["show_debug"]["world"].value_or(false);
show_debug_contouring = config["show_debug"]["contouring"].value_or(false);
show_debug_controls = config["show_debug"]["controls"].value_or(false);
editor_show = config["editor"]["visible"].value_or(false);
tool.material = config["editor"]["tool"]["material"].value_or<int>(tool.material);
tool.radius = config["editor"]["tool"]["radius"].value_or(tool.radius);
}
/// Write to PATH
void save() {
auto config = toml::table();
config.insert_or_assign("window", toml::table({
{"fps", target_fps},
{"samples", samples},
{"fullscreen", fullscreen},
}));
config.insert_or_assign("render", toml::table({
{"textures", renderer.textures},
{"texture_quality", renderer.mipMapLOD},
{"pbr", renderer.main.pbr},
{"triplanar", renderer.main.triplanar},
{"geometry", renderer.main.geometry},
{"blend", renderer.main.blend},
{"fog", renderer.main.fog},
{"fog_color", toHexa(renderer.clear_color)},
{"skybox", renderer.skybox}
}));
config.insert_or_assign("world", toml::table({
{"load_distance", world.loadDistance},
{"keep_distance", world.keepDistance},
{"voxel_density", voxel_density},
{"path", world.folderPath}
}));
config.insert_or_assign("mesh", toml::table({
{"culling", culling},
{"mode", contouring::names[contouring_idx]},
{"options", toml::table()}
}));
for(const auto& [key, val]: contouring_data) {
if(!val.empty())
config["mesh"]["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("overlay", toml::table({
{"visible", overlay_show},
{"corner", overlay_corner}
}));
config.insert_or_assign("show_debug", toml::table({
{"menu", show_debug_menu},
{"render", show_debug_render},
{"world", show_debug_world},
{"contouring", show_debug_contouring},
{"controls", show_debug_controls}
}));
config.insert_or_assign("editor", toml::table({
{"visible", editor_show},
{"tool", toml::table({
{"material", (int)tool.material},
{"radius", tool.radius}
})}
}));
std::ofstream out;
out.open(PATH, std::ios::out | std::ios::trunc);
out << config << "\n\n";
out.close();
}
bool show_debug_menu;
bool show_debug_render;
int target_fps;
int samples;
bool fullscreen;
Renderer::options renderer;
bool show_debug_world;
world::Universe::options world;
int voxel_density;
bool show_debug_contouring;
bool culling;
int contouring_idx;
std::map<std::string, std::string> contouring_data;
bool show_debug_controls;
Controllable::options control;
Camera::options camera;
bool editor_show;
struct tool {
int radius = 2;
unsigned short material = 2;
} tool;
bool overlay_show;
int overlay_corner;
bool console_show = false;
bool console_scrool = true;
};
/// Live state
struct state {
bool capture_mouse = true;
camera_pos position = camera_pos(voxel_pos(0), 1);
std::optional<world::Universe::ray_target> look_at = {};
std::shared_ptr<contouring::Abstract> contouring;
std::array<char, 256> console_buffer;
};
/// Readonly metrics
struct reports {
size_t tris_count = 0;
size_t models_count = 0;
};