1
0
Fork 0

Split client server

This commit is contained in:
May B. 2020-09-14 18:03:21 +02:00
parent f0f12da614
commit 0dcff4b885
110 changed files with 899 additions and 523 deletions

184
src/client/Client.cpp Normal file
View File

@ -0,0 +1,184 @@
#include "Client.hpp"
#include "render/gl/Renderer.hpp"
#include "render/gl/UI.hpp"
#include "render/gl/Pipeline.hpp"
#include "InputMap.hpp"
Client::Client() { }
Client::~Client() { }
void Client::run() {
if (!render::gl::Renderer::Load(window, {options.renderer.clear_color}))
return;
window.setTargetFPS(options.target_fps);
InputMap inputs(window.getPtr());
Controllable player(window.getPtr(), inputs, options.control);
Camera camera(&player, options.camera);
auto *pipeline = static_cast<render::gl::Pipeline*>(render::Renderer::Get()->createPipeline(options.renderer));
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();
//TODO: loop
do {
window.startFrame();
{ // 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.show_debug_menu, 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))
) {
player.position += player.velocity;
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");
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);
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);
}
if (inputs.isDown(Input::Throw)) {
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);
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.target_fps);
}
if (actions && render::UI::Actions::FullScreen) {
window.setFullscreen(options.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) {
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::ChangeContouring) {
state.contouring = NULL;
world.setContouring(contouring::load(options.contouring_idx, options.contouring_data));
state.contouring = world.getContouring();
}
pipeline->SkyEnable = options.renderer.skybox;
}
{ // 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, buffer::Abstract *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) {
pipeline->SphereProj = glm::vec4(pos, std::get<1>(area));
pipeline->Curvature = std::get<2>(area);
reports.models_count++;
reports.tris_count += buffer->draw(pass(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));
}
}
world.getContouring()->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density);
} else {
world.getContouring()->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.tool.radius)), glm::vec3(1 + options.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.getPtr());
inputs.poll();
FrameMark;
}
window.waitTargetFPS();
} while (!(inputs.isDown(Input::Quit) || window.shouldClose()));
render::UI::Unload();
render::Renderer::Unload();
window.destroy();
contouring::save(options.contouring_idx, state.contouring, options.contouring_data);
options.save();
}

26
src/client/Client.hpp Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include "state.h"
#include "Window.hpp"
namespace render {
class Renderer;
};
/// Client view
class Client {
public:
Client();
~Client();
void run();
protected:
private:
config::options options;
config::state state;
config::reports reports;
Window window;
};

View File

@ -49,4 +49,6 @@ bool InputMap::isPressing(Mouse input) const {
}
bool InputMap::isReleasing(Mouse input) const {
return !isDown(input) && wasDown(input);
}
}
void InputMap::poll() const { glfwPollEvents(); }

View File

