Commit ddbcd047 authored by Shu's avatar Shu 🍠
Browse files

Big bad shared server rework

parent 0dcff4b8
......@@ -108,6 +108,14 @@
"group": "build",
"dependsOrder": "sequence",
"dependsOn": ["Build debug", "exec memcheck"]
},
{
"label": "Dependencies",
"type": "shell",
"command": ["~/Téléchargements/cinclude2dot.pl", "--paths", "--include ../include/zstd/dictBuilder,../include/zstd,/usr/include/c++/10.2.0,../include/robin_hood,../include/imgui,../include/meshoptimizer,../include,../include/tracy,../include/gl3w,../include/FastNoiseSIMD", ">", "../build/dep.dot"],
"options": {
"cwd": "${workspaceRoot}/src",
}
}
]
}
\ No newline at end of file
#version 330 core
#define UNIT_SIZE 8
// Ouput data
layout(location = 0) out vec3 color;
......@@ -112,7 +114,7 @@ vec3 getTriTexture(sampler2DArray sample, vec2 crdx, vec2 crdy, vec2 crdz, vec3
}
void main() {
float texScale = .5;
float texScale = 1. / UNIT_SIZE;
#ifdef TRIPLANAR
// Triplanar
float plateauSize = 0.001;
......@@ -144,7 +146,7 @@ void main() {
#else
// Cheap planar
vec3 blendWeights = abs(vs.FaceNormal_modelspace);
vec3 nrm = normalize(pow(blendWeights, vec3(80)));
vec3 nrm = normalize(pow(blendWeights, vec3(80 / sqrt(UNIT_SIZE))));
vec2 UV = (vec2(vs.Position_modelspace.xy * nrm.z) + vec2(vs.Position_modelspace.yz * nrm.x) + vec2(vs.Position_modelspace.zx * nrm.y)) * texScale;
vec3 tex = getTexture(TextureAtlas, UV).rgb;
......
......@@ -4,15 +4,19 @@
#include "render/gl/UI.hpp"
#include "render/gl/Pipeline.hpp"
#include "InputMap.hpp"
#include "world/index.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include "../core/data/math.hpp"
#include <Tracy.hpp>
Client::Client() { }
Client::Client(config::client::options& options): options(options) { }
Client::~Client() { }
void Client::run() {
void Client::run(server_handle* const localHandle) {
if (!render::gl::Renderer::Load(window, {options.renderer.clear_color}))
return;
window.setTargetFPS(options.target_fps);
window.setTargetFPS(options.window.targetFPS);
InputMap inputs(window.getPtr());
......@@ -23,10 +27,9 @@ void Client::run() {
pipeline->LightInvDir = glm::normalize(glm::vec3(-.5f, 2, -2));
render::Renderer::Get()->loadUI(window);
//TODO: extract to server
world::Universe world = world::Universe(options.world);
world.setContouring(contouring::load(options.contouring_idx, options.contouring_data));
state.contouring = world.getContouring();
auto world = world::client::Load(options.useLocal, localHandle, options.world);
world->setContouring(contouring::load(options.contouring.idx, options.contouring.data));
state.contouring = world->getContouring();
//TODO: loop
do {
......@@ -37,12 +40,12 @@ void Client::run() {
const double partTime = window.getTime();
const float deltaTime = partTime - lastTime;
inputs.toggle(state.capture_mouse, Input::Mouse);
inputs.toggle(options.show_debug_menu, Input::Debug);
inputs.toggle(options.debugMenu.bar, Input::Debug);
player.capture(state.capture_mouse, !render::UI::IsFocus(), deltaTime);
if(player.velocity != glm::vec3(0) && (
!options.control.collide ||
!world.collide(player.position, player.velocity, options.voxel_density, 1))
!world->collide(player.position, player.velocity, options.voxel_density, options.voxel_density))
) {
player.position += player.velocity;
state.position = player.position;
......@@ -52,7 +55,7 @@ void Client::run() {
pipeline->LightInvDir = glm::vec3(glm::rotate(glm::mat4(1), deltaTime * .1f, glm::vec3(1, .5, .1)) * glm::vec4(pipeline->LightInvDir, 0));
{
const auto ray_result = world.raycast(camera.getRay() * options.voxel_density);
const auto ray_result = world->raycast(camera.getRay() * options.voxel_density);
if(auto target = std::get_if<world::Universe::ray_target>(&ray_result)) {
state.look_at = *target;
} else {
......@@ -62,16 +65,19 @@ void Client::run() {
if (state.capture_mouse) {
if (state.look_at.has_value()) {
ZoneScopedN("Edit");
const auto &tool = options.editor.tool;
if (inputs.isPressing(Mouse::Left))
world.setCube(state.look_at.value().pos, world::Voxel(world::materials::AIR, options.tool.empty_air * world::Voxel::DENSITY_MAX), options.tool.radius);
world->emit(world::action::FillCube(
state.look_at.value().pos, world::Voxel(world::materials::AIR, tool.emptyAir * world::Voxel::DENSITY_MAX), tool.radius));
else if (inputs.isPressing(Mouse::Right))
world.setCube(state.look_at.value().pos, world::Voxel(options.tool.material, world::Voxel::DENSITY_MAX), options.tool.radius);
world->emit(world::action::FillCube(
state.look_at.value().pos, world::Voxel(tool.material, world::Voxel::DENSITY_MAX), tool.radius));
}
if (inputs.isDown(Input::Throw)) {
world.addEntity(entity_id(0), {state.position * options.voxel_density, glm::vec3(10, 0, 0)});
//FIXME: register entity type world->addEntity(entity_id(0), {state.position * options.voxel_density, glm::vec3(10, 0, 0)});
}
}
world.update((state.position * options.voxel_density).as_voxel(), deltaTime);
world->update((state.position * options.voxel_density).as_voxel(), deltaTime);
inputs.saveKeys();
lastTime = partTime;
}
......@@ -80,10 +86,10 @@ void Client::run() {
ZoneScopedN("UI");
const auto actions = render::UI::Get()->draw(options, state, reports);
if (actions && render::UI::Actions::FPS) {
window.setTargetFPS(options.target_fps);
window.setTargetFPS(options.window.targetFPS);
}
if (actions && render::UI::Actions::FullScreen) {
window.setFullscreen(options.fullscreen);
window.setFullscreen(options.window.fullscreen);
}
if(actions && render::UI::Actions::ClearColor) {
pipeline->setClearColor(options.renderer.clear_color);
......@@ -95,7 +101,7 @@ void Client::run() {
pipeline->reloadTextures(options.renderer.textures, options.renderer.mipMapLOD, options.renderer.anisotropy);
}
if(actions && render::UI::Actions::World) {
world.setOptions(options.world);
//FIXME: server options world->setOptions(options.world);
}
if(actions && render::UI::Actions::Camera) {
camera.setOptions(options.camera);
......@@ -105,8 +111,8 @@ void Client::run() {
}
if(actions && render::UI::Actions::ChangeContouring) {
state.contouring = NULL;
world.setContouring(contouring::load(options.contouring_idx, options.contouring_data));
state.contouring = world.getContouring();
world->setContouring(contouring::load(options.contouring.idx, options.contouring.data));
state.contouring = world->getContouring();
}
pipeline->SkyEnable = options.renderer.skybox;
}
......@@ -142,9 +148,9 @@ void Client::run() {
occlusion.emplace_back(cos(v) * sin(h), sin(v), cos(v) * cos(h));
}
}
world.getContouring()->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density);
state.contouring->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density);
} else {
world.getContouring()->getModels(draw, frustum, offset, options.voxel_density);
state.contouring->getModels(draw, frustum, offset, options.voxel_density);
}
}
{ // Entities
......@@ -153,10 +159,10 @@ void Client::run() {
reports.models_count += models.size();
reports.tris_count += buffer->draw(pass(models));
};
world.getEntitiesModels(draw, frustum, offset, options.voxel_density);
//world->getEntitiesModels(draw, frustum, offset, options.voxel_density);
}
if(state.look_at.has_value()) { // Indicator
const auto model = glm::scale(glm::translate(glm::scale(glm::mat4(1), 1.f / glm::vec3(options.voxel_density)), glm::vec3(state.look_at.value().pos.second + state.look_at.value().offset - offset * glm::llvec3(options.voxel_density)) - glm::vec3(.5 + options.tool.radius)), glm::vec3(1 + options.tool.radius * 2));
const auto model = glm::scale(glm::translate(glm::scale(glm::mat4(1), 1.f / glm::vec3(options.voxel_density)), glm::vec3(state.look_at.value().pos.second + state.look_at.value().offset - offset * glm::llvec3(options.voxel_density)) - glm::vec3(.5 + options.editor.tool.radius)), glm::vec3(1 + options.editor.tool.radius * 2));
reports.models_count++;
reports.tris_count += pipeline->drawIndicatorCube(model);
}
......@@ -176,9 +182,9 @@ void Client::run() {
} while (!(inputs.isDown(Input::Quit) || window.shouldClose()));
render::UI::Unload();
delete pipeline;
render::Renderer::Unload();
window.destroy();
contouring::save(options.contouring_idx, state.contouring, options.contouring_data);
options.save();
contouring::save(options.contouring.idx, state.contouring, options.contouring.data);
}
\ No newline at end of file
#pragma once
#include "state.h"
#include "state.hpp"
#include "Window.hpp"
#include "../core/server_handle.hpp"
namespace render {
class Renderer;
......@@ -10,17 +11,17 @@ namespace render {
/// Client view
class Client {
public:
Client();
Client(config::client::options &options);
~Client();
void run();
void run(server_handle *const);
protected:
private:
config::options options;
config::state state;
config::reports reports;
config::client::options &options;
state::state state;
state::reports reports;
Window window;
};
\ No newline at end of file
......@@ -93,10 +93,13 @@ double Window::getTime() const {
void Window::startFrame() {
frameStart = getTime();
}
void Window::wait(int microseconds) {
std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
}
void Window::waitTargetFPS() {
if (targetFPS >= MIN_FPS && targetFPS <= MAX_FPS) {
while (glfwGetTime() < frameStart + 1.0 / targetFPS) {
std::this_thread::sleep_for(std::chrono::microseconds(100));
wait();
}
}
}
......
......@@ -45,6 +45,8 @@ public:
double getTime() const;
static void wait(int microseconds = 100);
private:
GLFWwindow *ptr;
int targetFPS;
......
#pragma once
#define UI_MARGIN 5
#include <toml.h>
#include <fstream>
#include <filesystem>
#include <optional>
#include <glm/vec4.hpp>
#include "render/Renderer.hpp"
#include <limits.h>
#include <iomanip>
#include "world/Universe.hpp"
#include "render/Pipeline.hpp"
#include "../server/world/Universe.hpp"
#include "contouring/index.hpp"
#include "control/Camera.hpp"
#include "render/contouring/index.hpp"
namespace config {
namespace config::client {
inline glm::vec4 fromHex(const std::string& str) {
std::array<int, 3> rgb = {UCHAR_MAX};
......@@ -27,16 +23,16 @@ inline std::string toHexa(const glm::vec4& rgb) {
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);
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);
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);
......@@ -51,16 +47,11 @@ struct options {
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);
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(culling);
contouring_idx = contouring::idxByName(config["mesh"]["mode"].value_or(std::string("")));
contouring.idx = contouring::idxByName(config["contouring"]["mode"].value_or(std::string("")));
for(const auto& name: contouring::names) {
contouring_data.emplace(name, config["mesh"]["options"][name].value_or(std::string("")));
contouring.data.emplace(name, config["contouring"]["options"][name].value_or(std::string("")));
}
camera.far = config["camera"]["far"].value_or(camera.far);
......@@ -70,29 +61,36 @@ struct options {
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
useLocal = config["world"]["use_local"].value_or(useLocal);
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);
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.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);
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);
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);
}
/// Write to PATH
void save() {
toml::table save() {
auto config = toml::table();
config.insert_or_assign("enabled", true);
config.insert_or_assign("window", toml::table({
{"fps", target_fps},
{"samples", samples},
{"fullscreen", fullscreen},
{"target_fps", window.targetFPS},
{"samples", window.samples},
{"fullscreen", window.fullscreen}
}));
config.insert_or_assign("render", toml::table({
{"prefer_vulkan", preferVulkan},
{"textures", renderer.textures},
{"texture_quality", renderer.mipMapLOD},
{"texture_angular_quality", renderer.anisotropy},
......@@ -105,24 +103,17 @@ struct options {
{"fog_color", toHexa(renderer.clear_color)},
{"skybox", renderer.skybox},
{"curvature", renderer.voxel.curvature},
{"curvature_depth", renderer.voxel.curv_depth}
{"curvature_depth", renderer.voxel.curv_depth},
{"culling", culling}
}));
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]},
config.insert_or_assign("contouring", toml::table({
{"mode", contouring::names[contouring.idx]},
{"options", toml::table()}
}));
for(const auto& [key, val]: contouring_data) {
for(const auto& [key, val]: contouring.data) {
if(!val.empty())
config["mesh"]["options"].as_table()->insert_or_assign(key, val);
config["contouring"]["options"].as_table()->insert_or_assign(key, val);
}
config.insert_or_assign("camera", toml::table({
{"far", camera.far},
{"near", camera.near},
......@@ -133,81 +124,76 @@ struct options {
{"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("world", toml::table({
{"use_local", useLocal},
{"load_distance", world.loadDistance},
{"keep_distance", world.keepDistance},
{"voxel_density", voxel_density}
}));
config.insert_or_assign("editor", toml::table({
{"visible", editor_show},
{"visible", editor.visible},
{"tool", toml::table({
{"material", (int)tool.material},
{"radius", tool.radius}
{"radius", editor.tool.radius},
{"material", editor.tool.material},
{"empty_air", editor.tool.emptyAir}
})}
}));
std::ofstream out;
out.open(PATH, std::ios::out | std::ios::trunc);
out << config << "\n\n";
out.close();
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;
}
bool show_debug_menu;
bool show_debug_render;
int target_fps;
int samples;
bool fullscreen;
bool useLocal = true;
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::Pipeline::options renderer;
bool show_debug_world;
world::Universe::options world;
int voxel_density;
bool show_debug_contouring;
int culling = 0;
int contouring_idx;
std::map<std::string, std::string> contouring_data;
bool show_debug_controls;
struct {
int idx;
std::map<std::string, std::string> data;
} contouring;
Controllable::options control;
Camera::options camera;
bool editor_show;
struct tool {
int radius = 2;
unsigned short material = 5;
bool empty_air = true;
} tool;
bool overlay_show;
int overlay_corner;
bool console_show = false;
bool console_scrool = true;
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;
};
/// 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;
};
}
\ No newline at end of file
#pragma once
#include "../gl/buffer/Abstract.hpp"
#include "../../../server/world/forward.h"
#include "../../../core/geometry/Frustum.hpp"
#include "../../../core/geometry/Ray.hpp"
#include "../../../core/geometry/Faces.hpp"
#include "../render/gl/buffer/Abstract.hpp"
#include "../../core/world/forward.h"
#include "../../core/geometry/Frustum.hpp"
#include "../../core/geometry/Ray.hpp"
#include "../../core/geometry/Faces.hpp"
/// Mesh creation
/// Mesh creation (from world to render)
namespace contouring {
/// Generating mesh from world data
class Abstract {
......@@ -16,7 +16,7 @@ namespace contouring {
/// Each frame ping.
/// Mostly used for cleanup and to flush buffers data using main thread
virtual void update(const voxel_pos &pos, const world::area_map &areas) = 0;
virtual void update(const voxel_pos &pos, const world::client::area_map &areas) = 0;
/// Chunk data change
/// @param offset priority position offset
......
......@@ -9,7 +9,7 @@ namespace contouring {
Dummy(): Abstract() { }
virtual ~Dummy() { }
void update(const voxel_pos &, const world::area_map &) override {}
void update(const voxel_pos &, const world::client::area_map &) override {}
void onUpdate(const area_<chunk_pos> &, const chunk_pos &, const world::ChunkContainer &, geometry::Faces) override {}
void onNotify(const area_<chunk_pos> &, const chunk_pos &, const world::ChunkContainer &) override {}
void onGui() override { }
......
#include "FlatDualMC.hpp"
#include "../../../server/world/Chunk.hpp"
#include "../../../server/world/Area.hpp"
#include "../../../core/world/materials.hpp"
#include "../../core/world/EdittableChunk.hpp"
#include "../../core/world/Area.hpp"
#include "../../core/world/materials.hpp"
#include <Tracy.hpp> // NOLINT
#include <common/TracySystem.hpp> // NOLINT