1
0
Fork 0
Univerxel/src/main.cpp

258 lines
9.9 KiB
C++

/**
* \file main.cpp
* \brief Univerxel game
* \author Maelys Bois
* \version 0.0.1
*
* Univerxel main program.
*/
#include <iostream>
#include <chrono>
#include "render/window.hpp"
#include "render/UI.hpp"
#include "control/InputMap.hpp" //TODO: add options
#include "render/pass/ColorProgram.hpp"
#include "render/buffer/Colored.hpp"
#include "state.h"
#include "data/math.hpp"
#include <Tracy.hpp>
#include <TracyOpenGL.hpp>
#if TRACY_MEMORY
void *operator new(std::size_t count)
{
auto ptr = malloc(count);
TracyAlloc(ptr, count);
return ptr;
}
void operator delete(void *ptr) noexcept
{
TracyFree(ptr);
free(ptr);
}
#endif
/// 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::vec3(-0.5f, 2, -2);
UI::setup(window);
GLuint aimTexture = pass::Program::loadTexture("ui/Aim", false);
auto *lookProgram = new pass::ColorProgram();
buffer::Colored lookBuffer(GL_LINES, 24, {
glm::vec3(0, 0, 0), glm::vec3(0, 0, 1),
glm::vec3(0, 0, 1), glm::vec3(0, 1, 1),
glm::vec3(0, 1, 1), glm::vec3(0, 1, 0),
glm::vec3(0, 1, 0), glm::vec3(0, 0, 0),
glm::vec3(1, 0, 0), glm::vec3(1, 0, 1),
glm::vec3(1, 0, 1), glm::vec3(1, 1, 1),
glm::vec3(1, 1, 1), glm::vec3(1, 1, 0),
glm::vec3(1, 1, 0), glm::vec3(1, 0, 0),
glm::vec3(0, 0, 0), glm::vec3(1, 0, 0),
glm::vec3(0, 0, 1), glm::vec3(1, 0, 1),
glm::vec3(0, 1, 1), glm::vec3(1, 1, 1),
glm::vec3(0, 1, 0), glm::vec3(1, 1, 0),
}, {
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
glm::vec4(1, 1, 1, 1), glm::vec4(1, 1, 1, 1),
});
#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);
state.look_at = world.raycast(camera.getRay() * options.voxel_density);
if (state.capture_mouse) {
if (state.look_at.has_value()) {
if (inputs.isPressing(Mouse::Left))
world.setCube(state.look_at.value().pos, world::Voxel(0), 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.main);
}
if(actions && UI::Actions::RendererTextures) {
renderer->reloadTextures(options.renderer.textures, options.renderer.mipMapLOD);
}
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");
auto pass = renderer->getPass();
pass.start();
reports.models_count = 0;
reports.tris_count = 0;
std::optional<geometry::Frustum> frustum;
if(options.culling) {
frustum = {camera.getFrustum()};
}
const auto offset = state.position.raw_as_long();
{ // Chunks
std::vector<std::pair<glm::mat4, buffer::Abstract *const>> models;
world.getContouring()->getModels(models, frustum, offset, options.voxel_density);
for (auto [model, buffer] : models) {
reports.models_count++;
reports.tris_count += buffer->draw(pass.setup(model));
}
}
{ // Entities
std::vector<std::pair<std::vector<glm::mat4>, buffer::Abstract *const>> models;
world.getEntitiesModels(models, frustum, offset, options.voxel_density);
lookProgram->useIt();
lookProgram->start(renderer);
for (auto [mats, buffer]: models) {
for(auto model: mats) {
reports.models_count++;
reports.tris_count += lookBuffer.draw(lookProgram->setup(renderer, model));
}
}
}
if(state.look_at.has_value()) { // Indicator
lookProgram->useIt();
lookProgram->start(renderer);
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 += lookBuffer.draw(lookProgram->setup(renderer, model));
}
renderer->postProcess();
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 lookProgram;
delete renderer;
// Close OpenGL window and terminate GLFW
glfwTerminate();
contouring::save(options.contouring_idx, state.contouring, options.contouring_data);
options.save();
return 0;
}