Image duplication for screen resize (#401)

## Link to GitHub Issue, if one exists
#399 

## Description of change
Add image duplication option to screen resize, allowing overflow images
to wrap around the other side.

## Testing
Tested with DDR, IIDX (windowed and full screen TDJ), SDVX (orientation
swap)
This commit is contained in:
bicarus-dev
2025-10-12 20:34:45 -07:00
committed by GitHub
parent 02711cdee1
commit be2dab9a1a
4 changed files with 63 additions and 1 deletions
+5
View File
@@ -87,6 +87,10 @@ namespace cfg {
load_float_value(doc, root + prefix + "scale_x", scene.scale_x); load_float_value(doc, root + prefix + "scale_x", scene.scale_x);
load_float_value(doc, root + prefix + "scale_y", scene.scale_y); load_float_value(doc, root + prefix + "scale_y", scene.scale_y);
load_bool_value(doc, root + prefix + "keep_aspect_ratio", scene.keep_aspect_ratio); 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<cfg::ScreenDuplicateMode>(duplicate);
} }
// windowed settings are always under game settings // 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_x").Set(doc, scene.scale_x);
rapidjson::Pointer(root + prefix + "scale_y").Set(doc, scene.scale_y); 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 + "keep_aspect_ratio").Set(doc, scene.keep_aspect_ratio);
rapidjson::Pointer(root + prefix + "duplicate").Set(doc, scene.duplicate);
} }
// windowed mode settings // windowed mode settings
+7
View File
@@ -14,12 +14,19 @@ namespace cfg {
ResizableFrame = 2 ResizableFrame = 2
}; };
enum ScreenDuplicateMode {
None = 0,
CopyLeft = 1,
CopyRight = 2,
};
struct fullscreen_setting { struct fullscreen_setting {
int offset_x = 0; int offset_x = 0;
int offset_y = 0; int offset_y = 0;
float scale_x = 1.0; float scale_x = 1.0;
float scale_y = 1.0; float scale_y = 1.0;
bool keep_aspect_ratio = true; bool keep_aspect_ratio = true;
ScreenDuplicateMode duplicate = ScreenDuplicateMode::None;
}; };
extern std::optional<std::string> SCREEN_RESIZE_CFG_PATH_OVERRIDE; extern std::optional<std::string> SCREEN_RESIZE_CFG_PATH_OVERRIDE;
@@ -733,6 +733,16 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
const int rectTop = param.BackBufferHeight; const int rectTop = param.BackBufferHeight;
const int w = param.BackBufferWidth; const int w = param.BackBufferWidth;
const int h = param.BackBufferHeight; 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; D3DLOCKED_RECT rect;
HRESULT hr; HRESULT hr;
@@ -750,6 +760,7 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
(LONG)(rectLeft + w), (LONG)(rectLeft + w),
(LONG)(rectTop + h), (LONG)(rectTop + h),
}; };
if (GRAPHICS_FS_ORIENTATION_SWAP) { if (GRAPHICS_FS_ORIENTATION_SWAP) {
originRect.left = (topSurface_width / 2) - (GRAPHICS_FS_ORIGINAL_WIDTH / 2); originRect.left = (topSurface_width / 2) - (GRAPHICS_FS_ORIGINAL_WIDTH / 2);
originRect.top = (topSurface_height / 2) - (GRAPHICS_FS_ORIGINAL_HEIGHT / 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; 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( // log_misc(
// "graphics::d3d9", "originRect: {} {} {} {}", // "graphics::d3d9", "originRect: {} {} {} {}",
// originRect.left, originRect.top, originRect.right, originRect.bottom); // originRect.left, originRect.top, originRect.right, originRect.bottom);
@@ -768,9 +794,21 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
if (hr != D3D_OK) { if (hr != D3D_OK) {
log_warning( log_warning(
"graphics::d3d9", "graphics::d3d9",
"SurfaceHook - StretchRect backbuffer failed, rect: {} {} {} {}", "SurfaceHook - StretchRect backbuffer failed for main image, rect: {} {} {} {}",
originRect.left, originRect.top, originRect.right, originRect.bottom); 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(); topSurface->UnlockRect();
// phase 2 - viewport calculation - do the actual zoom / offset math // phase 2 - viewport calculation - do the actual zoom / offset math
@@ -55,6 +55,7 @@ namespace overlay::windows {
scene.offset_y = 0; scene.offset_y = 0;
scene.scale_x = 1.f; scene.scale_x = 1.f;
scene.scale_y = 1.f; scene.scale_y = 1.f;
scene.duplicate = cfg::ScreenDuplicateMode::None;
} }
cfg::SCREENRESIZE->enable_window_resize = false; 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."); 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<int *>(&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(); ImGui::EndDisabled();
} }