272 lines
12 KiB
C++
272 lines
12 KiB
C++
#include "UI.hpp"
|
|
|
|
#include <imgui.h>
|
|
#include "../state.hpp"
|
|
#include "../Window.hpp"
|
|
#include "../../core/world/materials.hpp"
|
|
|
|
using namespace render;
|
|
|
|
UI *UI::sInstance = nullptr;
|
|
|
|
constexpr auto UI_MARGIN = 5;
|
|
|
|
UI::UI() {
|
|
// Setup Dear ImGui context
|
|
IMGUI_CHECKVERSION();
|
|
ImGui::CreateContext();
|
|
ImGui::StyleColorsDark();
|
|
}
|
|
UI::~UI() {
|
|
ImGui::DestroyContext();
|
|
}
|
|
|
|
UI::Actions UI::draw(config::client::options &options, state::state &state, const state::reports &reports, intptr_t aim) {
|
|
auto actions = Actions::None;
|
|
ImGui::NewFrame();
|
|
|
|
const ImGuiIO &io = ImGui::GetIO();
|
|
|
|
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 *)aim, ImVec2(32, 32));
|
|
ImGui::End();
|
|
}
|
|
|
|
if (options.debugMenu.bar) {
|
|
ImGui::BeginMainMenuBar();
|
|
if (ImGui::BeginMenu("Debug")) {
|
|
ImGui::Checkbox("Render", &options.debugMenu.render);
|
|
ImGui::Checkbox("World", &options.debugMenu.world);
|
|
ImGui::Checkbox("Contouring", &options.debugMenu.contouring);
|
|
ImGui::Checkbox("Controls", &options.debugMenu.controls);
|
|
ImGui::EndMenu();
|
|
}
|
|
ImGui::Checkbox("Editor", &options.editor.visible);
|
|
|
|
if(ImGui::MenuItem("Close"))
|
|
options.debugMenu.bar = false;
|
|
ImGui::EndMainMenuBar();
|
|
}
|
|
|
|
if (options.debugMenu.render) {
|
|
ImGui::Begin("Debug: Render", &options.debugMenu.render, ImGuiWindowFlags_AlwaysAutoResize);
|
|
ImGui::Text("Tris: %ld (%ld models)", reports.tris_count, reports.models_count);
|
|
ImGui::Separator();
|
|
ImGui::Checkbox("Overlay", &options.overlay.visible);
|
|
if (ImGui::SliderInt("FPS", &options.window.targetFPS, Window::MIN_FPS-1, Window::MAX_FPS+1, options.window.targetFPS > Window::MIN_FPS ? (options.window.targetFPS < Window::MAX_FPS ? "%d" : "UNLIMITED") : "VSYNC")){
|
|
actions |= Actions::FPS;
|
|
}
|
|
|
|
ImGui::Text("Sampling %d (requires restart)", options.window.samples);
|
|
if (ImGui::Checkbox("Fullscreen", &options.window.fullscreen)){
|
|
actions |= Actions::FullScreen;
|
|
}
|
|
|
|
{
|
|
bool changeRenderer = false;
|
|
changeRenderer |= ImGui::Checkbox("PBR", &options.renderer.voxel.pbr);
|
|
ImGui::SameLine();
|
|
changeRenderer |= ImGui::Checkbox("Triplanar", &options.renderer.voxel.triplanar);
|
|
ImGui::SameLine();
|
|
changeRenderer |= ImGui::Checkbox("Stochastic", &options.renderer.voxel.stochastic);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("Hide textures tiling\nMay cause visible inconsistances on chunk borders");
|
|
|
|
changeRenderer |= ImGui::Checkbox("Geometry", &options.renderer.voxel.geometry);
|
|
ImGui::SameLine();
|
|
if(options.renderer.voxel.geometry) {
|
|
changeRenderer |= ImGui::Checkbox("Blend", &options.renderer.voxel.blend);
|
|
} else {
|
|
ImGui::TextDisabled("Blend");
|
|
}
|
|
|
|
changeRenderer |= ImGui::Checkbox("Curvature", &options.renderer.voxel.curvature);
|
|
ImGui::SameLine();
|
|
if(options.renderer.voxel.curvature) {
|
|
changeRenderer |= ImGui::Checkbox("Depth", &options.renderer.voxel.curv_depth);
|
|
if(ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("Planets may look way bigger than expected without it");
|
|
} else {
|
|
ImGui::TextDisabled("Depth");
|
|
}
|
|
|
|
changeRenderer |= ImGui::Checkbox("Fog", &options.renderer.voxel.fog);
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox("Skybox", &options.renderer.skybox);
|
|
if (changeRenderer) {
|
|
actions |= Actions::RendererSharders;
|
|
}
|
|
}
|
|
if (ImGui::ColorEdit3("Fog color", &options.renderer.clear_color[0])) {
|
|
actions |= Actions::ClearColor;
|
|
}
|
|
if (ImGui::Checkbox("Wireframe", &options.renderer.wireframe)) {
|
|
actions |= Actions::FillMode;
|
|
}
|
|
ImGui::Text("Textures '%s'", options.renderer.textures.c_str()); // MAYBE: select
|
|
if (ImGui::SliderFloat("LOD", &options.renderer.mipMapLOD, -1, 1) |
|
|
ImGui::SliderInt("Anisotropy", &options.renderer.anisotropy, 0, 8)) {
|
|
actions |= Actions::RendererTextures;
|
|
}
|
|
ImGui::End();
|
|
}
|
|
|
|
if (options.debugMenu.world) {
|
|
ImGui::Begin("Debug: World", &options.debugMenu.world, ImGuiWindowFlags_AlwaysAutoResize);
|
|
int load = options.world.loadDistance;
|
|
int keep = options.world.keepDistance;
|
|
if (ImGui::SliderInt("Load distance", &load, 1, options.world.keepDistance) |
|
|
ImGui::SliderInt("Keep distance", &keep, options.world.loadDistance + 1, 21)) {
|
|
options.world.loadDistance = load;
|
|
options.world.keepDistance = keep;
|
|
actions |= Actions::World;
|
|
}
|
|
if(ImGui::SliderInt("Voxel density", &options.voxel_density, 1, CHUNK_LENGTH * REGION_LENGTH)) {
|
|
options.voxel_density = pow(2, ceil(log(options.voxel_density) / log(2)));
|
|
}
|
|
ImGui::End();
|
|
}
|
|
|
|
if (options.debugMenu.contouring) {
|
|
ImGui::Begin("Debug: Contouring", &options.debugMenu.contouring, ImGuiWindowFlags_AlwaysAutoResize);
|
|
ImGui::SliderInt("Culling", &options.culling, -1, 10, options.culling > 0 ? "Occlusion %d" : (options.culling < 0 ? "None" : "Frustum"));
|
|
state.contouring->onGui();
|
|
ImGui::End();
|
|
}
|
|
|
|
{
|
|
const auto farRange = state.contouring->getFarRange();
|
|
if (options.debugMenu.controls) {
|
|
ImGui::Begin("Debug: Controls", &options.debugMenu.controls, ImGuiWindowFlags_AlwaysAutoResize);
|
|
const auto p = state.position.as_voxel(options.voxel_density);
|
|
ImGui::Text("Position: (%lld, %lld, %lld)", p.x, p.y, p.z);
|
|
ImGui::Separator();
|
|
{
|
|
if (ImGui::SliderFloat("Move speed", &options.control.speed, 0.1, 50) |
|
|
ImGui::SliderInt("Sensibility", &options.control.sensibility, 1, 100, "%d%%")) {
|
|
actions |= Actions::Control;
|
|
}
|
|
ImGui::Checkbox("Collide", &options.control.collide);
|
|
}
|
|
ImGui::Separator();
|
|
{
|
|
bool changePerspective = false;
|
|
changePerspective |= ImGui::SliderAngle("FoV", &options.camera.fov, 30, 110);
|
|
changePerspective |= ImGui::SliderFloat("Near", &options.camera.near, 0.01, 10);
|
|
changePerspective |= ImGui::SliderFloat("Far", &options.camera.far, farRange.first / options.voxel_density, farRange.second / options.voxel_density);
|
|
if(changePerspective) {
|
|
actions |= Actions::Camera;
|
|
}
|
|
}
|
|
ImGui::End();
|
|
}
|
|
const auto far = std::clamp(options.camera.far, farRange.first / options.voxel_density, farRange.second / options.voxel_density);
|
|
if(far != options.camera.far) {
|
|
options.camera.far = far;
|
|
actions |= Actions::Camera;
|
|
}
|
|
}
|
|
|
|
if (options.editor.visible) {
|
|
ImGui::Begin("Editor", &options.editor.visible, ImGuiWindowFlags_AlwaysAutoResize);
|
|
if (state.look_at.has_value()) {
|
|
const auto &look = state.look_at.value();
|
|
ImGui::Text("Look at: (%ld: %lld, %lld, %lld) (%s, %.1f)", look.pos.first.index, look.pos.second.x, look.pos.second.y, look.pos.second.z,
|
|
world::materials::names[look.value.material()].c_str(), look.value.density_ratio());
|
|
const auto w_pos = look.pos.second + look.offset;
|
|
ImGui::Text("(%.3f, %.3f, %.3f)", w_pos.x * 1. / options.voxel_density, w_pos.y * 1. / options.voxel_density, w_pos.z * 1. / options.voxel_density);
|
|
} else {
|
|
ImGui::Text("Look at: none");
|
|
}
|
|
ImGui::Separator();
|
|
if (ImGui::BeginCombo("Material", world::materials::names[options.editor.tool.material].c_str())) {
|
|
for (size_t i = 0; i < world::materials::names.size(); i++) {
|
|
if (!world::materials::invisibility[i]) {
|
|
const bool is_selected = (options.editor.tool.material == i);
|
|
if (ImGui::Selectable(world::materials::names[i].c_str(), is_selected))
|
|
options.editor.tool.material = i;
|
|
if (is_selected)
|
|
ImGui::SetItemDefaultFocus();
|
|
}
|
|
}
|
|
ImGui::EndCombo();
|
|
}
|
|
ImGui::SliderInt("Radius", &options.editor.tool.radius, 0, 10);
|
|
ImGui::Checkbox("Empty air", &options.editor.tool.emptyAir);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("Is cleaned area breathable");
|
|
ImGui::End();
|
|
}
|
|
|
|
/*if (show_console) {
|
|
ImGui::SetNextWindowPos(ImVec2(UI_MARGIN, 500), ImGuiCond_FirstUseEver);
|
|
ImGui::SetNextWindowSize(ImVec2(200, 100), ImGuiCond_FirstUseEver);
|
|
ImGui::Begin("Console", &show_console, ImGuiWindowFlags_MenuBar);
|
|
ImGui::BeginMenuBar();
|
|
ImGui::MenuItem("Auto-scrool", NULL, &console_scrool);
|
|
ImGui::EndMenuBar();
|
|
|
|
// TODO: text
|
|
ImGui::Separator();
|
|
|
|
// Command-line
|
|
bool reclaim_focus = false;
|
|
// TODO: completion callback
|
|
if (ImGui::InputText("Input", console_buffer, IM_ARRAYSIZE(console_buffer), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory)) {
|
|
char *s = console_buffer;
|
|
//Strtrim(s);
|
|
//if (s[0])
|
|
// ExecCommand(s);
|
|
strcpy(s, "");
|
|
reclaim_focus = true;
|
|
}
|
|
|
|
// Auto-focus on window apparition
|
|
ImGui::SetItemDefaultFocus();
|
|
if (reclaim_focus)
|
|
ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
|
|
|
|
ImGui::End();
|
|
}*/
|
|
|
|
if (options.overlay.visible) {
|
|
if (options.overlay.corner != -1) {
|
|
ImVec2 window_pos = ImVec2((options.overlay.corner & 1) ? io.DisplaySize.x - UI_MARGIN : UI_MARGIN, (options.overlay.corner & 2) ? io.DisplaySize.y - UI_MARGIN : UI_MARGIN);
|
|
ImVec2 window_pos_pivot = ImVec2((options.overlay.corner & 1) ? 1.0f : 0.0f, (options.overlay.corner & 2) ? 1.0f : 0.0f);
|
|
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
|
|
}
|
|
ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
|
|
ImGui::Begin("Overlay", &options.overlay.visible, (options.overlay.corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav);
|
|
ImGui::Text("%.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
|
ImGui::Text("%ld tris(%ld models)", reports.tris_count, reports.models_count);
|
|
if (ImGui::BeginPopupContextWindow()) {
|
|
if (ImGui::MenuItem("Custom", NULL, options.overlay.corner == -1))
|
|
options.overlay.corner = -1;
|
|
if (ImGui::MenuItem("Top-left", NULL, options.overlay.corner == 0))
|
|
options.overlay.corner = 0;
|
|
if (ImGui::MenuItem("Top-right", NULL, options.overlay.corner == 1))
|
|
options.overlay.corner = 1;
|
|
if (ImGui::MenuItem("Bottom-left", NULL, options.overlay.corner == 2))
|
|
options.overlay.corner = 2;
|
|
if (ImGui::MenuItem("Bottom-right", NULL, options.overlay.corner == 3))
|
|
options.overlay.corner = 3;
|
|
if (options.overlay.visible && ImGui::MenuItem("Close"))
|
|
options.overlay.visible = false;
|
|
ImGui::EndPopup();
|
|
}
|
|
ImGui::End();
|
|
}
|
|
ImGui::Render();
|
|
return actions;
|
|
}
|
|
|
|
bool UI::IsFocus() {
|
|
return ImGui::IsAnyItemActive();
|
|
}
|
|
|
|
void UI::Unload() {
|
|
delete sInstance;
|
|
sInstance = nullptr;
|
|
} |