diff --git a/src/spice2x/cfg/screen_resize.cpp b/src/spice2x/cfg/screen_resize.cpp index e55e130..8d78f1a 100644 --- a/src/spice2x/cfg/screen_resize.cpp +++ b/src/spice2x/cfg/screen_resize.cpp @@ -87,6 +87,10 @@ namespace cfg { load_float_value(doc, root + prefix + "scale_x", scene.scale_x); load_float_value(doc, root + prefix + "scale_y", scene.scale_y); load_bool_value(doc, root + prefix + "keep_aspect_ratio", scene.keep_aspect_ratio); + + int duplicate = 0; + load_int_value(doc, root + prefix + "duplicate", duplicate); + scene.duplicate = static_cast(duplicate); } // windowed settings are always under game settings @@ -201,6 +205,7 @@ namespace cfg { rapidjson::Pointer(root + prefix + "scale_x").Set(doc, scene.scale_x); rapidjson::Pointer(root + prefix + "scale_y").Set(doc, scene.scale_y); rapidjson::Pointer(root + prefix + "keep_aspect_ratio").Set(doc, scene.keep_aspect_ratio); + rapidjson::Pointer(root + prefix + "duplicate").Set(doc, scene.duplicate); } // windowed mode settings diff --git a/src/spice2x/cfg/screen_resize.h b/src/spice2x/cfg/screen_resize.h index dd60cc6..e1077f1 100644 --- a/src/spice2x/cfg/screen_resize.h +++ b/src/spice2x/cfg/screen_resize.h @@ -14,12 +14,19 @@ namespace cfg { ResizableFrame = 2 }; + enum ScreenDuplicateMode { + None = 0, + CopyLeft = 1, + CopyRight = 2, + }; + struct fullscreen_setting { int offset_x = 0; int offset_y = 0; float scale_x = 1.0; float scale_y = 1.0; bool keep_aspect_ratio = true; + ScreenDuplicateMode duplicate = ScreenDuplicateMode::None; }; extern std::optional SCREEN_RESIZE_CFG_PATH_OVERRIDE; diff --git a/src/spice2x/hooks/graphics/backends/d3d9/d3d9_device.cpp b/src/spice2x/hooks/graphics/backends/d3d9/d3d9_device.cpp index bb50c16..47ad120 100644 --- a/src/spice2x/hooks/graphics/backends/d3d9/d3d9_device.cpp +++ b/src/spice2x/hooks/graphics/backends/d3d9/d3d9_device.cpp @@ -733,6 +733,16 @@ void SurfaceHook(IDirect3DDevice9 *pReal) { const int rectTop = param.BackBufferHeight; const int w = param.BackBufferWidth; const int h = param.BackBufferHeight; + + if (cfg::SCREENRESIZE->enable_screen_resize) { + RECT rect { + 0, + 0, + (LONG)topSurface_width, + (LONG)topSurface_height, + }; + pReal->ColorFill(topSurface, &rect, D3DCOLOR_XRGB(0, 0, 0)); + } D3DLOCKED_RECT rect; HRESULT hr; @@ -750,6 +760,7 @@ void SurfaceHook(IDirect3DDevice9 *pReal) { (LONG)(rectLeft + w), (LONG)(rectTop + h), }; + if (GRAPHICS_FS_ORIENTATION_SWAP) { originRect.left = (topSurface_width / 2) - (GRAPHICS_FS_ORIGINAL_WIDTH / 2); originRect.top = (topSurface_height / 2) - (GRAPHICS_FS_ORIGINAL_HEIGHT / 2); @@ -757,6 +768,21 @@ void SurfaceHook(IDirect3DDevice9 *pReal) { originRect.bottom = originRect.top + GRAPHICS_FS_ORIGINAL_HEIGHT; } + bool duplicate = false; + RECT originRect2 = originRect; + if (cfg::SCREENRESIZE->enable_screen_resize) { + auto& scene = cfg::SCREENRESIZE->scene_settings[cfg::SCREENRESIZE->screen_resize_current_scene]; + if (scene.duplicate == cfg::ScreenDuplicateMode::CopyLeft) { + duplicate = true; + originRect2.right = originRect.left; + originRect2.left = (LONG)(originRect2.left - (originRect.right - originRect.left)); + } else if (scene.duplicate == cfg::ScreenDuplicateMode::CopyRight) { + duplicate = true; + originRect2.left = originRect.right; + originRect2.right = (LONG)(originRect2.left + (originRect.right - originRect.left)); + } + } + // log_misc( // "graphics::d3d9", "originRect: {} {} {} {}", // originRect.left, originRect.top, originRect.right, originRect.bottom); @@ -768,9 +794,21 @@ void SurfaceHook(IDirect3DDevice9 *pReal) { if (hr != D3D_OK) { log_warning( "graphics::d3d9", - "SurfaceHook - StretchRect backbuffer failed, rect: {} {} {} {}", + "SurfaceHook - StretchRect backbuffer failed for main image, rect: {} {} {} {}", originRect.left, originRect.top, originRect.right, originRect.bottom); } + if (duplicate) { + hr = pReal->StretchRect( + backbuffer, nullptr, + topSurface, &originRect2, + D3DTEXF_LINEAR); + if (hr != D3D_OK) { + log_warning( + "graphics::d3d9", + "SurfaceHook - StretchRect backbuffer failed for the duplicate, rect: {} {} {} {}", + originRect2.left, originRect2.top, originRect2.right, originRect2.bottom); + } + } topSurface->UnlockRect(); // phase 2 - viewport calculation - do the actual zoom / offset math diff --git a/src/spice2x/overlay/windows/screen_resize.cpp b/src/spice2x/overlay/windows/screen_resize.cpp index f3c53b8..3e10e75 100644 --- a/src/spice2x/overlay/windows/screen_resize.cpp +++ b/src/spice2x/overlay/windows/screen_resize.cpp @@ -55,6 +55,7 @@ namespace overlay::windows { 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; @@ -149,6 +150,17 @@ namespace overlay::windows { 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(); }