@ -3,12 +3,11 @@
#include <robin_hood.h>
#include <vector>
#include <GL/gl3w.h>
#include <GLFW/glfw3.h>
enum class Input {
Forward, Backward, Left, Right, Up, Down,
Mouse, Debug, Throw
Mouse, Debug, Throw, Quit
};
enum class Mouse {
Left = GLFW_MOUSE_BUTTON_LEFT,
@ -35,6 +34,8 @@ public:
bool isPressing(Mouse input) const;
bool isReleasing(Mouse input) const;
void poll() const;
private:
GLFWwindow *window;
robin_hood::unordered_map<Input, int> Map = {
@ -46,7 +47,8 @@ private:
{Input::Down, GLFW_KEY_LEFT_SHIFT},
{Input::Mouse, GLFW_KEY_E},
{Input::Debug, GLFW_KEY_F3},
{Input::Throw, GLFW_KEY_B}
{Input::Throw, GLFW_KEY_B},
{Input::Quit, GLFW_KEY_ESCAPE}
};
const std::vector<Input> Toggles = {
Input::Mouse, Input::Debug, Input::Throw

121
src/client/Window.cpp Normal file
View File

@ -0,0 +1,121 @@
#include "Window.hpp"
#include <GL/gl3w.h>
#include <GLFW/glfw3.h>
#include <exception>
#include <thread>
#include <chrono>
#include "../core/utils/logger.hpp"
/// Default floating window width
constexpr auto DEFAULT_WIDTH = 1280;
/// Default floating window height
constexpr auto DEFAULT_HEIGHT = 720;
constexpr auto MIN_WIDTH = 854;
constexpr auto MIN_HEIGHT = 480;
constexpr auto APP_NAME = "Univerxel";
Window::Window() : ptr(nullptr), targetFPS(60) {
if (!glfwInit()) {
FATAL("Failed to initialize GLFW");
}
}
Window::~Window() {
glfwTerminate();
}
bool Window::create(const CreateInfo &opt) {
if(isReady()) {
LOG_W("Previous window in use");
return false;
}
glfwWindowHint(GLFW_SAMPLES, opt.samples);
switch (opt.client.type) {
case CreateInfo::Client::Type::GL:
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, opt.client.major);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, opt.client.minor);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
break;
default:
FATAL("Unsupported client type");
break;
}
#if FIXED_WINDOW
glfwWindowHint(GLFW_RESIZABLE, false); //Note: Dev-only: Force floating on i3
#endif
ptr = glfwCreateWindow(DEFAULT_WIDTH, DEFAULT_HEIGHT, APP_NAME, NULL, NULL);
if (ptr == NULL) {
LOG_E("Failed to open GLFW window");
return false;
}
glfwMakeContextCurrent(ptr);
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(ptr, GLFW_STICKY_KEYS, GL_TRUE);
// Hide the mouse and enable unlimited mouvement
glfwSetInputMode(ptr, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Set the mouse at the center of the screen
// TODO: move to input manager
glfwPollEvents();
glfwSetCursorPos(ptr, DEFAULT_WIDTH / 2, DEFAULT_HEIGHT / 2);
// Force aspect ratio
glfwSetWindowSizeLimits(ptr, MIN_WIDTH, MIN_HEIGHT, GLFW_DONT_CARE, GLFW_DONT_CARE);
glfwSetWindowAspectRatio(ptr, RATIO_WIDTH, RATIO_HEIGHT);
glfwSetFramebufferSizeCallback(ptr, opt.pfnResize);
glfwSetWindowTitle(ptr, APP_NAME);
glfwSetWindowAttrib(ptr, GLFW_RESIZABLE, true);
return true;
}
bool Window::isReady() const { return ptr != nullptr; }
void Window::setTargetFPS(int val) {
targetFPS = val;
glfwSwapInterval(static_cast<int>(val < MIN_FPS));
}
double Window::getTime() const {
return glfwGetTime();
}
void Window::startFrame() {
frameStart = getTime();
}
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));
}
}
}
void Window::destroy() {
glfwDestroyWindow(ptr);
}
bool Window::shouldClose() { return glfwWindowShouldClose(ptr); }
void Window::setFullscreen(bool val) {
// MAYBE: real fullscreen
if(fullscreen != val) {
fullscreen = val;
if (val) {
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
glfwSetWindowMonitor(ptr, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
} else {
glfwSetWindowMonitor(ptr, nullptr, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, GLFW_DONT_CARE);
}
}
}

53
src/client/Window.hpp Normal file
View File

@ -0,0 +1,53 @@
#pragma once
#include "../core/flags.hpp"
typedef struct GLFWwindow GLFWwindow;
typedef void (*GLFWframebuffersizefun)(GLFWwindow*, int, int);
/// GLFW context and window
class Window {
public:
Window();
~Window();
static constexpr auto MIN_FPS = 24;
static constexpr auto MAX_FPS = 240;
static constexpr auto RATIO_WIDTH = 16;
static constexpr auto RATIO_HEIGHT = 9;
/// Fixed window ratio
static constexpr auto RATIO = RATIO_WIDTH / (RATIO_HEIGHT * 1.0f);
struct CreateInfo {
GLFWframebuffersizefun pfnResize;
struct Client {
enum class Type { GL, VK } type;
int major;
int minor;
} client;
int samples;
};
bool create(const CreateInfo &opt);
void destroy();
bool isReady() const;
void setTargetFPS(int val);
void setFullscreen(bool val);
_FORCE_INLINE_ GLFWwindow *getPtr() { return ptr; }
void startFrame();
void waitTargetFPS();
bool shouldClose();
double getTime() const;
private:
GLFWwindow *ptr;
int targetFPS;
bool fullscreen;
double frameStart;
};

View File

@ -1,7 +1,7 @@
#include "Camera.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include "../render/window.hpp"
#include "../Window.hpp"
Camera::Camera(const Controllable* origin, const Camera::options& opt): origin(origin), o(opt) {
updateProjection();
@ -9,7 +9,7 @@ Camera::Camera(const Controllable* origin, const Camera::options& opt): origin(o
Camera::~Camera() { }
void Camera::updateProjection() {
ProjectionMatrix = glm::perspective(o.fov, RATIO, o.near, o.far);
ProjectionMatrix = glm::perspective(o.fov, Window::RATIO, o.near, o.far);
}
void Camera::update() {

View File

@ -1,8 +1,8 @@
#pragma once
#include "Controllable.hpp"
#include "../data/geometry/Frustum.hpp"
#include "../data/geometry/Ray.hpp"
#include "../../core/geometry/Frustum.hpp"
#include "../../core/geometry/Ray.hpp"
/// Moving perspective camera
class Camera {

View File

@ -1,6 +1,6 @@
#include "Controllable.hpp"
Controllable::Controllable(GLFWwindow *window, const InputMap& inputs, const Controllable::options& opt): position(voxel_pos(0), 1), window(window), inputs(inputs), o(opt){ }
Controllable::Controllable(GLFWwindow *window, const InputMap& inputs, const Controllable::options& opt): position(voxel_pos(100, 0, 0), 1), window(window), inputs(inputs), o(opt){ }
Controllable::~Controllable() { }
Controllable::axis Controllable::getAxis() const {

View File

@ -1,11 +1,9 @@
#pragma once
#include "InputMap.hpp"
#include "../InputMap.hpp"
#include <GL/gl3w.h>
#include <GLFW/glfw3.h>
#include "../data/glm.hpp"
#include "../world/position.h"
#include "../../core/data/glm.hpp"
#include "../../core/world/position.h"
/// Player controller moving entity
struct Controllable {

View File

@ -0,0 +1,45 @@
#pragma once
#include "gl/pass/VoxelProgram.hpp"
struct GLFWwindow;
class Camera;
namespace render {
/// Handle rendering passes and params
class Pipeline {
public:
/// Rendering options
struct options {
/// Voxel passes
pass::VoxelProgram::options voxel;
/// Display skybox
bool skybox = true;
/// Display only wires
bool wireframe = false;
/// Texture pack name
std::string textures = "1024-realistic";
/// Textures quality
float mipMapLOD = -.5;
/// Textures anisotropic mapping
int anisotropy = 0;
/// Depth color
glm::vec4 clear_color;
};
virtual ~Pipeline() { }
/// Start new frame and setup
virtual void beginFrame() = 0;
/// Apply postprocessing
virtual void endPass() = 0;
/// Swap displayed image
virtual void swapBuffer(GLFWwindow*) = 0;
/// Apply camera matrices
virtual void lookFrom(const Camera&) = 0;
virtual void setClearColor(glm::vec4) = 0;
};
}

View File

@ -0,0 +1,10 @@
#include "Renderer.hpp"
using namespace render;
Renderer *Renderer::sInstance = nullptr;
void Renderer::Unload() {
delete sInstance;
sInstance = nullptr;
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "../Window.hpp"
#include "Pipeline.hpp"
#include <cassert>
namespace render {
/// Rendering plateform interface
class Renderer {
public:
virtual ~Renderer() { }
virtual Pipeline* createPipeline(const Pipeline::options&) = 0;
virtual void loadUI(Window&) = 0;
static _FORCE_INLINE_ Renderer *Get() {
assert(sInstance != nullptr && "Uninitialized renderer");
return sInstance;
}
static void Unload();
protected:
static Renderer *sInstance;
};
}

View File

@ -1,33 +1,25 @@
#include "UI.hpp"
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include "../state.h"
#include "../contouring/Abstract.hpp"
#include "../world/materials.hpp"
#include "../../core/world/materials.hpp"
void UI::setup(GLFWwindow* window) {
using namespace render;
UI *UI::sInstance = nullptr;
UI::UI() {
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGui::StyleColorsDark();
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 130");
}
void UI::unload() {
ImGui_ImplGlfw_Shutdown();
ImGui_ImplOpenGL3_Shutdown();
UI::~UI() {
ImGui::DestroyContext();
}
UI::Actions UI::draw(options &options, state &state, const reports &reports, GLuint aim) {
UI::Actions UI::draw(config::options &options, config::state &state, const config::reports &reports, intptr_t aim) {
auto actions = Actions::None;
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
const ImGuiIO &io = ImGui::GetIO();
@ -35,7 +27,7 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
if(state.capture_mouse) {
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x / 2, io.DisplaySize.y / 2), ImGuiCond_Always, ImVec2(.5f, .5f));
ImGui::Begin("Aim", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoInputs);
ImGui::Image((void *)(intptr_t)aim, ImVec2(32, 32));
ImGui::Image((void *)aim, ImVec2(32, 32));
ImGui::End();
}
@ -60,7 +52,7 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
ImGui::Text("Tris: %ld (%ld models)", reports.tris_count, reports.models_count);
ImGui::Separator();
ImGui::Checkbox("Overlay", &options.overlay_show);
if (ImGui::SliderInt("FPS", &options.target_fps, MIN_FPS-1, MAX_FPS+1, options.target_fps > MIN_FPS ? (options.target_fps < MAX_FPS ? "%d" : "UNLIMITED") : "VSYNC")){
if (ImGui::SliderInt("FPS", &options.target_fps, Window::MIN_FPS-1, Window::MAX_FPS+1, options.target_fps > Window::MIN_FPS ? (options.target_fps < Window::MAX_FPS ? "%d" : "UNLIMITED") : "VSYNC")){
actions |= Actions::FPS;
}
@ -279,10 +271,12 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
ImGui::Render();
return actions;
}
void UI::render() {
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
bool UI::IsFocus() {
return ImGui::IsAnyItemActive();
}
bool UI::isFocus() {
return ImGui::IsAnyItemActive();
void UI::Unload() {
delete sInstance;
sInstance = nullptr;
}

66
src/client/render/UI.hpp Normal file
View File

@ -0,0 +1,66 @@
#pragma once
#include <stdint.h>
#include <cassert>
#include "../../core/flags.hpp"
namespace config {
struct options;
struct state;
struct reports;
}
namespace render {
//TODO: rewrite as static with function pointers
/// ImGui interface
class UI {
protected:
UI();
public:
virtual ~UI();
/// Retro actions to state
enum class Actions {
None = 0,
FPS = 1 << 0,
FullScreen = 1 << 1,
ClearColor = 1 << 2,
RendererSharders = 1 << 3,
RendererTextures = 1 << 4,
World = 1 << 5,
Camera = 1 << 6,
Control = 1 << 7,
ChangeContouring = 1 << 8,
};
friend inline void operator|=(Actions& a, Actions b) {
a = static_cast<Actions>(static_cast<int>(a) | static_cast<int>(b));
}
friend inline bool operator&&(Actions a, Actions b) {
return static_cast<int>(a) & static_cast<int>(b);
}
/// Compute UI
virtual Actions draw(config::options&, config::state&, const config::reports&) = 0;
/// Display UI
virtual void render() = 0;
/// Is UI in focus
static bool IsFocus();
static _FORCE_INLINE_ UI *Get() {
assert(sInstance != nullptr && "Uninitialized ui");
return sInstance;
}
static void Unload();
protected:
static Actions draw(config::options &, config::state &, const config::reports &, intptr_t aim);
static UI* sInstance;
};
};

View File

@ -1,10 +1,10 @@
#pragma once
#include "../render/buffer/Abstract.hpp"
#include "../world/forward.h"
#include "../data/geometry/Frustum.hpp"
#include "../data/geometry/Ray.hpp"
#include "../data/geometry/Faces.hpp"
#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"
/// Mesh creation
namespace contouring {

View File

@ -2,8 +2,8 @@
#include <imgui.h> // NOLINT
#include <toml.h>
#include "../world/Chunk.hpp"
#include "../world/Area.hpp"
#include "../../../server/world/Chunk.hpp"
#include "../../../server/world/Area.hpp"
namespace contouring {
size_t AbstractFlat::clear(const voxel_pos& pos, const world::area_map& areas) {

View File

@ -1,7 +1,7 @@
#pragma once
#include "Abstract.hpp"
#include "../data/math.hpp"
#include "../../../core/data/math.hpp"
namespace contouring {
/// Generating mesh for chunks 1:1

View File

@ -1,8 +1,8 @@
#include "FlatDualMC.hpp"
#include "../world/Chunk.hpp"
#include "../world/Area.hpp"
#include "../world/materials.hpp"
#include "../../../server/world/Chunk.hpp"
#include "../../../server/world/Area.hpp"
#include "../../../core/world/materials.hpp"
#include <Tracy.hpp> // NOLINT
#include <common/TracySystem.hpp> // NOLINT
#include <imgui.h> // NOLINT

View File

@ -3,10 +3,10 @@
#include "AbstractFlat.hpp"
#include "surrounding.hpp"
#include "../data/safe_queue.hpp"
#include "../data/safe_priority_queue.hpp"
#include "../data/circular_buffer.hpp"
#include "../render/buffer/LodShortIndexed.hpp"
#include "../../../core/data/safe_queue.hpp"
#include "../../../core/data/safe_priority_queue.hpp"
#include "../../../core/data/circular_buffer.hpp"
#include "../gl/buffer/LodShortIndexed.hpp"
#include <thread>
using namespace data;

View File

@ -1,7 +1,7 @@
#include "surrounding.hpp"
#include "../world/Area.hpp"
#include "../data/math.hpp"
#include "../../../server/world/Area.hpp"
#include "../../../core/data/math.hpp"
using namespace geometry;
namespace contouring::surrounding {

View File

@ -1,7 +1,7 @@
#pragma once
#include "../data/geometry/Faces.hpp"
#include "../world/forward.h"
#include "../../../core/geometry/Faces.hpp"
#include "../../../server/world/forward.h"
namespace world {
class Chunk;

View File

@ -1,9 +1,12 @@
#include "Renderer.hpp"
#include "Pipeline.hpp"
#include "../world/materials.hpp"
#include "../control/Camera.hpp"
#include "../../../core/world/materials.hpp"
#include "../../control/Camera.hpp"
#include <TracyOpenGL.hpp>
Renderer::Renderer(const Renderer::options& options):
using namespace render::gl;
Pipeline::Pipeline(const Pipeline::options& options):
IndicatorCubeBuffer(GL_LINES, 24, {
glm::vec3(0, 0, 0), glm::vec3(0, 0, 1),
glm::vec3(0, 0, 1), glm::vec3(0, 1, 1),
@ -43,16 +46,17 @@ Renderer::Renderer(const Renderer::options& options):
loadTextures(options.textures, options.mipMapLOD, options.anisotropy);
}
Renderer::~Renderer() {
Pipeline::~Pipeline() {
unloadTextures();
glDeleteVertexArrays(1, &VertexArrayID);
}
void Renderer::beginFrame() {
void Pipeline::beginFrame() {
TracyGpuZone("Render");
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
std::function<buffer::params(glm::mat4)> Renderer::beginWorldPass() {
std::function<buffer::params(glm::mat4)> Pipeline::beginWorldPass() {
WorldPass->useIt();
WorldPass->start(this);
return [&](glm::mat4 model) {
@ -60,7 +64,7 @@ std::function<buffer::params(glm::mat4)> Renderer::beginWorldPass() {
};
}
std::function<buffer::params(const std::vector<glm::mat4> &)> Renderer::beginEntityPass() {
std::function<buffer::params(const std::vector<glm::mat4> &)> Pipeline::beginEntityPass() {
EntityPass->useIt();
EntityPass->start(this);
return [&](const std::vector<glm::mat4>& models) {
@ -68,45 +72,57 @@ std::function<buffer::params(const std::vector<glm::mat4> &)> Renderer::beginEnt
};
}
size_t Renderer::drawIndicatorCube(glm::mat4 model) {
size_t Pipeline::drawIndicatorCube(glm::mat4 model) {
IndicatorPass->useIt();
return IndicatorCubeBuffer.draw(IndicatorPass->setup(this, model));
}
void Renderer::endFrame() {
void Pipeline::endPass() {
if(SkyEnable) {
SkyPass->draw(this);
}
}
void Renderer::reloadShaders(const pass::VoxelProgram::options& options) {
void Pipeline::swapBuffer(GLFWwindow* ptr) {
TracyGpuZone("Swap");
glfwSwapBuffers(ptr);
TracyGpuCollect;
}
void Pipeline::reloadShaders(const pass::VoxelProgram::options& options) {
WorldPass = std::make_unique<pass::WorldProgram>(options);
EntityPass = std::make_unique<pass::EntityProgram>(options);
}
void Renderer::reloadTextures(const std::string& texturePath, float mipMapLOD, float anisotropy) {
void Pipeline::reloadTextures(const std::string& texturePath, float mipMapLOD, float anisotropy) {
unloadTextures();
loadTextures(texturePath, mipMapLOD, anisotropy);
}
void Renderer::unloadTextures() {
void Pipeline::unloadTextures() {
glDeleteTextures(1, &HOSAtlas);
glDeleteTextures(1, &NormalAtlas);
glDeleteTextures(1, &TextureAtlas);
}
void Renderer::loadTextures(const std::string& texturePath, float mipMapLOD, float anisotropy) {
void Pipeline::loadTextures(const std::string& texturePath, float mipMapLOD, float anisotropy) {
std::vector<std::string> terrainTextures;
for(const auto& texture: world::materials::textures) {
terrainTextures.emplace_back(texturePath + "/terrain/" + texture);
}
TextureAtlas = pass::Program::loadTextureArray(terrainTextures, "", mipMapLOD, anisotropy * anisotropy);
NormalAtlas = pass::Program::loadTextureArray(terrainTextures, ".nrm", mipMapLOD, anisotropy * anisotropy);
HOSAtlas = pass::Program::loadTextureArray(terrainTextures, ".hos", mipMapLOD, anisotropy * anisotropy);
const auto ani = anisotropy >= 1 ? (1 << (static_cast<int>(anisotropy)-1)) : 0;
TextureAtlas = pass::Program::loadTextureArray(terrainTextures, "", mipMapLOD, ani);
NormalAtlas = pass::Program::loadTextureArray(terrainTextures, ".nrm", mipMapLOD, ani);
HOSAtlas = pass::Program::loadTextureArray(terrainTextures, ".hos", mipMapLOD, ani);
Skybox = pass::Program::loadTextureCube(texturePath + "/sky/Space_tray");
}
void Renderer::lookFrom(const Camera& camera) {
void Pipeline::lookFrom(const Camera& camera) {
ProjectionMatrix = camera.getProjectionMatrix();
ViewMatrix = camera.getViewMatrix();
FogDepth = camera.getDepth();
}
void Pipeline::setClearColor(glm::vec4 c) {
FogColor = c;
glClearColor(c.r, c.g, c.b, c.a);
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "../Pipeline.hpp"
#include <functional>
#include <memory>
#include <GL/gl3w.h>
@ -9,34 +10,17 @@
#include "pass/ColorProgram.hpp"
#include "buffer/Colored.hpp"
class Camera;
/// Handle rendering passes and params
class Renderer {
public:
/// Rendering options
struct options {
/// Voxel passes
pass::VoxelProgram::options voxel;
/// Display skybox
bool skybox = true;
/// Display only wires
bool wireframe = false;
/// Texture pack name
std::string textures = "1024-realistic";
/// Textures quality
float mipMapLOD = -.5;
/// Textures anisotropic mapping
int anisotropy = 0;
/// Depth color
glm::vec4 clear_color;
};
namespace render::gl {
Renderer(const options&);
Renderer(Renderer &&) = delete;
Renderer(const Renderer &) = delete;
Renderer &operator=(Renderer &&) = delete;
Renderer &operator=(const Renderer &) = delete;
~Renderer();
/// Handle OpenGL rendering passes and params
class Pipeline final: public render::Pipeline {
public:
Pipeline(const options&);
Pipeline(Pipeline &&) = delete;
Pipeline(const Pipeline &) = delete;
Pipeline &operator=(Pipeline &&) = delete;
Pipeline &operator=(const Pipeline &) = delete;
~Pipeline();
glm::vec3 LightInvDir = glm::vec3(0.5f, 2, 2);
glm::vec3 FogColor;
@ -71,7 +55,7 @@ public:
}
/// Start new frame and setup
void beginFrame();
void beginFrame() override;
/// Get started world program
std::function<buffer::params(glm::mat4)> beginWorldPass();
/// Get started entity program
@ -79,10 +63,13 @@ public:
/// Draw cube indicator
size_t drawIndicatorCube(glm::mat4 model);
/// Apply postprocessing
void endFrame();
void endPass() override;
void swapBuffer(GLFWwindow *) override;
void setClearColor(glm::vec4) override;
/// Apply camera matrices
void lookFrom(const Camera&);
void lookFrom(const Camera&) override;
void reloadShaders(const pass::VoxelProgram::options &);
void reloadTextures(const std::string &, float mipMapLOD, float anisotropy);
@ -106,3 +93,5 @@ private:
void loadTextures(const std::string &, float mipMapLOD, float anisotropy);
void unloadTextures();
};
}

View File

@ -0,0 +1,71 @@
#include "Renderer.hpp"
#include "UI.hpp"
#include "Pipeline.hpp"
#include "../../../core/utils/logger.hpp"
#include <GL/gl3w.h>
#include <TracyOpenGL.hpp>
using namespace render::gl;
constexpr auto GL_MAJOR = 4;
constexpr auto GL_MINOR = 6;
Renderer::Renderer(const Options& options): options(options) { }
Renderer::~Renderer() { }
bool Renderer::Load(Window& window, const Options& options) {
auto windowInfo = GetWindowInfo();
windowInfo.samples = 1;
if (!window.create(windowInfo))
return false;
if (gl3wInit() != GL3W_OK) {
LOG_E("Failed to initialize OpenGL");
return false;
}
if (!gl3wIsSupported(GL_MAJOR, GL_MINOR)) {
LOG_E("OpenGL " << GL_MAJOR << "." << GL_MINOR << " not supported");
return false;
}
LOG_D("OpenGL " << glGetString(GL_VERSION) << ", GLSL " << glGetString(GL_SHADING_LANGUAGE_VERSION));
sInstance = new Renderer(options);
return true;
}
void framebuffer_size_callback(GLFWwindow *, int width, int height) {
glViewport(0, 0, width, height);
}
Window::CreateInfo Renderer::GetWindowInfo() {
Window::CreateInfo windowInfo;
windowInfo.pfnResize = framebuffer_size_callback;
windowInfo.client = { Window::CreateInfo::Client::Type::GL, GL_MAJOR, GL_MINOR };
return windowInfo;
}
render::Pipeline *Renderer::createPipeline(const render::Pipeline::options &opt) {
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LEQUAL);
// Cull triangles which normal is not towards the camera
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
GLint smp;
glGetIntegerv(GL_SAMPLES, &smp);
if (smp > 0) {
glEnable(GL_MULTISAMPLE);
}
glClearColor(options.clear_color.x, options.clear_color.y, options.clear_color.z, options.clear_color.w);
TracyGpuContext;
return new Pipeline(opt);
}
void Renderer::loadUI(Window& w) {
UI::Load(w);
}

View File

@ -0,0 +1,32 @@
#pragma once
#include "../Renderer.hpp"
#include <glm/vec4.hpp>
namespace render::gl {
/// OpenGL rendering
class Renderer final: public render::Renderer {
public:
virtual ~Renderer();
struct Options {
/// Depth color
glm::vec4 clear_color;
};
static bool Load(Window& window, const Options &options);
render::Pipeline *createPipeline(const render::Pipeline::options &) override;
void loadUI(Window &) override;
static _FORCE_INLINE_ Renderer *Get() { return static_cast<Renderer*>(render::Renderer::Get()); }
private:
Renderer(const Options &options);
static Window::CreateInfo GetWindowInfo();
Options options;
};
}

View File

@ -0,0 +1,9 @@
#include "Texture.hpp"
#include "texture.hpp"
using namespace render::gl;
GLuint Texture::CreatePtr(const std::string &name, bool linear) {
return loadDDS("content/textures/" + name + ".dds", linear);
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <string>
#include <GLFW/glfw3.h>
namespace render::gl {
class Texture {
public:
static GLuint CreatePtr(const std::string &name, bool linear);
};
}

View File

@ -0,0 +1,31 @@
#include "UI.hpp"
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include "Texture.hpp"
using namespace render::gl;
UI::UI(GLFWwindow *window): render::UI() {
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 130");
aim = Texture::CreatePtr("ui/Aim", false);
}
UI::~UI() {
ImGui_ImplGlfw_Shutdown();
ImGui_ImplOpenGL3_Shutdown();
}
UI::Actions UI::draw(config::options &o, config::state &s, const config::reports &r) {
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
return render::UI::draw(o, s, r, aim);
}
void UI::render() {
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
void UI::Load(Window& w) {
UI::sInstance = new UI(w.getPtr());
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "../UI.hpp"
#include "../../Window.hpp"
namespace render::gl {
/// ImGui OpenGL/GLFW interface
class UI final: public render::UI {
private:
UI(GLFWwindow *window);
public:
~UI();
static void Load(Window &);
Actions draw(config::options &, config::state &, const config::reports &) override;
void render() override;
private:
intptr_t aim;
};
}

View File

@ -1,7 +1,7 @@
#include "ShortIndexed.hpp"
#include "vboindexer.hpp"
#include "../../data/logger.hpp"
#include "../../../../core/utils/logger.hpp"
using namespace buffer;

View File

@ -1,6 +1,6 @@
#include "ColorProgram.hpp"
#include "../Renderer.hpp"
#include "../Pipeline.hpp"
using namespace pass;
@ -20,7 +20,7 @@ ColorProgram::~ColorProgram() { }
std::string ColorProgram::getName() const {
return "Color";
}
buffer::params ColorProgram::setup(Renderer *renderer, glm::mat4 modelMatrix) {
buffer::params ColorProgram::setup(render::gl::Pipeline *renderer, glm::mat4 modelMatrix) {
const auto mvp = renderer->getProjectionMatrix() * renderer->getViewMatrix() * modelMatrix;
setMVP(&mvp[0][0]);
return buffer::params{.vertexOnly = false};

View File

@ -9,7 +9,7 @@ namespace pass {
ColorProgram();
~ColorProgram();
buffer::params setup(Renderer *, glm::mat4 modelMatrix);
buffer::params setup(render::gl::Pipeline *, glm::mat4 modelMatrix);
protected:
std::string getName() const override;

View File

@ -1,6 +1,6 @@
#include "EntityProgram.hpp"
#include "../Renderer.hpp"
#include "../Pipeline.hpp"
using namespace pass;
@ -17,7 +17,7 @@ EntityProgram::EntityProgram(const EntityProgram::options &opts) : VoxelProgram(
}
EntityProgram::~EntityProgram() { }
buffer::params EntityProgram::setup(Renderer *renderer, const std::vector<glm::mat4>& modelsMatrices) {
buffer::params EntityProgram::setup(render::gl::Pipeline *renderer, const std::vector<glm::mat4>& modelsMatrices) {
setModels(&modelsMatrices[0][0][0], modelsMatrices.size());
auto params = VoxelProgram::setup(renderer);
params.instances = modelsMatrices.size();

View File

@ -11,7 +11,7 @@ namespace pass {
static constexpr auto LOCATION = 6;
buffer::params setup(Renderer *, const std::vector<glm::mat4> &modelsMatrices);
buffer::params setup(render::gl::Pipeline *, const std::vector<glm::mat4> &modelsMatrices);
void disable();
protected:

View File

@ -2,7 +2,7 @@
#include <algorithm>
#include <stdexcept>
#include "texture.hpp"
#include "../texture.hpp"
#define CONTENT_DIR "content/"
#define SHADER_DIR CONTENT_DIR "shaders/"

View File

@ -8,7 +8,9 @@
#include "Shader.hpp"
#include "../buffer/Abstract.hpp"
class Renderer;
namespace render::gl {
class Pipeline;
}
/// OpenGL programs
namespace pass {
/// OpenGL shaders pipeline

View File

@ -1,6 +1,6 @@
#include "SkyProgram.hpp"
#include "../Renderer.hpp"
#include "../Pipeline.hpp"
using namespace pass;
@ -65,7 +65,7 @@ SkyProgram::~SkyProgram() { }
std::string SkyProgram::getName() const {
return "Sky";
}
void SkyProgram::start(Renderer *renderer) {
void SkyProgram::start(render::gl::Pipeline *renderer) {
const auto fixedView = glm::mat4(glm::mat3(renderer->getViewMatrix()));
setView(&fixedView[0][0]);
setProjection(&renderer->getProjectionMatrix()[0][0]);
@ -75,7 +75,7 @@ void SkyProgram::start(Renderer *renderer) {
buffer::params SkyProgram::setup() {
return buffer::params{.vertexOnly = true};
}
void SkyProgram::draw(Renderer *renderer) {
void SkyProgram::draw(render::gl::Pipeline *renderer) {
useIt();
start(renderer);
CubeBuffer.draw(setup());

View File

@ -10,11 +10,11 @@ namespace pass {
SkyProgram();
~SkyProgram();
void start(Renderer *);
void start(render::gl::Pipeline *);
buffer::params setup();
/// Direct draw using internal buffer
void draw(Renderer *);
void draw(render::gl::Pipeline *);
protected:
std::string getName() const override;

View File

@ -1,6 +1,6 @@
#include "VoxelProgram.hpp"
#include "../Renderer.hpp"
#include "../Pipeline.hpp"
using namespace pass;
@ -53,7 +53,7 @@ VoxelProgram::~VoxelProgram() { }
std::string VoxelProgram::getName() const {
return "Voxel";
}
void VoxelProgram::start(Renderer *renderer) {
void VoxelProgram::start(render::gl::Pipeline *renderer) {
bindTexture(renderer->getTextureAtlas());
bindNormal(renderer->getNormalAtlas());
bindHOS(renderer->getHOSAtlas());
@ -62,7 +62,7 @@ void VoxelProgram::start(Renderer *renderer) {
setView(&renderer->getViewMatrix()[0][0]);
setProj(&renderer->getProjectionMatrix()[0][0]);
}
buffer::params VoxelProgram::setup(Renderer *renderer) {
buffer::params VoxelProgram::setup(render::gl::Pipeline *renderer) {
setSphereProj(&renderer->SphereProj[0]);
setCurvature(renderer->Curvature);
return buffer::params{.vertexOnly = false};

View File

@ -29,10 +29,10 @@ namespace pass {
VoxelProgram(const options &opts, std::vector<std::string> flags = {});
~VoxelProgram();
void start(Renderer *);
void start(render::gl::Pipeline *);
protected:
buffer::params setup(Renderer *);
buffer::params setup(render::gl::Pipeline *);
std::string getName() const override;
void setView(const GLfloat *matrix);

View File

@ -1,6 +1,6 @@
#include "WorldProgram.hpp"
#include "../Renderer.hpp"
#include "../Pipeline.hpp"
using namespace pass;
@ -11,7 +11,7 @@ WorldProgram::WorldProgram(const WorldProgram::options& opts): VoxelProgram(opts
WorldProgram::~WorldProgram() { }
buffer::params WorldProgram::setup(Renderer *renderer, glm::mat4 modelMatrix) {
buffer::params WorldProgram::setup(render::gl::Pipeline *renderer, glm::mat4 modelMatrix) {
setModel(&modelMatrix[0][0]);
return VoxelProgram::setup(renderer);
}

View File

@ -9,7 +9,7 @@ namespace pass {
WorldProgram(const options &opts);
~WorldProgram();
buffer::params setup(Renderer *, glm::mat4 modelMatrix);
buffer::params setup(render::gl::Pipeline *, glm::mat4 modelMatrix);
protected:
void setModel(const GLfloat *matrix);

View File

@ -1,19 +1,19 @@
#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 <glm/vec4.hpp>
#include "render/Renderer.hpp"
#include "world/Universe.hpp"
#include "render/Pipeline.hpp"
#include "../server/world/Universe.hpp"
#include "control/Camera.hpp"
#include "contouring/index.hpp"
#include "render/contouring/index.hpp"
namespace config {
inline glm::vec4 fromHex(const std::string& str) {
std::array<int, 3> rgb = {UCHAR_MAX};
@ -164,7 +164,7 @@ struct options {
int target_fps;
int samples;
bool fullscreen;
Renderer::options renderer;
render::Pipeline::options renderer;
bool show_debug_world;
world::Universe::options world;
@ -208,4 +208,6 @@ struct state {
struct reports {
size_t tris_count = 0;
size_t models_count = 0;
};
};
}

24
src/core/flags.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef _ALWAYS_INLINE_
#if defined(__GNUC__) && (__GNUC__ >= 4)
#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
#elif defined(__llvm__)
#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#define _ALWAYS_INLINE_ __forceinline
#else
#define _ALWAYS_INLINE_ inline
#endif
#endif
//should always inline, except in some cases because it makes debugging harder
#ifndef _FORCE_INLINE_
#ifdef DISABLE_FORCED_INLINE
#define _FORCE_INLINE_ inline
#else
#define _FORCE_INLINE_ _ALWAYS_INLINE_
#endif
#endif

View File

@ -1,6 +1,6 @@
#pragma once
#include "../../world/position.h"
#include "../world/position.h"
/// Math utils
namespace geometry {

View File

@ -1,7 +1,7 @@
#pragma once
#include "IBox.hpp"
#include "../../world/position.h"
#include "../world/position.h"
namespace geometry {
/// Raycast with distance

View File

@ -10,6 +10,7 @@
#define LOG_W(expr) _OUT("[" << YELLOW << logger::now() << END_COLOR << "] " << expr)
#define LOG_I(expr) _OUT("[" << GREEN << logger::now() << END_COLOR << "] " << expr)
#define LOG_D(expr) _OUT("[" << GREY << logger::now() << END_COLOR << "] " << expr)
#define FATAL(expr) LOG_E(expr); exit(EXIT_FAILURE)
namespace logger {
std::_Put_time<char> now();

View File

@ -7,18 +7,8 @@
* Univerxel main program.
*/
#include <iostream>
#include <chrono>
#include "render/window.hpp"
#include "render/UI.hpp"
#include "control/InputMap.hpp" //TODO: add options
#include "state.h"
#include "data/math.hpp"
#include "client/Client.hpp"
#include <Tracy.hpp>
#include <TracyOpenGL.hpp>
#if TRACY_MEMORY
void *operator new(std::size_t count)
@ -37,209 +27,13 @@ void operator delete(void *ptr) noexcept
/// Entry point
int main(int /*unused*/, char */*unused*/[]){
LOG("Univerxel");
options options;
state state;
reports reports;
GLFWwindow *window = createWindow(options.samples);
if(window == nullptr)
return 1;
glClearColor(options.renderer.clear_color.x, options.renderer.clear_color.y, options.renderer.clear_color.z, options.renderer.clear_color.w);
glfwSwapInterval(static_cast<int>(options.target_fps < MIN_FPS));
InputMap inputs(window);
Controllable player(window, inputs, options.control);
Camera camera(&player, options.camera);
auto *renderer = new Renderer(options.renderer);
renderer->LightInvDir = glm::normalize(glm::vec3(-.5f, 2, -2));
UI::setup(window);
GLuint aimTexture = pass::Program::loadTexture("ui/Aim", false);
#if TRACY_ENABLE
LOG("Profiling !");
#endif
TracyGpuContext;
world::Universe world = world::Universe(options.world);
world.setContouring(contouring::load(options.contouring_idx, options.contouring_data));
state.contouring = world.getContouring();
do {
const double startTime = glfwGetTime();
{ // Update
ZoneScopedN("Update");
static double lastTime = glfwGetTime();
const double partTime = glfwGetTime();
const float deltaTime = partTime - lastTime;
inputs.toggle(state.capture_mouse, Input::Mouse);
inputs.toggle(options.show_debug_menu, Input::Debug);
player.capture(state.capture_mouse, !UI::isFocus(), deltaTime);
if(player.velocity != glm::vec3(0) && (
!options.control.collide ||
!world.collide(player.position, player.velocity, options.voxel_density, 1))
) {
player.position += player.velocity;
state.position = player.position;
}
camera.update();
renderer->lookFrom(camera);
renderer->LightInvDir = glm::vec3(glm::rotate(glm::mat4(1), deltaTime * .1f, glm::vec3(1, .5, .1)) * glm::vec4(renderer->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");
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);
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);
}
if (inputs.isDown(Input::Throw)) {
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);
inputs.saveKeys();
lastTime = partTime;
}
{
ZoneScopedN("UI");
const auto actions = UI::draw(options, state, reports, aimTexture);
if (actions && UI::Actions::FPS) {
glfwSwapInterval(static_cast<int>(options.target_fps < MIN_FPS));
}
if (actions && UI::Actions::FullScreen) {
// MAYBE: real fullscreen
if(options.fullscreen) {
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
} else {
glfwSetWindowMonitor(window, nullptr, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, GLFW_DONT_CARE);
}
}
if(actions && UI::Actions::ClearColor) {
renderer->FogColor = glm::vec3(options.renderer.clear_color.x, options.renderer.clear_color.y, options.renderer.clear_color.z);
glClearColor(options.renderer.clear_color.x, options.renderer.clear_color.y, options.renderer.clear_color.z, options.renderer.clear_color.w);
}
if(actions && UI::Actions::RendererSharders) {
renderer->reloadShaders(options.renderer.voxel);
}
if(actions && UI::Actions::RendererTextures) {
renderer->reloadTextures(options.renderer.textures, options.renderer.mipMapLOD, options.renderer.anisotropy);
}
if(actions && UI::Actions::World) {
world.setOptions(options.world);
}
if(actions && UI::Actions::Camera) {
camera.setOptions(options.camera);
}
if(actions && UI::Actions::Control) {
player.setOptions(options.control);
}
if(actions && UI::Actions::ChangeContouring) {
state.contouring = NULL;
world.setContouring(contouring::load(options.contouring_idx, options.contouring_data));
state.contouring = world.getContouring();
}
renderer->SkyEnable = options.renderer.skybox;
}
{ // Rendering
ZoneScopedN("Render");
TracyGpuZone("Render");
renderer->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 = renderer->beginWorldPass();
const auto draw = [&](glm::mat4 model, buffer::Abstract *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) {
renderer->SphereProj = glm::vec4(pos, std::get<1>(area));
renderer->Curvature = std::get<2>(area);
reports.models_count++;
reports.tris_count += buffer->draw(pass(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 = 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));
}
}
world.getContouring()->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density);
} else {
world.getContouring()->getModels(draw, frustum, offset, options.voxel_density);
}
}
{ // Entities
const auto pass = renderer->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.tool.radius)), glm::vec3(1 + options.tool.radius * 2));
reports.models_count++;
reports.tris_count += renderer->drawIndicatorCube(model);
}
renderer->endFrame();
UI::render();
}
{ // Swap buffers
ZoneScopedN("Swap");
TracyGpuZone("Swap");
glfwSwapBuffers(window);
glfwPollEvents();
TracyGpuCollect;
FrameMark;
}
{ // Wait target fps
if(options.target_fps >= MIN_FPS && options.target_fps <= MAX_FPS) {
while (glfwGetTime() < startTime + 1.0 / options.target_fps) {
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
}
}
} // Check if the ESC key was pressed or the window was closed
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0);
UI::unload();
delete renderer;
// Close OpenGL window and terminate GLFW
glfwTerminate();
contouring::save(options.contouring_idx, state.contouring, options.contouring_data);
options.save();
Client client;
client.run();
return 0;
}

View File

@ -1,41 +0,0 @@
#pragma once
#include <GL/gl3w.h>
#include <GLFW/glfw3.h>
struct options;
struct state;
struct reports;
namespace UI {
/// Retro actions to state
enum class Actions {
None = 0,
FPS = 1 << 0,
FullScreen = 1 << 1,
ClearColor = 1 << 2,
RendererSharders = 1 << 3,
RendererTextures = 1 << 4,
World = 1 << 5,
Camera = 1 << 6,
Control = 1 << 7,
ChangeContouring = 1 << 8,
};
inline void operator|=(Actions& a, Actions b) {
a = static_cast<Actions>(static_cast<int>(a) | static_cast<int>(b));
}
inline bool operator&&(Actions a, Actions b) {
return static_cast<int>(a) & static_cast<int>(b);
}
/// Prepare UI
void setup(GLFWwindow*);
/// Release UI
void unload();
/// Compute UI
Actions draw(options&, state&, const reports&, GLuint aim);
/// Is UI in focus
bool isFocus();
/// Display UI
void render();
};

View File

@ -1,97 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include "window.hpp"
#include <GL/gl3w.h>
#include <GLFW/glfw3.h>
#define MIN_WIDTH 854
#define MIN_HEIGHT 480
#define GL_MAJOR 3
#define GL_MINOR 3
void framebuffer_size_callback(GLFWwindow *, int width, int height) {
glViewport(0, 0, width, height);
}
GLFWwindow* createWindow(int samples) {
GLFWwindow *window;
// Initialise GLFW
if (!glfwInit()) {
fprintf(stderr, "Failed to initialize GLFW\n");
getchar();
return NULL;
}
glfwWindowHint(GLFW_SAMPLES, samples);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, GL_MAJOR);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, GL_MINOR);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#if FIXED_WINDOW
glfwWindowHint(GLFW_RESIZABLE, false); //Note: Dev-only: Force floating on i3
#endif
window = glfwCreateWindow(DEFAULT_WIDTH, DEFAULT_HEIGHT, "Univerxel", NULL, NULL);
if (window == NULL) {
fprintf(stderr, "Failed to open GLFW window.\n");
getchar();
glfwTerminate();
return NULL;
}
glfwMakeContextCurrent(window);
// Initialize gl3w
if (gl3wInit()) {
fprintf(stderr, "failed to initialize OpenGL\n");
glfwTerminate();
return NULL;
}
if (!gl3wIsSupported(GL_MAJOR, GL_MINOR)) {
fprintf(stderr, "OpenGL %d.%d not supported\n", GL_MAJOR, GL_MINOR);
glfwTerminate();
return NULL;
}
printf("OpenGL %s, GLSL %s\n", glGetString(GL_VERSION),
glGetString(GL_SHADING_LANGUAGE_VERSION));
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// Hide the mouse and enable unlimited mouvement
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Set the mouse at the center of the screen
glfwPollEvents();
glfwSetCursorPos(window, DEFAULT_WIDTH / 2, DEFAULT_HEIGHT / 2);
// Force aspect ratio
glfwSetWindowSizeLimits(window, MIN_WIDTH, MIN_HEIGHT, GLFW_DONT_CARE, GLFW_DONT_CARE);
glfwSetWindowAspectRatio(window, RATIO_WIDTH, RATIO_HEIGHT);
// Handle resize
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetWindowTitle(window, "Univerxel");
glfwSetWindowAttrib(window, GLFW_RESIZABLE, true);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LEQUAL);
// Cull triangles which normal is not towards the camera
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
GLint smp;
glGetIntegerv(GL_SAMPLES, &smp);
if(smp > 0) {
glEnable(GL_MULTISAMPLE);
}
return window;
}

View File

@ -1,20 +0,0 @@
#ifndef WINDOW_HPP
#define WINDOW_HPP
#define RATIO_WIDTH 16
#define RATIO_HEIGHT 9
/// Fixed window ratio
#define RATIO RATIO_WIDTH / (RATIO_HEIGHT * 1.0f)
/// Default floating window width
#define DEFAULT_WIDTH 1280
/// Default floating window height
#define DEFAULT_HEIGHT 720
#include <GL/gl3w.h>
#include <GLFW/glfw3.h>
/// Initialise glew and glfw, then create window
GLFWwindow *createWindow(int samples);
#endif

0
src/server/Server.hpp Normal file
View File

View File

@ -5,7 +5,7 @@
using namespace libguarded;
#include "region/index.hpp"
#include "generator.hpp"
#include "../data/geometry/IBox.hpp"
#include "../../core/geometry/IBox.hpp"
namespace world {
/// Chunk map with restricted access

View File

@ -1,7 +1,7 @@
#include "Chunk.hpp"
#include <algorithm>
#include "../data/math.hpp"
#include "../../core/data/math.hpp"
#include <Tracy.hpp>
using namespace world;

View File

@ -4,8 +4,8 @@
#include <sstream>
#include "generator.hpp"
#include "Voxel.hpp"
#include "../data/geometry/Faces.hpp"
#include "../data/math.hpp"
#include "../../core/geometry/Faces.hpp"
#include "../../core/data/math.hpp"
/// Chunk length
namespace world {

View File

@ -6,7 +6,7 @@
#include <FastNoiseSIMD.h>
#endif
#include <memory>
#include "position.h"
#include "../../core/world/position.h"
namespace world {
/// Noise handler

View File

@ -5,10 +5,10 @@
#include <filesystem>
#include <random>
#include "../contouring/Dummy.hpp"
#include "../../client/render/contouring/Dummy.hpp"
#include "Chunk.hpp"
#include "../render/buffer/ShortIndexed.hpp"
#include "../../client/render/gl/buffer/ShortIndexed.hpp"
using namespace world;

Some files were not shown because too many files have changed in this diff Show More