#include #include "screen_resize.h" #include "avs/game.h" #include "cfg/screen_resize.h" #include "hooks/graphics/graphics.h" #include "overlay/imgui/extensions.h" #include "misc/eamuse.h" #include "util/logging.h" #include "util/utils.h" namespace overlay::windows { ScreenResize::ScreenResize(SpiceOverlay *overlay) : Window(overlay) { this->title = "Screen Resize"; this->flags = ImGuiWindowFlags_AlwaysAutoResize; this->init_pos = ImVec2(10, 10); this->toggle_button = games::OverlayButtons::ToggleScreenResize; this->toggle_screen_resize = games::OverlayButtons::ScreenResize; this->toggle_scene[0] = games::OverlayButtons::ScreenResizeScene1; this->toggle_scene[1] = games::OverlayButtons::ScreenResizeScene2; this->toggle_scene[2] = games::OverlayButtons::ScreenResizeScene3; this->toggle_scene[3] = games::OverlayButtons::ScreenResizeScene4; } ScreenResize::~ScreenResize() { } HWND ScreenResize::get_first_window() { if (GRAPHICS_WINDOWS.size() == 0) { return NULL; } return GRAPHICS_WINDOWS[0]; } void ScreenResize::reset_window() { this->reset_vars_to_default(); if (GRAPHICS_WINDOWED) { const auto window = get_first_window(); if (window) { graphics_move_resize_window(window); graphics_update_window_style(window); } } } void ScreenResize::reset_vars_to_default() { cfg::SCREENRESIZE->enable_screen_resize = false; cfg::SCREENRESIZE->screen_resize_current_scene = 0; cfg::SCREENRESIZE->enable_linear_filter = true; for (size_t i = 0; i < std::size(cfg::SCREENRESIZE->scene_settings); i++) { auto& scene = cfg::SCREENRESIZE->scene_settings[i]; scene.keep_aspect_ratio = true; scene.offset_x = 0; scene.offset_y = 0; scene.scale_x = 1.f; scene.scale_y = 1.f; scene.duplicate = cfg::ScreenDuplicateMode::None; } cfg::SCREENRESIZE->enable_window_resize = false; cfg::SCREENRESIZE->window_always_on_top = false; cfg::SCREENRESIZE->window_decoration = cfg::WindowDecorationMode::Default; cfg::SCREENRESIZE->window_offset_x = 0; cfg::SCREENRESIZE->window_offset_y = 0; cfg::SCREENRESIZE->client_keep_aspect_ratio = true; cfg::SCREENRESIZE->client_width = cfg::SCREENRESIZE->init_client_width; cfg::SCREENRESIZE->client_height = cfg::SCREENRESIZE->init_client_height; } void ScreenResize::build_content() { ImGui::Text("For: %s", eamuse_get_game().c_str()); { if (ImGui::TreeNodeEx("Image Resize", ImGuiTreeNodeFlags_DefaultOpen)) { this->build_fullscreen_config(); ImGui::TreePop(); } } ImGui::BeginDisabled(!GRAPHICS_WINDOWED); { int flags = 0; if (GRAPHICS_WINDOWED) { flags |= ImGuiTreeNodeFlags_DefaultOpen; } if (ImGui::TreeNodeEx("Window Size", flags)) { build_windowed_config(); ImGui::TreePop(); } ImGui::EndDisabled(); } ImGui::Separator(); build_footer(); } void ScreenResize::build_fullscreen_config() { // enable checkbox ImGui::Checkbox("Enable", &cfg::SCREENRESIZE->enable_screen_resize); ImGui::SameLine(); ImGui::HelpMarker("Hint: bind a key to Screen Resize for a quick toggle."); ImGui::BeginDisabled(!cfg::SCREENRESIZE->enable_screen_resize); ImGui::Checkbox("Linear Filter", &cfg::SCREENRESIZE->enable_linear_filter); if (ImGui::RadioButton("Scene 1", cfg::SCREENRESIZE->screen_resize_current_scene == 0)) { cfg::SCREENRESIZE->screen_resize_current_scene = 0; } ImGui::SameLine(); if (ImGui::RadioButton("Scene 2", cfg::SCREENRESIZE->screen_resize_current_scene == 1)) { cfg::SCREENRESIZE->screen_resize_current_scene = 1; } ImGui::SameLine(); if (ImGui::RadioButton("Scene 3", cfg::SCREENRESIZE->screen_resize_current_scene == 2)) { cfg::SCREENRESIZE->screen_resize_current_scene = 2; } ImGui::SameLine(); if (ImGui::RadioButton("Scene 4", cfg::SCREENRESIZE->screen_resize_current_scene == 3)) { cfg::SCREENRESIZE->screen_resize_current_scene = 3; } ImGui::SameLine(); ImGui::HelpMarker( "Hint: bind a key to Screen Resize 1/2/3/4 for quick scene switching. " "Scene 1 is the default scene activated when starting the game."); auto& scene = cfg::SCREENRESIZE->scene_settings[cfg::SCREENRESIZE->screen_resize_current_scene]; // general settings ImGui::InputInt("X Offset", &scene.offset_x); ImGui::SameLine(); ImGui::HelpMarker("Hint: ctrl + click on +/- buttons to move quickly."); ImGui::InputInt("Y Offset", &scene.offset_y); ImGui::SameLine(); ImGui::HelpMarker("Hint: ctrl + click on +/- buttons to move quickly."); // aspect ratio ImGui::Checkbox("Keep Aspect Ratio", &scene.keep_aspect_ratio); if (scene.keep_aspect_ratio) { if (ImGui::SliderFloat("Scale", &scene.scale_x, 0.5f, 2.5f)) { scene.scale_y = scene.scale_x; } ImGui::SameLine(); ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value."); } else { ImGui::SliderFloat("Width Scale", &scene.scale_x, 0.5f, 2.5f); ImGui::SameLine(); ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value."); ImGui::SliderFloat("Height Scale", &scene.scale_y, 0.5f, 2.5f); ImGui::SameLine(); ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value."); } static const char* dupe_items[] = { "None", "Copy Left", "Copy Right" }; ImGui::Combo( "Duplicate", reinterpret_cast(&scene.duplicate), dupe_items, ARRAYSIZE(dupe_items)); ImGui::SameLine(); ImGui::HelpMarker( "Show an identical copy of the image on the left or right, allowing you to achieve " "wrap-around effect when an offset is set."); ImGui::EndDisabled(); } void ScreenResize::build_windowed_config() { // for now, only supports the first window const auto window = get_first_window(); if (!window) { return; } ImGui::TextUnformatted("Warning: may cause some games to crash."); ImGui::BeginDisabled(graphics_window_change_crashes_game()); if (ImGui::Combo( "Window Style", &cfg::SCREENRESIZE->window_decoration, "Default\0Borderless\0Resizable Window\0\0")) { graphics_update_window_style(window); } ImGui::EndDisabled(); ImGui::SameLine(); ImGui::HelpMarker( "Change window decoration. Resizable Window may not cause your mouse cursor to change, " "but you can still drag to resize. Disabled for some games due to incompatibility."); if (ImGui::Checkbox("Always On Top", &cfg::SCREENRESIZE->window_always_on_top) ) { graphics_update_z_order(window, cfg::SCREENRESIZE->window_always_on_top); } ImGui::BeginDisabled(); ImGui::Checkbox("Forced Render Scaling", &GRAPHICS_WINDOW_BACKBUFFER_SCALE); ImGui::EndDisabled(); ImGui::SameLine(); ImGui::HelpMarker( "For windowed mode: forcibly set DX9 back buffer dimensions to match window size. " "Reduces pixelated scaling artifacts. Works great on some games, but completely broken on others.\n\n" "This can't be changed in-game; instead, set -windowscale option in spicecfg and restart."); ImGui::Checkbox("Keep Aspect Ratio", &cfg::SCREENRESIZE->client_keep_aspect_ratio); ImGui::Checkbox("Manual window move/resize", &cfg::SCREENRESIZE->enable_window_resize); ImGui::BeginDisabled(!cfg::SCREENRESIZE->enable_window_resize); bool changed = false; const uint32_t step = 1; const uint32_t step_fast = 10; ImGui::BeginDisabled(cfg::SCREENRESIZE->client_keep_aspect_ratio); ImGui::InputScalar( "Width", ImGuiDataType_U32, &cfg::SCREENRESIZE->client_width, &step, &step_fast, nullptr); changed |= ImGui::IsItemDeactivatedAfterEdit(); ImGui::EndDisabled(); ImGui::InputScalar( "Height", ImGuiDataType_U32, &cfg::SCREENRESIZE->client_height, &step, &step_fast, nullptr); changed |= ImGui::IsItemDeactivatedAfterEdit(); ImGui::InputScalar( "X Offset", ImGuiDataType_S32, &cfg::SCREENRESIZE->window_offset_x, &step, &step_fast, nullptr); changed |= ImGui::IsItemDeactivatedAfterEdit(); ImGui::InputScalar( "Y Offset", ImGuiDataType_S32, &cfg::SCREENRESIZE->window_offset_y, &step, &step_fast, nullptr); changed |= ImGui::IsItemDeactivatedAfterEdit(); if (changed) { if (cfg::SCREENRESIZE->client_keep_aspect_ratio) { cfg::SCREENRESIZE->client_width = cfg::SCREENRESIZE->client_height * cfg::SCREENRESIZE->init_client_aspect_ratio; } graphics_move_resize_window(window); } ImGui::EndDisabled(); } void ScreenResize::build_footer() { // reset button if (ImGui::Button("Reset")) { this->reset_window(); } // load button ImGui::SameLine(); if (ImGui::Button("Load")) { cfg::SCREENRESIZE->config_load(); } // save button ImGui::SameLine(); if (ImGui::Button("Save")) { cfg::SCREENRESIZE->config_save(); } } void ScreenResize::update() { Window::update(); auto overlay_buttons = games::get_buttons_overlay(eamuse_get_game()); // toggle if (this->toggle_screen_resize != ~0u) { bool toggle_screen_resize_new = overlay_buttons && this->overlay->hotkeys_triggered() && GameAPI::Buttons::getState(RI_MGR, overlay_buttons->at(this->toggle_screen_resize)); if (toggle_screen_resize_new && !this->toggle_screen_resize_state) { cfg::SCREENRESIZE->enable_screen_resize = !cfg::SCREENRESIZE->enable_screen_resize; } this->toggle_screen_resize_state = toggle_screen_resize_new; } // scene switch auto toggle_scene_state_new = ~0u; for (size_t i = 0; i < std::size(this->toggle_scene); i++) { if (this->toggle_scene[i] == ~0u) { continue; } bool scene_switched = overlay_buttons && this->overlay->hotkeys_triggered() && GameAPI::Buttons::getState(RI_MGR, overlay_buttons->at(this->toggle_scene[i])); if (scene_switched) { toggle_scene_state_new = (uint32_t)i; } // only detect rising edges of key presses if (scene_switched && (this->toggle_scene_state != i)) { if (cfg::SCREENRESIZE->screen_resize_current_scene == (int8_t)i && cfg::SCREENRESIZE->enable_screen_resize) { // this scene is already active, turn scaling off cfg::SCREENRESIZE->enable_screen_resize = false; } else { // switch to scene cfg::SCREENRESIZE->enable_screen_resize = true; cfg::SCREENRESIZE->screen_resize_current_scene = i; } break; } } // remember if a key was pressed (or nothing pressed) this frame this->toggle_scene_state = toggle_scene_state_new; } }