Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/WolfireGames/overgrowth.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Source/GUI/dimgui/settings_screen.cpp')
-rw-r--r--Source/GUI/dimgui/settings_screen.cpp1258
1 files changed, 1258 insertions, 0 deletions
diff --git a/Source/GUI/dimgui/settings_screen.cpp b/Source/GUI/dimgui/settings_screen.cpp
new file mode 100644
index 00000000..91bce3e4
--- /dev/null
+++ b/Source/GUI/dimgui/settings_screen.cpp
@@ -0,0 +1,1258 @@
+//-----------------------------------------------------------------------------
+// Name: settings_screen.cpp
+// Developer: Wolfire Games LLC
+// Description:
+// License: Read below
+//-----------------------------------------------------------------------------
+//
+//
+// Copyright 2022 Wolfire Games LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-----------------------------------------------------------------------------
+#include "settings_screen.h"
+
+#include <Graphics/graphics.h>
+#include <Graphics/textures.h>
+#include <Graphics/sky.h>
+#include <Graphics/shaders.h>
+#include <Graphics/camera.h>
+#include <Graphics/pxdebugdraw.h>
+
+#include <Internal/config.h>
+#include <Internal/timer.h>
+#include <Internal/filesystem.h>
+#include <Internal/common.h>
+
+#include <Asset/Asset/animation.h>
+#include <Asset/Asset/levelinfo.h>
+
+#include <Main/scenegraph.h>
+#include <Main/engine.h>
+
+#include <Scripting/angelscript/ascrashdump.h>
+#include <Scripting/angelscript/ascontext.h>
+
+#include <Logging/logdata.h>
+#include <UserInput/input.h>
+#include <Editors/map_editor.h>
+#include <Sound/sound.h>
+#include <Math/vec3math.h>
+#include <UserInput/keyTranslator.h>
+#include <Compat/fileio.h>
+
+#include <SDL_keycode.h>
+
+#include <imgui.h>
+#include <imgui_internal.h>
+
+#include <sstream>
+
+extern float imgui_scale;
+
+extern Config config;
+extern AnimationConfig animation_config;
+extern bool g_simple_shadows;
+extern bool g_level_shadows;
+extern bool g_simple_water;
+extern bool g_disable_fog;
+extern bool g_draw_vr;
+extern bool g_albedo_only;
+extern bool g_no_reflection_capture;
+extern bool g_no_detailmaps;
+extern bool g_no_decals;
+extern bool g_no_decal_elements;
+extern bool g_single_pass_shadow_cascade;
+extern bool g_perform_occlusion_query;
+extern bool g_gamma_correct_final_output;
+extern bool g_attrib_envobj_intancing_support;
+extern bool g_attrib_envobj_intancing_enabled;
+extern bool g_ubo_batch_multiplier_force_1x;
+extern Timer game_timer;
+
+const vec3 kRedBloodColor(0.4f,0.0f,0.0f);
+const vec3 kGreenBloodColor(0.0f,0.4f,0.0f);
+const vec3 kCyanBloodColor(0.0f,0.4f,0.4f);
+const vec3 kBlackBloodColor(0.1f,0.1f,0.1f);
+
+static void UpdateFullscreenMode(FullscreenMode::Mode val) {
+ config.GetRef("fullscreen") = static_cast<int>(val);
+ Graphics::Instance()->SetFullscreen(static_cast<FullscreenMode::Mode>(config["fullscreen"].toNumber<int>()));
+}
+
+static void UpdateMultisampleSetting(int val){
+ config.GetRef("multisample") = val;
+ Graphics::Instance()->SetFSAA(config["multisample"].toNumber<int>());
+}
+
+static void UpdateAnisotropy(int val){
+ config.GetRef("anisotropy") = val;
+ if(config["anisotropy"].toNumber<int>() != Graphics::Instance()->config_.anisotropy()){
+ Graphics::Instance()->SetAnisotropy((float)config["anisotropy"].toNumber<int>());
+ Textures::Instance()->ApplyAnisotropy();
+ }
+}
+
+static void UpdateSimpleFog(bool val){
+ config.GetRef("simple_fog") = val;
+ Graphics::Instance()->SetSimpleFog(val);
+}
+
+static void UpdateDepthOfField(bool val){
+ config.GetRef("depth_of_field") = val;
+ Graphics::Instance()->SetDepthOfField(val);
+}
+
+static void UpdateDepthOfFieldReduced(bool val){
+ config.GetRef("depth_of_field_reduced") = val;
+ Graphics::Instance()->SetDepthOfFieldReduced(val);
+}
+
+static void UpdateDetailObjects(bool val){
+ config.GetRef("detail_objects") = val;
+ Graphics::Instance()->SetDetailObjects(val);
+}
+
+static void UpdateDetailObjectDecals(bool val){
+ config.GetRef("detail_object_decals") = val;
+ Graphics::Instance()->SetDetailObjectDecals(val);
+}
+
+static void UpdateDetailObjectLowres(bool val){
+ config.GetRef("detail_object_lowres") = val;
+ Graphics::Instance()->SetDetailObjectLowres(val);
+}
+
+static void UpdateDetailObjectShadows(bool val){
+ config.GetRef("detail_object_disable_shadows") = !val;
+ Graphics::Instance()->SetDetailObjectShadows(val);
+}
+
+static void UpdateDetailObjectsReduced(bool val){
+ config.GetRef("detail_objects_reduced") = val;
+ Graphics::Instance()->SetDetailObjectsReduced(val);
+}
+
+static void UpdateSimpleShadows(bool val){
+ config.GetRef("simple_shadows") = val;
+ Graphics::Instance()->setSimpleShadows(val);
+}
+
+static void UpdateSimpleWater(bool val) {
+ config.GetRef("simple_water") = val;
+ Graphics::Instance()->setSimpleWater(config["simple_water"].toNumber<bool>());
+}
+
+static void UpdateParticleFieldSimple(bool val){
+ config.GetRef("particle_field_simple") = val;
+ Graphics::Instance()->SetParticleFieldSimple(val);
+}
+
+static void UpdateAttribEnvObjInstancing(bool val){
+ config.GetRef("attrib_envobj_instancing") = val;
+ Graphics::Instance()->setAttribEnvObjInstancing(val);
+}
+
+static void UpdateTetMeshLighting(SceneGraph* scenegraph, bool val){
+ if(config["tet_mesh_lighting"] != val){
+ config.GetRef("tet_mesh_lighting") = val;
+ }
+ if(scenegraph){
+ scenegraph->light_probe_collection.probe_lighting_enabled = val;
+ }
+}
+
+static void UpdateLightVolumes(SceneGraph* scenegraph, bool val){
+ if(config["light_volume_lighting"] != val){
+ config.GetRef("light_volume_lighting") = val;
+ }
+ if(scenegraph){
+ scenegraph->light_probe_collection.light_volume_enabled = val;
+ }
+}
+
+static void UpdateMotionBlur(float val) {
+ config.GetRef("motion_blur_amount") = val;
+ Graphics::Instance()->config_.motion_blur_amount_ = val;
+}
+
+static void UpdateNoReflectionCapture(bool val ) {
+ LOGI << "Setting no reflection capture to " << val << std::endl;
+ g_no_reflection_capture = val;
+ config.GetRef("no_reflection_capture") = val;
+}
+
+static void AddResolution(std::vector<Resolution> &resolutions, int w, int h){
+ if(w < 640 || h < 480){
+ return;
+ }
+ // Check if resolution is already there
+ int num_res = resolutions.size();
+ for(int i=0; i<num_res; ++i){
+ if(resolutions[i].w == w && resolutions[i].h == h){
+ return;
+ }
+ }
+ // Add resolution
+ resolutions.push_back(Resolution(w,h));
+}
+
+static void UpdateEnableLayeredSoundtrackLimiter(bool val) {
+ Engine::Instance()->GetSound()->EnableLayeredSoundtrackLimiter(val);
+ config.GetRef("use_soundtrack_limiter") = val;
+}
+
+void AddResolutionDropdownImGui() {
+ std::vector<Resolution> resolutions = config.GetPossibleResolutions();
+ // Add current resolution
+ const int *render_dims = Graphics::Instance()->render_dims;
+ AddResolution(resolutions, render_dims[0], render_dims[1]);
+ // Sort resolutions
+ std::sort(resolutions.begin(), resolutions.end(), ResolutionCompare());
+ // Add dropdown list
+ static int item = 0;
+ for(int i=0, len=resolutions.size(); i<len; ++i){
+ if(render_dims[0] == resolutions[i].w && render_dims[1] == resolutions[i].h){
+ item = i+1;
+ }
+ }
+ const int kMaxResolutions = 30;
+ const int kMaxResolutionLen = 30;
+ const int kMaxStrLen = kMaxResolutions*kMaxResolutionLen;
+ char resolution_items[kMaxStrLen];
+ char temp[kMaxResolutionLen];
+ int num_resolutions = min((int)resolutions.size(), kMaxResolutions);
+ int index = 0;
+ FormatString(temp, kMaxResolutionLen, "Custom");
+ for(int j=0,len=strlen(temp); j<len; ++j){
+ resolution_items[index] = temp[j];
+ ++index;
+ }
+ resolution_items[index] = '\0';
+ ++index;
+ for(int i=0; i<num_resolutions; ++i){
+ FormatString(temp, kMaxResolutionLen, "%dx%d", resolutions[i].w, resolutions[i].h);
+ for(int j=0,len=strlen(temp); j<len; ++j){
+ resolution_items[index] = temp[j];
+ ++index;
+ }
+ resolution_items[index] = '\0';
+ ++index;
+ }
+ resolution_items[index] = '\0';
+ ++index;
+ static int custom_res[2];
+ int set_new_res[] = {-1,-1};
+ if(ImGui::Combo("Resolution", &item, resolution_items)){
+ if(item == 0){
+ ImGui::OpenPopup("custom_resolution");
+ custom_res[0] = render_dims[0];
+ custom_res[1] = render_dims[1];
+ } else {
+ set_new_res[0] = resolutions[item-1].w;
+ set_new_res[1] = resolutions[item-1].h;
+ }
+ }
+ if (ImGui::BeginPopup("custom_resolution")) {
+ ImGui::Text("Set custom resolution:");
+ ImGui::InputInt("Width", &custom_res[0], 0);
+ ImGui::InputInt("Height", &custom_res[1], 0);
+ if(ImGui::Button("Apply")){
+ set_new_res[0] = custom_res[0];
+ set_new_res[1] = custom_res[1];
+ ImGui::CloseCurrentPopup();
+ }
+ ImGui::EndPopup();
+ }
+ if(set_new_res[0] != -1){
+ set_new_res[0] = max(set_new_res[0], 640);
+ set_new_res[1] = max(set_new_res[1], 480);
+ config.GetRef("screenwidth") = set_new_res[0];
+ config.GetRef("screenheight") = set_new_res[1];
+ Graphics::Instance()->SetResolution(set_new_res[0], set_new_res[1], false);
+ }
+}
+
+static void SetGameSpeed(float val, bool hard) {
+ Engine::Instance()->SetGameSpeed(val, hard);
+}
+
+void DrawSettingsImGui(SceneGraph* scenegraph, ImGuiSettingsType type){
+ Graphics* graphics = Graphics::Instance();
+ static Config* global_settings = Config::GetPresets();
+
+ if (ImGui::BeginMenu("Graphics")) {
+ bool checkbox_val;
+ int dropdown_item;
+
+ // Determine if we match any of the global_settings presets
+ dropdown_item = 0;
+ for(int i=0; i<3; ++i){
+ Config::Map& map = global_settings[i].map_;
+ for(Config::Map::iterator iter = map.begin(); iter != map.end(); ++iter ){
+ if(config.GetRef(iter->first) != iter->second.data){
+ dropdown_item = i + 1;
+ break;
+ }
+ }
+ if(dropdown_item == i){
+ break;
+ }
+ }
+ if(dropdown_item == 3){
+ dropdown_item = 0;
+ } else {
+ ++dropdown_item;
+ }
+
+ if(ImGui::Combo("Overall", &dropdown_item, "Custom\0Low\0Medium\0High\0\0")){
+ if(dropdown_item != 0){
+ int curr_global_setting = dropdown_item-1;
+ Config::Map& map = global_settings[curr_global_setting].map_;
+ for(Config::Map::iterator iter = map.begin(); iter != map.end(); ++iter ){
+ config.GetRef(iter->first) = iter->second.data;
+ }
+ UpdateMultisampleSetting(config.GetRef("multisample").toNumber<int>());
+ UpdateAnisotropy(config.GetRef("anisotropy").toNumber<int>());
+ UpdateSimpleFog(config.GetRef("simple_fog").toNumber<bool>());
+ UpdateDepthOfField(config.GetRef("depth_of_field").toNumber<bool>());
+ UpdateDepthOfFieldReduced(config.GetRef("depth_of_field_reduced").toNumber<bool>());
+ UpdateDetailObjects(config.GetRef("detail_objects").toNumber<bool>());
+ UpdateDetailObjectDecals(config.GetRef("detail_object_decals").toNumber<bool>());
+ UpdateDetailObjectLowres(config.GetRef("detail_object_lowres").toNumber<bool>());
+ UpdateDetailObjectShadows(!config.GetRef("detail_object_disable_shadows").toNumber<bool>());
+ UpdateSimpleShadows(config.GetRef("simple_shadows").toNumber<bool>());
+ UpdateSimpleWater(config.GetRef("simple_water").toNumber<bool>());
+ UpdateAttribEnvObjInstancing(config.GetRef("attrib_envobj_instancing").toNumber<bool>());
+ UpdateTetMeshLighting(scenegraph, config.GetRef("tet_mesh_lighting").toNumber<bool>());
+ UpdateMotionBlur(config.GetRef("motion_blur_amount").toNumber<float>());
+ UpdateNoReflectionCapture(config.GetRef("no_reflection_capture").toBool());
+ }
+ }
+
+ AddResolutionDropdownImGui();
+
+ dropdown_item = static_cast<int>(graphics->config_.full_screen());
+ const char* fullscreen_choices[] = {
+ "Windowed",
+ "Fullscreen",
+ "Windowed borderless",
+ "Fullscreen borderless"
+ };
+ if (ImGui::Combo("Fullscreen mode", &dropdown_item, fullscreen_choices, IM_ARRAYSIZE(fullscreen_choices))){
+ UpdateFullscreenMode(static_cast<FullscreenMode::Mode>(dropdown_item));
+ }
+
+ switch(graphics->config_.FSAA_samples()) {
+ case 2: dropdown_item=1; break;
+ case 4: dropdown_item=2; break;
+ case 8: dropdown_item=3; break;
+ default: dropdown_item=0; break;
+ }
+ const char* aa_choices[] = {
+ "None",
+ "2x",
+ "4x",
+ "8x"
+ };
+ if(ImGui::Combo("Anti-aliasing", &dropdown_item, aa_choices, IM_ARRAYSIZE(aa_choices))){
+ switch(dropdown_item){
+ case 0:
+ UpdateMultisampleSetting(1); break;
+ case 1:
+ UpdateMultisampleSetting(2); break;
+ case 2:
+ UpdateMultisampleSetting(4); break;
+ case 3:
+ UpdateMultisampleSetting(8); break;
+ }
+ }
+
+ switch(config["anisotropy"].toNumber<int>()) {
+ case 2: dropdown_item=1; break;
+ case 4: dropdown_item=2; break;
+ case 8: dropdown_item=3; break;
+ default: dropdown_item=0; break;
+ }
+ if(ImGui::Combo("Anisotropy", &dropdown_item, aa_choices, IM_ARRAYSIZE(aa_choices))){
+ switch(dropdown_item){
+ case 0:
+ UpdateAnisotropy(1); break;
+ case 1:
+ UpdateAnisotropy(2); break;
+ case 2:
+ UpdateAnisotropy(4); break;
+ case 3:
+ UpdateAnisotropy(8); break;
+ }
+ }
+
+ dropdown_item = config.GetRef("texture_reduce").toNumber<int>();
+ const char* texture_detail_choices[] = {
+ "Full",
+ "1/2",
+ "1/4",
+ "1/8"
+ };
+ if(ImGui::Combo("Texture Detail (requires restart)", &dropdown_item, texture_detail_choices, IM_ARRAYSIZE(texture_detail_choices))){
+ config.GetRef("texture_reduce") = dropdown_item;
+ }
+
+
+ dropdown_item = config.GetRef("imgui_scale").toNumber<int>();
+ const char* imgui_scale_choices[] = {
+ "100%",
+ "125%",
+ "150%",
+ "175%",
+ "200%",
+ "225%",
+ "250%",
+ "275%",
+ "300%"
+ };
+ if (ImGui::Combo("Debug Menu Scale", &dropdown_item, imgui_scale_choices, IM_ARRAYSIZE(imgui_scale_choices))) {
+ config.GetRef("imgui_scale") = dropdown_item;
+ imgui_scale = 1.0f + static_cast<float>(dropdown_item) / 4.0f;
+ }
+
+
+ checkbox_val = graphics->config_.vSync();
+ if(ImGui::Checkbox("VSync", &checkbox_val)){
+ config.GetRef("vsync") = checkbox_val;
+ graphics->SetVsync(checkbox_val);
+ }
+
+ checkbox_val = graphics->config_.limit_fps_in_game();
+ if(ImGui::Checkbox("Limit FPS In Game", &checkbox_val)){
+ config.GetRef("limit_fps_in_game") = checkbox_val;
+ graphics->SetLimitFpsInGame(checkbox_val);
+ }
+
+ {
+ int max_fps_val = graphics->config_.max_frame_rate();
+ if(ImGui::DragInt("Max FPS", &max_fps_val, 5.0f, 15, 300)){
+ if(max_fps_val < 15){
+ max_fps_val = 15;
+ }
+ if(max_fps_val > 500){
+ max_fps_val = 500;
+ }
+ config.GetRef("max_frame_rate") = max_fps_val;
+ graphics->SetMaxFrameRate(max_fps_val);
+ }
+ }
+
+ checkbox_val = g_simple_shadows;
+ if(ImGui::Checkbox("Simple shadows", &checkbox_val)){
+ UpdateSimpleShadows(checkbox_val);
+ }
+
+ checkbox_val = config["simple_fog"].toNumber<bool>();
+ if(ImGui::Checkbox("Simple fog", &checkbox_val)){
+ UpdateSimpleFog(checkbox_val);
+ }
+
+ checkbox_val = config["simple_water"].toNumber<bool>();
+ if(ImGui::Checkbox("Simple Water", &checkbox_val)){
+ UpdateSimpleWater(checkbox_val);
+ }
+
+ bool depth_of_field = config["depth_of_field"].toNumber<bool>();
+ if(ImGui::Checkbox("Depth of field", &depth_of_field)){
+ UpdateDepthOfField(depth_of_field);
+ }
+
+ ImGui::BeginDisabled(!depth_of_field);
+ checkbox_val = config["depth_of_field_reduced"].toNumber<bool>();
+ if(ImGui::Checkbox("Depth of field reduce amount", &checkbox_val)){
+ UpdateDepthOfFieldReduced(checkbox_val);
+ }
+ ImGui::EndDisabled();
+
+ ImGui::BeginDisabled(!g_attrib_envobj_intancing_support);
+ checkbox_val = g_attrib_envobj_intancing_enabled;
+ if(ImGui::Checkbox("Vertex Attrib Instancing", &checkbox_val)){
+ UpdateAttribEnvObjInstancing(checkbox_val);
+ }
+ ImGui::EndDisabled();
+
+ checkbox_val = config.GetRef("tet_mesh_lighting").toNumber<bool>();
+ if(ImGui::Checkbox("Use tet mesh lighting", &checkbox_val)){
+ UpdateTetMeshLighting(scenegraph, checkbox_val);
+ }
+
+ checkbox_val = config["light_volume_lighting"].toNumber<bool>();
+ if(ImGui::Checkbox("Use ambient light volumes", &checkbox_val)){
+ UpdateLightVolumes(scenegraph, checkbox_val);
+ }
+
+ bool detail_objects = graphics->config_.detail_objects();
+ if(ImGui::Checkbox("Detail objects", &detail_objects)){
+ UpdateDetailObjects(detail_objects);
+ }
+
+ ImGui::BeginDisabled(!detail_objects);
+ checkbox_val = config["detail_objects_reduced"].toNumber<bool>();
+ if(ImGui::Checkbox("Detail objects reduce count", &checkbox_val)) {
+ UpdateDetailObjectsReduced(checkbox_val);
+ }
+
+ checkbox_val = config["detail_object_decals"].toNumber<bool>();
+ if(ImGui::Checkbox("Detail object decals", &checkbox_val)) {
+ UpdateDetailObjectDecals(checkbox_val);
+ }
+
+ checkbox_val = config["detail_object_lowres"].toNumber<bool>();
+ if(ImGui::Checkbox("Lowres detail objects (needs restart)", &checkbox_val)) {
+ UpdateDetailObjectLowres(checkbox_val);
+ }
+
+ checkbox_val = !config["detail_object_disable_shadows"].toNumber<bool>();
+ if(ImGui::Checkbox("Detail object shadows", &checkbox_val)) {
+ UpdateDetailObjectShadows(checkbox_val);
+ }
+ ImGui::EndDisabled();
+
+ checkbox_val = config.GetRef("particle_field").toNumber<bool>();
+ if(ImGui::Checkbox("GPU particle field", &checkbox_val)){
+ config.GetRef("particle_field") = checkbox_val;
+ }
+
+ checkbox_val = config.GetRef("particle_field_simple").toNumber<bool>();
+ if(ImGui::Checkbox("GPU particle field (simplify)", &checkbox_val)){
+ config.GetRef("particle_field_simple") = checkbox_val;
+ }
+
+ checkbox_val = config.GetRef("custom_level_shaders").toNumber<bool>();
+ if(ImGui::Checkbox("Custom level shaders", &checkbox_val)){
+ config.GetRef("custom_level_shaders") = checkbox_val;
+ }
+
+ checkbox_val = config["no_reflection_capture"].toNumber<bool>();
+ if(ImGui::Checkbox("No reflection capture", &checkbox_val)){
+ UpdateNoReflectionCapture(checkbox_val);
+ }
+
+ int slider_val = (int)( graphics->config_.motion_blur_amount_ * 100.0f + 0.5f );
+ if(ImGui::SliderInt("Motion blur", &slider_val, 0, 100, "%.0f%%")){
+ UpdateMotionBlur(slider_val * 0.01f);
+ }
+
+ {
+ int slider_val = (int)( config.GetRef("brightness").toNumber<float>() * 100.0f + 0.5f );
+ if(ImGui::SliderInt("Brightness", &slider_val, 10, 200, "%.0f%%")){
+ config.GetRef("brightness") = slider_val * 0.01f;
+ }
+ }
+
+ ImGui::EndMenu();
+ }
+ if (ImGui::BeginMenu("Audio")) {
+ int slider_val = (int)(config.GetRef("music_volume").toNumber<float>() * 100.0f + 0.5f);
+ if(ImGui::SliderInt("Music Volume", &slider_val, 0, 100, "%.0f%%")){
+ float val = slider_val / 100.0f;
+ config.GetRef("music_volume") = val;
+ Engine::Instance()->GetSound()->SetMusicVolume(val);
+ }
+
+ slider_val = (int)(config.GetRef("master_volume").toNumber<float>() * 100.0f + 0.5f);
+ if(ImGui::SliderInt("Master Volume", &slider_val, 0, 100, "%.0f%%")){
+ float val = slider_val / 100.0f;
+ config.GetRef("master_volume") = val;
+ Engine::Instance()->GetSound()->SetMasterVolume(val);
+ }
+
+ static int device_selection = -1;
+ std::vector<std::string> available_devices = Engine::Instance()->GetSound()->GetAvailableDevices();
+ if( device_selection == -1 ) {
+ for( unsigned i = 0; i < available_devices.size(); i++ ) {
+ if( strmtch( available_devices[i], config["preferred_audio_device"].str() ) ) {
+ device_selection = i;
+ }
+ }
+ }
+ std::string used_device = Engine::Instance()->GetSound()->GetUsedDevice();
+ const char* devices[16];
+ int audio_device_count = 0;
+ for( unsigned i = 0; i < 16 && i < available_devices.size(); i++ ) {
+ devices[i] = available_devices[i].c_str();
+ if( device_selection == -1 ) {
+ if( strmtch(used_device, available_devices[i]) ) {
+ device_selection = i;
+ }
+ }
+ audio_device_count++;
+ }
+ if( device_selection == -1 ) {
+ device_selection = 0;
+ }
+ ImGui::Text("Used Device: %s", used_device.c_str());
+ ImGui::Text("You will need to restart to apply new audio device usage.");
+ if(ImGui::Combo("Preferred Audio Device", &device_selection, devices, audio_device_count)) {
+ if( device_selection < audio_device_count ) {
+ LOGI << "Setting new preferred audio device: " << devices[device_selection] << std::endl;
+ config.GetRef("preferred_audio_device") = devices[device_selection];
+ }
+ }
+ ImGui::EndMenu();
+ }
+ if (ImGui::BeginMenu("Game")) {
+ int dropdown_val;
+ dropdown_val = 2 - config.GetRef("blood").toNumber<int>();
+ if(ImGui::Combo("Blood amount", &dropdown_val, "Full\0No dripping\0None\0\0")){
+ int val = 2 -dropdown_val;
+ config.GetRef("blood") = val;
+ Graphics::Instance()->config_.SetBlood(val);
+ }
+
+ dropdown_val = 0;
+ const float kBloodColorThreshold = 0.01f;
+ vec3 blood_color = GraphicsConfig::BloodColorFromString(config["blood_color"].str());
+ if(distance_squared(blood_color, kGreenBloodColor) < kBloodColorThreshold){
+ dropdown_val = 1;
+ } else if(distance_squared(blood_color, kCyanBloodColor) < kBloodColorThreshold){
+ dropdown_val = 2;
+ } else if(distance_squared(blood_color, kBlackBloodColor) < kBloodColorThreshold){
+ dropdown_val = 3;
+ }
+ if(ImGui::Combo("Blood color", &dropdown_val, "Red\0Green\0Cyan\0Black\0\0")){
+ vec3 col;
+ switch(dropdown_val){
+ case 0: col = kRedBloodColor; break;
+ case 1: col = kGreenBloodColor; break;
+ case 2: col = kCyanBloodColor; break;
+ case 3: col = kBlackBloodColor; break;
+ }
+ std::ostringstream oss;
+ oss << col[0] << " " << col[1] << " " << col[2];
+ config.GetRef("blood_color") = oss.str();
+ Graphics::Instance()->config_.SetBloodColor(col);
+ }
+
+ bool checkbox_val = config["split_screen"].toNumber<bool>();
+ if(ImGui::Checkbox("Split screen", &checkbox_val)){
+ config.GetRef("split_screen") = checkbox_val;
+ Graphics::Instance()->config_.SetSplitScreen(checkbox_val);
+ }
+
+ bool tutorials = config["tutorials"].toBool();
+ if(ImGui::Checkbox("Tutorials", &tutorials)) {
+ config.GetRef("tutorials") = tutorials;
+ }
+
+ checkbox_val = config["auto_ledge_grab"].toNumber<bool>();
+ if(ImGui::Checkbox("Automatic ledge grab", &checkbox_val)){
+ config.GetRef("auto_ledge_grab") = checkbox_val;
+ }
+
+ std::vector<std::string> diff_presets = config.GetDifficultyPresets();
+ const char* custom_fallback = "Custom";
+ std::vector<const char*> diff_presets_c;
+
+ std::string diff_current = config.GetClosestDifficulty();
+
+ int dropdown_item = -1;
+
+ for( size_t i = 0; i < diff_presets.size(); i++ ) {
+ if( diff_presets[i] == diff_current ) {
+ dropdown_item = i;
+ }
+ diff_presets_c.push_back(diff_presets[i].c_str());
+ }
+
+ if(dropdown_item == -1) {
+ diff_presets_c.push_back(custom_fallback);
+ dropdown_item = diff_presets_c.size()-1;
+ }
+
+ if(ImGui::Combo("Difficulty Preset", &dropdown_item, &diff_presets_c[0], diff_presets.size())){
+ config.SetDifficultyPreset(diff_presets[dropdown_item]);
+ config.ReloadDynamicSettings();
+ }
+
+ float global_time_scale_mult = config["global_time_scale_mult"].toNumber<float>();
+ if(ImGui::SliderFloat("Game Speed", &global_time_scale_mult, 0.5f, 1.0f)){
+ SetGameSpeed(global_time_scale_mult, true);
+ }
+
+ float game_difficulty = config["game_difficulty"].toNumber<float>();
+ if(ImGui::SliderFloat("Game Difficulty", &game_difficulty, 0.0f, 1.0f)){
+ config.GetRef("game_difficulty") = game_difficulty;
+ }
+
+ ImGui::EndMenu();
+ }
+ if (ImGui::BeginMenu("Controls")) {
+ int slider_val;
+ slider_val = (int)(config["mouse_sensitivity"].toNumber<float>()*40.0f + 0.5f);
+ if(ImGui::SliderInt("Mouse sensitivity", &slider_val, 0, 100, "%.0f%%")){
+ float val = slider_val / 40.0f;
+ config.GetRef("mouse_sensitivity") = val;
+ Input::Instance()->SetMouseSensitivity(val);
+ }
+
+ bool checkbox_val;
+ checkbox_val = config["invert_x_mouse_look"].toNumber<bool>();
+ if(ImGui::Checkbox("Invert mouse X", &checkbox_val)){
+ config.GetRef("invert_x_mouse_look") = checkbox_val;
+ Input::Instance()->SetInvertXMouseLook(checkbox_val);
+ }
+
+ checkbox_val = config["invert_y_mouse_look"].toNumber<bool>();
+ if(ImGui::Checkbox("Invert mouse Y", &checkbox_val)){
+ config.GetRef("invert_y_mouse_look") = checkbox_val;
+ Input::Instance()->SetInvertYMouseLook(checkbox_val);
+ }
+
+ checkbox_val = config["use_raw_input"].toNumber<bool>();
+ if(ImGui::Checkbox("Raw mouse input", &checkbox_val)){
+ config.GetRef("use_raw_input") = checkbox_val;
+ Input::Instance()->UseRawInput(checkbox_val);
+ }
+
+ checkbox_val = config["auto_camera"].toNumber<bool>();
+ if(ImGui::Checkbox("Automatic camera", &checkbox_val)){
+ config.GetRef("auto_camera") = checkbox_val;
+ int num_cameras = ActiveCameras::NumCameras();
+ int curr_id = ActiveCameras::GetID();
+ for(int i=0; i<num_cameras; ++i){
+ ActiveCameras::Set(i);
+ ActiveCameras::Get()->SetAutoCamera(checkbox_val);
+ }
+ ActiveCameras::Set(curr_id);
+ }
+
+ static int key_selected = -1;
+ const char* commands[] = {
+ "Forwards",
+ "key[up]",
+ "Backwards",
+ "key[down]",
+ "Left",
+ "key[left]",
+ "Right",
+ "key[right]",
+ "Jump",
+ "key[jump]",
+ "Crouch",
+ "key[crouch]",
+ "Slow motion",
+ "key[slow]",
+ "Equip/sheathe item",
+ "key[item]",
+ "Throw/pick-up item",
+ "key[drop]",
+ "\0"
+ };
+
+ ImGui::Columns(2);
+ int id=0;
+ for(int i=0; commands[i][0] != '\0'; i+=2){
+ ImGui::PushItemWidth(-1);
+ if(i == key_selected){
+ ImGui::Text("Enter input");
+ } else {
+ ImGui::PushID(id);
+ if(ImGui::Button(config[commands[i+1]].str().c_str())){
+ key_selected = i;
+ }
+ ImGui::PopID();
+ ++id;
+ }
+ ImGui::PopItemWidth();
+ ImGui::NextColumn();
+ ImGui::PushID(id);
+ ImGui::Text("%s", commands[i]);
+ ImGui::PopID();
+ ++id;
+ ImGui::NextColumn();
+ }
+ if(key_selected != -1){
+ ImGui::CaptureKeyboardFromApp();
+ ImGui::CaptureMouseFromApp();
+ for(int i=0; i<512; ++i){
+ if(ImGui::IsKeyDown(i)){
+ int val = i;
+ if(val > SDLK_z){
+ val = val + SDLK_CAPSLOCK - 1 - SDLK_z;
+ }
+ config.GetRef(commands[key_selected+1]) = SDLKeycodeToString((SDL_Keycode)val);
+ Input::Instance()->SetFromConfig(config);
+ key_selected = -1;
+ }
+ }
+ }
+ ImGui::Columns(1);
+ ImGui::EndMenu();
+ }
+
+ if (ImGui::BeginMenu("Camera")) {
+ int slider_val;
+ slider_val = static_cast<int>(config["chase_camera_fov"].toNumber<float>());
+
+ if (slider_val == 0) {
+ slider_val = 90;
+ }
+
+ if (ImGui::SliderInt("Chase Camera FOV", &slider_val, 1, 180, "%.0f degrees")) {
+ config.GetRef("chase_camera_fov") = static_cast<float>(slider_val);
+ }
+
+ slider_val = static_cast<int>(config["editor_camera_fov"].toNumber<float>());
+
+ if (slider_val == 0) {
+ slider_val = 90;
+ }
+
+ if (ImGui::SliderInt("Editor Camera FOV", &slider_val, 1, 180, "%.0f degrees")) {
+ config.GetRef("editor_camera_fov") = static_cast<float>(slider_val);
+ }
+
+ ImGui::Text("+/- key to change current FOV");
+ ImGui::Text("0 to reset to 90");
+
+ ImGui::EndMenu();
+ }
+
+ if (ImGui::BeginMenu("Debug")) {
+ bool checkbox_val;
+
+ checkbox_val = config["debug_keys"].toNumber<bool>();
+ if(ImGui::Checkbox("Debug keys", &checkbox_val)){
+ config.GetRef("debug_keys") = checkbox_val;
+ Input::Instance()->debug_keys = checkbox_val;
+ }
+
+ checkbox_val = config["skip_loading_pause"].toNumber<bool>();
+ if(ImGui::Checkbox("Skip Loading Pause 'press any key'", &checkbox_val)){
+ config.GetRef("skip_loading_pause") = checkbox_val;
+ }
+
+ ImGui::Checkbox("Dynamic Character Cubemap", &Graphics::Instance()->config_.dynamic_character_cubemap_);
+
+ checkbox_val = config["decal_normals"].toNumber<bool>();
+ if(ImGui::Checkbox("Decal normal maps", &checkbox_val)){
+ config.GetRef("decal_normals") = checkbox_val;
+ }
+
+ checkbox_val = config["visible_raycasts"].toNumber<bool>();
+ if(ImGui::Checkbox("Visible Raycasts", &checkbox_val)){
+ config.GetRef("visible_raycasts") = checkbox_val;
+ }
+
+ checkbox_val = config["visible_sound_spheres"].toNumber<bool>();
+ if(ImGui::Checkbox("Visible Sound Spheres", &checkbox_val)){
+ config.GetRef("visible_sound_spheres") = checkbox_val;
+ DebugDrawAux::Instance()->visible_sound_spheres = checkbox_val;
+ }
+
+ checkbox_val = config["sound_label"].toNumber<bool>();
+ if(ImGui::Checkbox("Sound Display", &checkbox_val)){
+ config.GetRef("sound_label") = checkbox_val;
+ }
+
+ checkbox_val = config["fps_label"].toNumber<bool>();
+ if(ImGui::Checkbox("FPS Display", &checkbox_val)){
+ config.GetRef("fps_label") = checkbox_val;
+ }
+
+ checkbox_val = config["editor_mode"].toNumber<bool>();
+ if(ImGui::Checkbox("Start Level In Editor", &checkbox_val)){
+ config.GetRef("editor_mode") = checkbox_val;
+ }
+
+ checkbox_val = config["main_menu"].toNumber<bool>();
+ if(ImGui::Checkbox("Start In Main Menu", &checkbox_val)){
+ config.GetRef("main_menu") = checkbox_val;
+ }
+
+ const int kBufSize = 256;
+ char buf[kBufSize];
+ FormatString(buf, kBufSize, "%s", config["debug_load_level"].str().c_str());
+ if(ImGui::InputText("Level to load", buf, kBufSize)){
+ config.GetRef("debug_load_level") = buf;
+ }
+
+ checkbox_val = config["seamless_cubemaps"].toNumber<bool>();
+ if(ImGui::Checkbox("Seamless Cubemaps", &checkbox_val)){
+ config.GetRef("seamless_cubemaps") = checkbox_val;
+ Graphics::Instance()->SetSeamlessCubemaps(checkbox_val);
+ }
+
+ /*
+ checkbox_val = config["background_process_pool"].toNumber<bool>();
+ if(ImGui::Checkbox("Background Process Pool", &checkbox_val)){
+ config.GetRef("background_process_pool") = checkbox_val;
+ Textures::Instance()->SetProcessPoolsEnabled(checkbox_val);
+ }
+ */
+
+ if (ImGui::BeginMenu("Animation")) {
+ ImGui::Checkbox("Disable IK", &animation_config.kDisableIK);
+ ImGui::Checkbox("Disable Modifiers", &animation_config.kDisableModifiers);
+ ImGui::Checkbox("Disable Soft Animation", &animation_config.kDisableSoftAnimation);
+ ImGui::Checkbox("Disable Interpolation", &animation_config.kDisableInterpolation);
+ ImGui::Checkbox("Disable Animation Layers", &animation_config.kDisableAnimationLayers);
+ ImGui::Checkbox("Disable Animation Mix", &animation_config.kDisableAnimationMix);
+ ImGui::Checkbox("Disable Animation Transition", &animation_config.kDisableAnimationTransition);
+ ImGui::Checkbox("Disable Physics Interpolation", &animation_config.kDisablePhysicsInterpolation);
+ ImGui::Checkbox("Force Idle Anim", &animation_config.kForceIdleAnim);
+ ImGui::EndMenu();
+ }
+
+ if (ImGui::BeginMenu("Movement")) {
+ checkbox_val = config["debug_draw_collision_spheres"].toNumber<bool>();
+ if(ImGui::Checkbox("Show Collision Spheres", &checkbox_val)){
+ config.GetRef("debug_draw_collision_spheres") = checkbox_val;
+ }
+
+ checkbox_val = config["debug_draw_combat_debug"].toNumber<bool>();
+ if(ImGui::Checkbox("Show Combat State", &checkbox_val)){
+ config.GetRef("debug_draw_combat_debug") = checkbox_val;
+ }
+
+ checkbox_val = config["debug_draw_vis_lines"].toNumber<bool>();
+ if(ImGui::Checkbox("Draw Vis Lines", &checkbox_val)){
+ config.GetRef("debug_draw_vis_lines") = checkbox_val;
+ }
+
+ checkbox_val = config["debug_draw_bones"].toNumber<bool>();
+ if(ImGui::Checkbox("Draw Bones", &checkbox_val)){
+ config.GetRef("debug_draw_bones") = checkbox_val;
+ }
+
+ ImGui::EndMenu();
+ }
+
+ if (ImGui::BeginMenu("AI")) {
+ checkbox_val = config["debug_show_ai_state"].toNumber<bool>();
+ if(ImGui::Checkbox("Show AI State", &checkbox_val)){
+ config.GetRef("debug_show_ai_state") = checkbox_val;
+ }
+
+ checkbox_val = config["debug_draw_stealth_debug"].toNumber<bool>();
+ if(ImGui::Checkbox("Show AI Awareness State", &checkbox_val)){
+ config.GetRef("debug_draw_stealth_debug") = checkbox_val;
+ }
+
+ checkbox_val = config["debug_show_ai_path"].toNumber<bool>();
+ if(ImGui::Checkbox("Show AI Path", &checkbox_val)){
+ config.GetRef("debug_show_ai_path") = checkbox_val;
+ }
+
+ checkbox_val = config["debug_show_ai_jump"].toNumber<bool>();
+ if(ImGui::Checkbox("Show AI Jump", &checkbox_val)){
+ config.GetRef("debug_show_ai_jump") = checkbox_val;
+ }
+
+ checkbox_val = config["debug_show_ai_investigate"].toNumber<bool>();
+ if(ImGui::Checkbox("Show AI Investigate", &checkbox_val)){
+ config.GetRef("debug_show_ai_investigate") = checkbox_val;
+ }
+
+ checkbox_val = config["debug_mouse_path_test"].toNumber<bool>();
+ if(ImGui::Checkbox("AI Mouse Path Testing", &checkbox_val)){
+ config.GetRef("debug_mouse_path_test") = checkbox_val;
+ }
+
+ ImGui::EndMenu();
+ }
+
+ if (ImGui::BeginMenu("Graphics")) {
+ checkbox_val = config["albedo_only"].toNumber<bool>();
+ if(ImGui::Checkbox("Albedo Only", &checkbox_val)){
+ config.GetRef("albedo_only") = checkbox_val;
+ g_albedo_only = checkbox_val;
+ }
+
+ checkbox_val = config["no_decals"].toNumber<bool>();
+ if(ImGui::Checkbox("No Light/Decal system", &checkbox_val)){
+ config.GetRef("no_decals") = checkbox_val;
+ g_no_decals = checkbox_val;
+ }
+
+ checkbox_val = config["no_decal_elements"].toNumber<bool>();
+ if(ImGui::Checkbox("No Lights or Decals", &checkbox_val)){
+ config.GetRef("no_decal_elements") = checkbox_val;
+ g_no_decal_elements = checkbox_val;
+ }
+
+ checkbox_val = config["occlusion_query"].toNumber<bool>();
+ if(ImGui::Checkbox("Occlusion Queries", &checkbox_val)){
+ config.GetRef("occlusion_query") = checkbox_val;
+ g_perform_occlusion_query = checkbox_val;
+ }
+
+ checkbox_val = config["gamma_correct_final_output"].toNumber<bool>();
+ if(ImGui::Checkbox("Gamma Correct Final Output", &checkbox_val)){
+ config.GetRef("gamma_correct_final_output") = checkbox_val;
+ g_gamma_correct_final_output = checkbox_val;
+ }
+
+ if (GLEW_VERSION_4_0) {
+ checkbox_val = config["single_pass_shadow_cascade"].toNumber<bool>();
+ if(ImGui::Checkbox("Single-Pass Shadow Cascade", &checkbox_val)){
+ config.GetRef("single_pass_shadow_cascade") = checkbox_val;
+ g_single_pass_shadow_cascade = checkbox_val;
+ }
+ }
+
+ checkbox_val = config["no_detailmaps"].toNumber<bool>();
+ if(ImGui::Checkbox("Disable detail maps", &checkbox_val)){
+ config.GetRef("no_detailmaps") = checkbox_val;
+ g_no_detailmaps = checkbox_val;
+ }
+
+ checkbox_val = g_ubo_batch_multiplier_force_1x;
+ if(ImGui::Checkbox("Disable UBO Batch Multiplier", &checkbox_val)){
+ // Not saved to config (at least for now)
+ g_ubo_batch_multiplier_force_1x = checkbox_val;
+ }
+
+ checkbox_val = config["volume_shadows"].toNumber<bool>();
+ if(ImGui::Checkbox("Volume Shadows", &checkbox_val)){
+ config.GetRef("volume_shadows") = checkbox_val;
+ }
+
+ checkbox_val = config["ssao"].toNumber<bool>();
+ if(ImGui::Checkbox("SSAO", &checkbox_val)){
+ config.GetRef("ssao") = checkbox_val;
+ }
+
+ checkbox_val = config["disable_fog"].toNumber<bool>();
+ if(ImGui::Checkbox("Disable Fog", &checkbox_val)){
+ config.GetRef("disable_fog") = checkbox_val;
+ g_disable_fog = config["disable_fog"].toNumber<bool>();
+ }
+
+ checkbox_val = graphics->config_.gpu_skinning();
+ if(ImGui::Checkbox("GPU Skinning", &checkbox_val)){
+ config.GetRef("gpu_skinning") = checkbox_val;
+ graphics->config_.SetGPUSkinning(checkbox_val);
+ if( scenegraph ) {
+ scenegraph->map_editor->UpdateGPUSkinning();
+ }
+ }
+
+ checkbox_val = config["opengl_callback_errors"].toNumber<bool>();
+ if(ImGui::Checkbox("OpenGL Callbacks Errors", &checkbox_val)){
+ config.GetRef("opengl_callback_errors") = checkbox_val;
+ }
+
+ checkbox_val = config["opengl_callback_error_dialog"].toNumber<bool>();
+ if(ImGui::Checkbox("Dialog on OpenGL error", &checkbox_val)){
+ config.GetRef("opengl_callback_error_dialog") = checkbox_val;
+ }
+
+ ImGui::EndMenu();
+ }
+
+ if (ImGui::BeginMenu("Sound")) {
+ checkbox_val = config["use_soundtrack_limiter"].toBool();
+ if(ImGui::Checkbox("Use Soundtrack Limiter", &checkbox_val)) {
+ UpdateEnableLayeredSoundtrackLimiter(checkbox_val);
+ }
+
+ ImGui::EndMenu();
+ }
+
+ if (ImGui::BeginMenu("Game")) {
+ checkbox_val = config["block_cheating_progress"].toBool();
+ if(ImGui::Checkbox("Block Cheating Progress", &checkbox_val)) {
+ config.GetRef("block_cheating_progress") = checkbox_val;
+ }
+
+ ImGui::EndMenu();
+ }
+
+ checkbox_val = config["allow_game_dir_save"].toNumber<bool>();
+ if(ImGui::Checkbox("Allow Game Directory Save", &checkbox_val)){
+ config.GetRef("allow_game_dir_save") = checkbox_val;
+ }
+
+ checkbox_val = config["no_auto_nav_mesh"].toNumber<bool>();
+ if(ImGui::Checkbox("Disable Auto Navmesh Regen", &checkbox_val)){
+ config.GetRef("no_auto_nav_mesh") = checkbox_val;
+ }
+
+ checkbox_val = config["no_texture_convert"].toNumber<bool>();
+ if(ImGui::Checkbox("Disable Auto Texture Conversion", &checkbox_val)){
+ config.GetRef("no_texture_convert") = checkbox_val;
+ }
+
+ checkbox_val = config.HasKey("list_include_files_when_logging_mod_errors")
+ ? config["list_include_files_when_logging_mod_errors"].toNumber<bool>()
+ : true;
+ if(ImGui::Checkbox("List Include Files When Logging Mod Errors", &checkbox_val)){
+ config.GetRef("list_include_files_when_logging_mod_errors") = checkbox_val;
+ }
+
+ ImGui::Separator();
+
+ if(ImGui::Button("Clear local write cache (dangerous)")){
+ ClearCache(false);
+ }
+
+ if(ImGui::Button("List files that would be cleared from cache")){
+ ClearCache(true);
+ }
+
+ ImGui::Separator();
+
+ if(ImGui::Button("Show test error message")){
+ DisplayError("Error test title", "Error test body");
+ }
+
+ if( ImGui::Button("Dump state" ) ) {
+ SceneGraph* s = Engine::Instance()->GetSceneGraph();
+ if(s) {
+ s->DumpState();
+ }
+ DumpAngelscriptStates();
+ LogSystem::Flush();
+ }
+
+ ImGui::Separator();
+
+ if (ImGui::BeginMenu("Campaign Progress (Dangerous)")) {
+ if(ImGui::Button("Unlock all campaign levels")){
+ std::vector<ModInstance::Campaign> campaigns = ModLoading::Instance().GetCampaigns();
+ for( size_t i = 0; i < campaigns.size(); i++ ) {
+ ModInstance::Campaign camp = campaigns[i];
+ SavedLevel& s = Engine::Instance()->save_file_.GetSave(camp.id.str(),"linear_campaign","");
+ for( size_t k = 0; k < camp.levels.size(); k++ ) {
+ s.SetArrayValue("unlocked_levels",k,camp.levels[k].id.str());
+ }
+ }
+ Engine::Instance()->save_file_.QueueWriteInPlace();
+ }
+
+ if(ImGui::BeginMenu("Unlock level in campaign")) {
+ std::vector<ModInstance::Campaign> campaigns = ModLoading::Instance().GetCampaigns();
+ for( size_t i = 0; i < campaigns.size(); i++ ) {
+ ModInstance::Campaign camp = campaigns[i];
+ if(ImGui::BeginMenu(camp.title.c_str())) {
+ for( size_t k = 0; k < camp.levels.size(); k++ ) {
+ if(ImGui::Button(camp.levels[k].title.c_str())) {
+ SavedLevel& s = Engine::Instance()->save_file_.GetSave(camp.id.str(),"linear_campaign","");
+ s.AppendArrayValueIfUnique("unlocked_levels",camp.levels[k].id.str());
+ Engine::Instance()->save_file_.QueueWriteInPlace();
+ }
+ }
+ ImGui::EndMenu();
+ }
+ }
+ ImGui::EndMenu();
+ }
+
+ if(ImGui::Button("Clear all campaign progress")){
+ std::vector<ModInstance::Campaign> campaigns = ModLoading::Instance().GetCampaigns();
+ for( size_t i = 0; i < campaigns.size(); i++ ) {
+ ModInstance::Campaign camp = campaigns[i];
+ SavedLevel& s = Engine::Instance()->save_file_.GetSave(camp.id.str(),"linear_campaign","");
+ s.ClearData();
+ }
+ Engine::Instance()->save_file_.QueueWriteInPlace();
+ }
+
+ std::vector<std::string> difficulties = config.GetDifficultyPresets();
+
+ if(ImGui::BeginMenu("Finish All Levels On Difficulty")) {
+ for( size_t k = 0; k < difficulties.size(); k++ ) {
+ if( ImGui::Button(difficulties[k].c_str())) {
+ std::vector<ModInstance::Campaign> campaigns = ModLoading::Instance().GetCampaigns();
+ for( size_t i = 0; i < campaigns.size(); i++ ) {
+ ModInstance::Campaign camp = campaigns[i];
+ for( size_t j = 0; j < camp.levels.size(); j++ ) {
+ SavedLevel& s = Engine::Instance()->save_file_.GetSave(camp.id.str(),"linear_campaign",camp.levels[j].id.str());
+ if( false == s.ArrayContainsValue("finished_difficulties",difficulties[k]) ) {
+ s.AppendArrayValue("finished_difficulties",difficulties[k]);
+ }
+ }
+ }
+ Engine::Instance()->save_file_.QueueWriteInPlace();
+ }
+ }
+ ImGui::EndMenu();
+ }
+
+ if(ImGui::BeginMenu("Finish Level On Difficulty")) {
+ std::vector<ModInstance::Campaign> campaigns = ModLoading::Instance().GetCampaigns();
+ for( size_t i = 0; i < campaigns.size(); i++ ) {
+ ModInstance::Campaign camp = campaigns[i];
+ if(ImGui::BeginMenu(camp.title)) {
+ for( size_t j = 0; j < camp.levels.size(); j++ ) {
+ ModInstance::Level level = camp.levels[j];
+ if(ImGui::BeginMenu(level.title)) {
+ for( size_t k = 0; k < difficulties.size(); k++ ) {
+ if( ImGui::Button(difficulties[k].c_str())) {
+ SavedLevel& s = Engine::Instance()->save_file_.GetSave(camp.id.str(),"linear_campaign",level.id.str());
+ if( false == s.ArrayContainsValue("finished_difficulties",difficulties[k]) ) {
+ s.AppendArrayValue("finished_difficulties",difficulties[k]);
+ }
+ Engine::Instance()->save_file_.QueueWriteInPlace();
+ }
+ }
+ ImGui::EndMenu();
+ }
+ }
+ ImGui::EndMenu();
+ }
+ }
+ ImGui::EndMenu();
+ }
+
+ if(ImGui::Button("Clear All Linear Level Data")) {
+ std::vector<ModInstance::Campaign> campaigns = ModLoading::Instance().GetCampaigns();
+ for( size_t i = 0; i < campaigns.size(); i++ ) {
+ ModInstance::Campaign camp = campaigns[i];
+ for( size_t j = 0; j < camp.levels.size(); j++ ) {
+ SavedLevel& s = Engine::Instance()->save_file_.GetSave(camp.id.str(),"linear_campaign",camp.levels[j].id.str());
+ s.ClearData();
+ }
+ }
+ Engine::Instance()->save_file_.QueueWriteInPlace();
+ }
+
+ if(ImGui::BeginMenu("Clear Save Data For Level")) {
+ std::vector<ModInstance::Campaign> campaigns = ModLoading::Instance().GetCampaigns();
+ for( size_t i = 0; i < campaigns.size(); i++ ) {
+ ModInstance::Campaign camp = campaigns[i];
+ if(ImGui::BeginMenu(camp.title)) {
+ for( size_t j = 0; j < camp.levels.size(); j++ ) {
+ ModInstance::Level level = camp.levels[j];
+ if(ImGui::Button(level.title)) {
+ SavedLevel& s = Engine::Instance()->save_file_.GetSave(camp.id.str(),"linear_campaign",level.id.str());
+ s.ClearData();
+ Engine::Instance()->save_file_.QueueWriteInPlace();
+ }
+ }
+ ImGui::EndMenu();
+ }
+ }
+ ImGui::EndMenu();
+ }
+
+ ImGui::EndMenu();
+ }
+
+ checkbox_val = config.GetRef("player_invincible").toNumber<bool>();
+ if(ImGui::Checkbox("Make player invincible", &checkbox_val)) {
+ config.GetRef("player_invincible") = checkbox_val;
+ }
+
+ ImGui::EndMenu();
+ }
+}