188 lines
8.4 KiB
C++
188 lines
8.4 KiB
C++
#include "Client.hpp"
|
|
|
|
#include "render/index.hpp"
|
|
#include "render/UI.hpp"
|
|
|
|
#include "InputMap.hpp"
|
|
#include "world/index.hpp"
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
#include "../core/data/math.hpp"
|
|
#include <Tracy.hpp>
|
|
|
|
Client::Client(config::client::options& options): options(options) { }
|
|
Client::~Client() { }
|
|
|
|
void Client::run(server_handle* const localHandle) {
|
|
if (!render::Load(window, options.preferVulkan, options.renderer))
|
|
return;
|
|
|
|
window.setTargetFPS(options.window.targetFPS);
|
|
|
|
|
|
InputMap inputs(window.getPtr());
|
|
Controllable player(window.getPtr(), inputs, options.control);
|
|
Camera camera(&player, options.camera);
|
|
|
|
auto pipeline = render::Renderer::Get();
|
|
pipeline->LightInvDir = glm::normalize(glm::vec3(-.5f, 2, -2));
|
|
render::Renderer::Get()->loadUI(window);
|
|
|
|
auto world = world::client::Load(options.connection, localHandle, options.world, options.contouring);
|
|
state.contouring = world->getContouring();
|
|
|
|
//TODO: loop
|
|
do {
|
|
window.startFrame();
|
|
FrameMark;
|
|
{ // Update
|
|
ZoneScopedN("Update");
|
|
static double lastTime = window.getTime();
|
|
const double partTime = window.getTime();
|
|
const float deltaTime = partTime - lastTime;
|
|
inputs.toggle(state.capture_mouse, Input::Mouse);
|
|
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, options.voxel_density))
|
|
) {
|
|
player.position += player.velocity;
|
|
const auto pos = player.position.as_voxel(options.voxel_density);
|
|
if(pos != state.position.as_voxel(options.voxel_density)) {
|
|
world->emit(world::action::Move(pos));
|
|
}
|
|
state.position = player.position;
|
|
}
|
|
camera.update();
|
|
pipeline->lookFrom(camera);
|
|
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);
|
|
if(auto target = std::get_if<world::Universe::ray_target>(&ray_result)) {
|
|
state.look_at = *target;
|
|
} else {
|
|
state.look_at = {};
|
|
}
|
|
}
|
|
if (state.capture_mouse) {
|
|
if (state.look_at.has_value()) {
|
|
ZoneScopedN("Edit");
|
|
const auto &tool = options.editor.tool;
|
|
if (inputs.isPressing(Mouse::Left))
|
|
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->emit(world::action::FillCube(
|
|
state.look_at.value().pos, world::Voxel(tool.material, world::Voxel::DENSITY_MAX), tool.radius));
|
|
}
|
|
if (inputs.isDown(Input::Throw)) {
|
|
//FIXME: register entity type world->addEntity(entity_id(0), {state.position * options.voxel_density, glm::vec3(10, 0, 0)});
|
|
}
|
|
}
|
|
world->update(state.position.as_voxel(options.voxel_density), deltaTime);
|
|
inputs.saveKeys();
|
|
lastTime = partTime;
|
|
}
|
|
|
|
{
|
|
ZoneScopedN("UI");
|
|
const auto actions = render::UI::Get()->draw(options, state, reports);
|
|
if (actions && render::UI::Actions::FPS) {
|
|
window.setTargetFPS(options.window.targetFPS);
|
|
}
|
|
if (actions && render::UI::Actions::FullScreen) {
|
|
window.setFullscreen(options.window.fullscreen);
|
|
}
|
|
if(actions && render::UI::Actions::ClearColor) {
|
|
pipeline->setClearColor(options.renderer.clear_color);
|
|
}
|
|
if(actions && render::UI::Actions::RendererSharders) {
|
|
pipeline->reloadShaders(options.renderer.voxel);
|
|
}
|
|
if(actions && render::UI::Actions::RendererTextures) {
|
|
pipeline->reloadTextures(options.renderer.textures, options.renderer.mipMapLOD, options.renderer.anisotropy);
|
|
}
|
|
if(actions && render::UI::Actions::World) {
|
|
//FIXME: server options world->setOptions(options.world);
|
|
}
|
|
if(actions && render::UI::Actions::Camera) {
|
|
camera.setOptions(options.camera);
|
|
}
|
|
if(actions && render::UI::Actions::Control) {
|
|
player.setOptions(options.control);
|
|
}
|
|
if(actions && render::UI::Actions::FillMode) {
|
|
//TODO: pipeline->setFillMode(options.renderer.wireframe);
|
|
}
|
|
}
|
|
{ // Rendering
|
|
ZoneScopedN("Render");
|
|
pipeline->beginFrame();
|
|
|
|
reports.models_count = 0;
|
|
reports.tris_count = 0;
|
|
std::optional<geometry::Frustum> frustum;
|
|
if(options.culling >= 0) {
|
|
frustum = {camera.getFrustum()};
|
|
}
|
|
const auto offset = state.position.raw_as_long();
|
|
{ // Chunks
|
|
const auto pass = pipeline->beginWorldPass();
|
|
const auto draw = [&](glm::mat4 model, render::LodModel *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) {
|
|
pipeline->setCurvature(glm::vec4(pos, std::get<1>(area)), std::get<2>(area));
|
|
reports.models_count++;
|
|
reports.tris_count += pass(buffer, model);
|
|
};
|
|
if (options.culling > 0) {
|
|
std::vector<glm::vec3> occlusion;
|
|
const auto ratio = options.culling * 2;
|
|
occlusion.reserve(glm::pow2(ratio * 2 - 1));
|
|
const auto [ch, cv] = player.getAngles();
|
|
const auto max_v = tan(options.camera.fov / 2.), max_h = Window::RATIO * max_v;
|
|
for(int iv = -ratio + 1; iv < ratio; iv++) {
|
|
const auto v = cv + max_v * iv / ratio;
|
|
for(int ih = -ratio + 1; ih < ratio; ih++) {
|
|
const auto h = ch + max_h * ih / ratio;
|
|
occlusion.emplace_back(cos(v) * sin(h), sin(v), cos(v) * cos(h));
|
|
}
|
|
}
|
|
state.contouring->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density);
|
|
} else {
|
|
state.contouring->getModels(draw, frustum, offset, options.voxel_density);
|
|
}
|
|
}
|
|
{ // Entities
|
|
const auto pass = pipeline->beginEntityPass();
|
|
/*const auto draw = [&](const std::vector<glm::mat4>& models, buffer::Abstract *const buffer) {
|
|
reports.models_count += models.size();
|
|
reports.tris_count += buffer->draw(pass(models));
|
|
};*/
|
|
//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.editor.tool.radius)), glm::vec3(1 + options.editor.tool.radius * 2));
|
|
reports.models_count++;
|
|
reports.tris_count += pipeline->drawIndicatorCube(model);
|
|
}
|
|
pipeline->endPass();
|
|
|
|
render::UI::Get()->render();
|
|
}
|
|
|
|
{ // Swap buffers
|
|
ZoneScopedN("Swap");
|
|
pipeline->swapBuffer(window);
|
|
inputs.poll();
|
|
}
|
|
|
|
window.waitTargetFPS();
|
|
} while (!(inputs.isDown(Input::Quit) || window.shouldClose()));
|
|
|
|
render::UI::Unload();
|
|
render::Renderer::Unload();
|
|
window.destroy();
|
|
|
|
options.contouring = state.contouring->getOptions();
|
|
} |