Update to spice2x-23-06-08

This commit is contained in:
[ ]
2023-09-20 02:09:17 +09:00
parent 8957d9d446
commit d03cca1fe2
98 changed files with 21957 additions and 4977 deletions
+55 -8
View File
@@ -401,23 +401,58 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::EnumAdapterModes(
format2s(pMode->Format));
*/
bool modified = false;
auto width = pMode->Width;
auto height = pMode->Height;
auto refresh = pMode->RefreshRate;
if (Mode == 0 && games::iidx::TDJ_MODE) {
log_misc("graphics::d3d9", "overriding mode 0 to 1280x720 @ 120 Hz");
pMode->Width = 1280;
pMode->Height = 720;
pMode->RefreshRate = 120;
if (games::iidx::is_tdj_fhd()) {
log_misc("graphics::d3d9", "overriding mode 0 to 1920x1080 @ 120 Hz (for TDJ FHD)");
pMode->Width = 1920;
pMode->Height = 1080;
pMode->RefreshRate = 120;
modified = true;
} else {
log_misc("graphics::d3d9", "overriding mode 0 to 1280x720 @ 120 Hz (for TDJ HD)");
pMode->Width = 1280;
pMode->Height = 720;
pMode->RefreshRate = 120;
modified = true;
}
}
// For whatever reason, TDJ FHD mode prefers to pick these resolutions over 1080p@120Hz.
// Remove them entirely.
if (!modified && games::iidx::is_tdj_fhd() && refresh == 60) {
if ((width == 1920 && height == 1080) ||
(width == 1280 && height == 720)){
log_misc(
"graphics::d3d9", "removing mode {}, {}x{} @ {}Hz (for TDJ FHD)",
Mode, width, height, refresh);
memset(pMode, 0, sizeof(*pMode));
modified = true;
}
}
// zero out display mode for bad entries
// - skip non-native resolutions
// - skip 75 and 90 Hz entries because LDJ game timing is messed up with it
// (TDJ should be fine as it assumes a fixed 60 Hz timing)
if (width == 1360 || width == 1366 || refresh == 75 || refresh == 90) {
if (!modified && (width == 1360 || width == 1366 || refresh == 75 || refresh == 90)) {
log_misc(
"graphics::d3d9", "removing mode {}, {}x{} @ {}Hz (for LDJ/TDJ)",
Mode, width, height, refresh);
memset(pMode, 0, sizeof(*pMode));
modified = true;
}
if (!modified && !games::iidx::TDJ_MODE && games::iidx::FORCE_720P && (height > 720)) {
log_misc(
"graphics::d3d9", "removing mode {}, {}x{} @ {}Hz (-sp2x-iidxforce720p)",
Mode, width, height, refresh);
memset(pMode, 0, sizeof(*pMode));
modified = true;
}
}
@@ -613,12 +648,20 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::CreateDevice(
if (GRAPHICS_WINDOWED) {
pPresentationParameters->Windowed = true;
pPresentationParameters->FullScreen_RefreshRateInHz = 0;
} else if (GRAPHICS_FORCE_REFRESH > 0) {
log_info("graphics::d3d9", "force refresh rate: {} => {} Hz",
log_info("graphics::d3d9", "force refresh rate: {} => {} Hz (-graphics-force-refresh option)",
pPresentationParameters->FullScreen_RefreshRateInHz,
GRAPHICS_FORCE_REFRESH);
pPresentationParameters->FullScreen_RefreshRateInHz = GRAPHICS_FORCE_REFRESH;
} else if (pPresentationParameters->FullScreen_RefreshRateInHz == 0) {
log_warning(
"graphics::d3d9",
"This game sets FullScreen_RefreshRateInHz to 0, which means it will boot with whatever "
"refresh rate you have set in the desktop. If the game is launching at the wrong Hz, "
"either use -graphics-force-refresh option or change the desktop resolution beforehand.");
}
// force single adapter
@@ -910,7 +953,11 @@ static void graphics_d3d9_ldj_on_present(IDirect3DDevice9 *wrapped_device) {
HRESULT hr = wrapped_device->GetSwapChain(1, &SUB_SWAP_CHAIN);
if (FAILED(hr)) {
log_warning("graphics::d3d9", "failed to acquire sub swap chain, hr={}", FMT_HRESULT(hr));
log_warning(
"graphics::d3d9",
"failed to acquire sub screeen swap chain; "
"this can be ignored if game does not have sub screen, hr={}",
FMT_HRESULT(hr));
return;
}
}
+34 -14
View File
@@ -716,35 +716,55 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
const int rectLeft = 1024;
const int rectTop = 576;
const int w = param.BackBufferWidth;
const int h = param.BackBufferHeight;
D3DLOCKED_RECT rect;
RECT targetRect {
rectLeft, rectTop,
(LONG) (rectLeft+param.BackBufferWidth),
(LONG) (rectTop+param.BackBufferHeight),
rectLeft,
rectTop,
(LONG)(rectLeft + w),
(LONG)(rectTop + h),
};
// stretch to add top/left offset to avoid going negative
topSurface->LockRect(&rect, NULL, D3DLOCK_DONOTWAIT);
auto hr = pReal->StretchRect(backbuffer, nullptr, topSurface,
&targetRect, D3DTEXF_LINEAR);
auto hr = pReal->StretchRect(
backbuffer, nullptr,
topSurface, &targetRect,
D3DTEXF_LINEAR);
if (hr != D3D_OK) {
log_misc("graphics::d3d9", "StretchRect backbuffer failed");
}
topSurface->UnlockRect();
targetRect.left -= cfg::SCREENRESIZE->offset_x;
targetRect.top += cfg::SCREENRESIZE->offset_y;
targetRect.right = -cfg::SCREENRESIZE->offset_x;
targetRect.right += (param.BackBufferWidth+rectLeft) / cfg::SCREENRESIZE->scale_x;
targetRect.bottom = cfg::SCREENRESIZE->offset_y;
targetRect.bottom += (param.BackBufferHeight+rectTop) / cfg::SCREENRESIZE->scale_y;
// do the actual zoom / offset math
if (cfg::SCREENRESIZE->centered) {
targetRect.right = (w + rectLeft) / cfg::SCREENRESIZE->scale_x;
targetRect.bottom = (h + rectTop) / cfg::SCREENRESIZE->scale_y;
const LONG deltaH = ((targetRect.bottom - targetRect.top) - h) / 2;
const LONG deltaW = ((targetRect.right - targetRect.left) - w) / 2;
targetRect.top -= deltaH;
targetRect.bottom -= deltaH;
targetRect.left -= deltaW;
targetRect.right -= deltaW;
} else {
targetRect.left -= cfg::SCREENRESIZE->offset_x;
targetRect.top += cfg::SCREENRESIZE->offset_y;
targetRect.right = -cfg::SCREENRESIZE->offset_x;
targetRect.right += (w + rectLeft) / cfg::SCREENRESIZE->scale_x;
targetRect.bottom = cfg::SCREENRESIZE->offset_y;
targetRect.bottom += (h + rectTop) / cfg::SCREENRESIZE->scale_y;
}
// draw to back buffer
backbuffer->LockRect(&rect, NULL, D3DLOCK_DONOTWAIT);
hr = pReal->StretchRect(topSurface, &targetRect, backbuffer,
nullptr, cfg::SCREENRESIZE->enable_linear_filter ? D3DTEXF_LINEAR : D3DTEXF_NONE);
hr = pReal->StretchRect(
topSurface, &targetRect,
backbuffer, nullptr,
cfg::SCREENRESIZE->enable_linear_filter ? D3DTEXF_LINEAR : D3DTEXF_NONE);
backbuffer->UnlockRect();
if (hr != D3D_OK) {
log_misc("graphics::d3d9", "StretchRect targetRect failed");
}
+55 -17
View File
@@ -10,6 +10,7 @@
#include "avs/game.h"
#include "cfg/icon.h"
#include "cfg/screen_resize.h"
#include "games/ddr/ddr.h"
#include "hooks/graphics/backends/d3d9/d3d9_backend.h"
#include "launcher/shutdown.h"
#include "overlay/overlay.h"
@@ -18,6 +19,7 @@
#include "util/logging.h"
#include "util/fileutils.h"
#include "util/utils.h"
#include "misc/wintouchemu.h"
#include "util/time.h"
struct CaptureData {
@@ -47,8 +49,8 @@ bool GRAPHICS_CAPTURE_CURSOR = false;
bool GRAPHICS_LOG_HRESULT = false;
bool GRAPHICS_SDVX_FORCE_720 = false;
bool GRAPHICS_SHOW_CURSOR = false;
graphics_orientation GRAPHICS_ADJUST_ORIENTATION = ORIENTATION_NORMAL;
bool GRAPHICS_WINDOWED = false;
bool GRAPHICS_ADJUST_ORIENTATION = false;
std::vector<HWND> GRAPHICS_WINDOWS;
UINT GRAPHICS_FORCE_REFRESH = 0;
bool GRAPHICS_FORCE_SINGLE_ADAPTER = false;
@@ -126,6 +128,24 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
}
}
if (wintouchemu::INJECT_MOUSE_AS_WM_TOUCH) {
// drop mouse inputs since only wintouches should be used
switch (uMsg) {
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
return true;
}
}
// window resize
graphics_windowed_wndproc(hWnd, uMsg, wParam, lParam);
// call custom procedures
for (WNDPROC wndProc : WNDPROC_CUSTOM) {
wndProc(hWnd, uMsg, wParam, lParam);
@@ -265,23 +285,35 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
fmt::ptr(lpParam));
// set display orientation
if (GRAPHICS_ADJUST_ORIENTATION) {
if (nHeight > nWidth) {
DEVMODE mode {};
// only do this when the target window is portrait
// (avoid doing this for SDVX subscreen which is in landscape, for example)
if ((nHeight > nWidth) &&
(GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CW ||
GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CCW)) {
DWORD orientation = (GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CW) ? DMDO_90 : DMDO_270;
DEVMODE mode {};
// get display settings
if (EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &mode)) {
log_misc("graphics", "rotating display");
mode.dmPelsWidth = nWidth;
mode.dmPelsHeight = nHeight;
mode.dmDisplayOrientation = DMDO_90;
auto disp_res = ChangeDisplaySettings(&mode, CDS_FULLSCREEN);
if (disp_res != DISP_CHANGE_SUCCESSFUL) {
log_warning("graphics", "failed to change display settings: {}", disp_res);
}
} else {
log_warning("graphics", "failed to get display settings");
// get display settings
if (EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &mode)) {
log_misc("graphics", "auto-rotate: rotating display to DMDO_xx mode {}", orientation);
mode.dmPelsWidth = nWidth;
mode.dmPelsHeight = nHeight;
mode.dmDisplayOrientation = orientation;
if (GRAPHICS_FORCE_REFRESH > 0) {
log_info(
"graphics",
"auto-rotate: force refresh rate: {} => {} Hz",
mode.dmDisplayFrequency,
GRAPHICS_FORCE_REFRESH);
mode.dmDisplayFrequency = GRAPHICS_FORCE_REFRESH;
}
auto disp_res = ChangeDisplaySettings(&mode, CDS_FULLSCREEN);
if (disp_res != DISP_CHANGE_SUCCESSFUL) {
log_warning("graphics", "auto-rotate: failed to change display settings: {}", disp_res);
}
} else {
log_warning("graphics", "auto-rotate: failed to get display settings");
}
}
@@ -328,7 +360,11 @@ static HWND WINAPI CreateWindowExW_hook(DWORD dwExStyle, LPCWSTR lpClassName, LP
// adjust window size to include window decoration
RECT rect {};
SetRect(&rect, 0, 0, 1280, 720);
if (games::ddr::SDMODE) {
SetRect(&rect, 0, 0, 800, 600);
} else {
SetRect(&rect, 0, 0, 1280, 720);
}
AdjustWindowRect(&rect, dwStyle, (hMenu != nullptr));
nWidth = rect.right - rect.left;
@@ -683,6 +719,8 @@ void graphics_hook_window(HWND hWnd, D3DPRESENT_PARAMETERS *pPresentationParamet
if (WNDPROC_ORIG == nullptr) {
WNDPROC_ORIG = reinterpret_cast<WNDPROC>(GetWindowLongPtrA(hWnd, GWLP_WNDPROC));
SetWindowLongPtrA(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc));
overlay::USE_WM_CHAR_FOR_IMGUI_CHAR_INPUT = true;
graphics_capture_initial_window(hWnd);
}
}
+21 -1
View File
@@ -9,18 +9,30 @@
#include "external/toojpeg/toojpeg.h"
// order must match spice2x_AutoOrientation UI enum order
enum graphics_orientation {
ORIENTATION_CW = 0,
ORIENTATION_CCW = 1,
ORIENTATION_NORMAL = 2,
};
// flag settings
extern bool GRAPHICS_CAPTURE_CURSOR;
extern bool GRAPHICS_LOG_HRESULT;
extern bool GRAPHICS_SDVX_FORCE_720;
extern bool GRAPHICS_SHOW_CURSOR;
extern bool GRAPHICS_WINDOWED;
extern bool GRAPHICS_ADJUST_ORIENTATION;
extern graphics_orientation GRAPHICS_ADJUST_ORIENTATION;
extern std::vector<HWND> GRAPHICS_WINDOWS;
extern UINT GRAPHICS_FORCE_REFRESH;
extern bool GRAPHICS_FORCE_SINGLE_ADAPTER;
extern bool GRAPHICS_9_ON_12;
extern std::optional<int> GRAPHICS_WINDOW_STYLE;
extern std::optional<std::string> GRAPHICS_WINDOW_SIZE;
extern std::optional<std::string> GRAPHICS_WINDOW_POS;
extern bool GRAPHICS_WINDOW_ALWAYS_ON_TOP;
// settings
extern std::string GRAPHICS_DEVICEID;
extern std::string GRAPHICS_SCREENSHOT_DIR;
@@ -47,3 +59,11 @@ bool graphics_capture_receive_jpeg(int screen, TooJpeg::WRITE_ONE_BYTE receiver,
uint64_t *timestamp = nullptr,
int *width = nullptr, int *height = nullptr);
std::string graphics_screenshot_genpath();
// graphics_windowed.cpp
void graphics_windowed_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void graphics_capture_initial_window(HWND hWnd);
void graphics_update_window_style(HWND hWnd);
void graphics_update_z_order(HWND hWnd);
void graphics_move_resize_window(HWND hWnd);
bool graphics_window_change_crashes_game();
+431
View File
@@ -0,0 +1,431 @@
#include "graphics.h"
#include "avs/game.h"
#include "cfg/screen_resize.h"
#include "overlay/overlay.h"
#include "util/logging.h"
#include "util/utils.h"
#if 0
#define log_debug(module, format_str, ...) logger::push( \
LOG_FORMAT("M", module, format_str, ## __VA_ARGS__), logger::Style::GREY)
#else
#define log_debug(module, format_str, ...)
#endif
void graphics_load_windowed_parameters();
void graphics_wm_style_changed(HWND hWnd, bool changed);
void graphics_wm_sizing_aspect_ratio(int edge, RECT& rect);
std::optional<int> GRAPHICS_WINDOW_STYLE;
std::optional<std::string> GRAPHICS_WINDOW_SIZE;
std::optional<std::string> GRAPHICS_WINDOW_POS;
bool GRAPHICS_WINDOW_ALWAYS_ON_TOP = false;
// these flags are carefully constructed to ensure maximum compatibility
// (e.g., DDR likes to hang when SetWindowPos is called with certain params)
static const DWORD SETWINDOWPOS_NOOP =
SWP_NOMOVE |
SWP_NOSIZE |
SWP_NOREDRAW |
SWP_NOCOPYBITS |
SWP_NOACTIVATE |
SWP_NOSENDCHANGING |
SWP_DEFERERASE |
SWP_NOZORDER |
SWP_ASYNCWINDOWPOS;
void graphics_capture_initial_window(HWND hWnd) {
if (!GRAPHICS_WINDOWED) {
return;
}
graphics_load_windowed_parameters();
cfg::SCREENRESIZE->init_window_style = GetWindowLong(hWnd, GWL_STYLE);
log_debug("graphics-windowed", "graphics_capture_initial_window called");
RECT rect;
if (!GetClientRect(hWnd, &rect)) {
log_warning(
"graphics",
"graphics_capture_initial_window - GetClientRect failed, GLE: {}",
GetLastError());
return;
}
const int client_w = rect.right - rect.left;
const int client_h = rect.bottom - rect.top;
cfg::SCREENRESIZE->init_client_width = client_w;
cfg::SCREENRESIZE->init_client_height = client_h;
cfg::SCREENRESIZE->init_client_aspect_ratio = (float)client_w / (float)client_h;
log_debug(
"graphics-windowed",
"graphics_capture_initial_window initial window size {}x{}, ratio {}",
client_w, client_h, cfg::SCREENRESIZE->init_client_aspect_ratio);
// ensure frame size is captured
graphics_wm_style_changed(hWnd, false);
// if there was no user-supplied dimension, seed it with the current size
// so that the next resize operation will work
if (cfg::SCREENRESIZE->client_width == 0) {
cfg::SCREENRESIZE->client_width = client_w;
}
if (cfg::SCREENRESIZE->client_height == 0) {
cfg::SCREENRESIZE->client_height = client_h;
}
// apply the config that was loaded from disk
// resize must be done before applying the border
if (cfg::SCREENRESIZE->enable_window_resize) {
log_info(
"graphics-windowed", "change window rect - window offset: {}x{}, client size: {}x{}",
cfg::SCREENRESIZE->window_offset_x,
cfg::SCREENRESIZE->window_offset_y,
cfg::SCREENRESIZE->client_width,
cfg::SCREENRESIZE->client_height);
graphics_move_resize_window(hWnd);
}
// ddr hangs when window frame doesn't have overlapped
if (cfg::SCREENRESIZE->window_decoration != cfg::WindowDecorationMode::Default) {
log_info(
"graphics-windowed", "change window style - decoration: {}",
cfg::SCREENRESIZE->window_decoration);
graphics_update_window_style(hWnd);
}
if (cfg::SCREENRESIZE->window_always_on_top) {
log_info("graphics-windowed", "change window z-order - always on top");
graphics_update_z_order(hWnd);
}
log_debug("graphics-windowed", "graphics_capture_initial_window returned");
}
void graphics_load_windowed_parameters() {
if (!GRAPHICS_WINDOWED) {
return;
}
log_debug("graphics-windowed", "graphics_load_windowed_parameters called");
const auto remove_spaces = [](const char& c) {
return c == ' ';
};
if (GRAPHICS_WINDOW_STYLE.has_value()) {
log_debug(
"graphics-windowed",
"graphics_load_windowed_parameters - load GRAPHICS_WINDOW_STYLE");
cfg::SCREENRESIZE->window_decoration = GRAPHICS_WINDOW_STYLE.value();
}
if (GRAPHICS_WINDOW_SIZE.has_value()) {
log_debug(
"graphics-windowed",
"graphics_load_windowed_parameters - load GRAPHICS_WINDOW_SIZE");
uint32_t w, h;
auto s = GRAPHICS_WINDOW_SIZE.value();
s.erase(std::remove_if(s.begin(), s.end(), remove_spaces), s.end());
if (sscanf(s.c_str(), "%u,%u", &w, &h) == 2) {
cfg::SCREENRESIZE->enable_window_resize = true;
cfg::SCREENRESIZE->client_keep_aspect_ratio = false;
cfg::SCREENRESIZE->client_width = w;
cfg::SCREENRESIZE->client_height = h;
} else {
log_warning("graphics-windowed", "failed to parse -sp2x-windowsize");
}
}
if (GRAPHICS_WINDOW_POS.has_value()) {
log_debug(
"graphics-windowed",
"graphics_load_windowed_parameters - load GRAPHICS_WINDOW_POS");
int32_t x, y;
auto s = GRAPHICS_WINDOW_POS.value();
s.erase(std::remove_if(s.begin(), s.end(), remove_spaces), s.end());
if (sscanf(s.c_str(), "%d,%d", &x, &y) == 2) {
cfg::SCREENRESIZE->enable_window_resize = true;
cfg::SCREENRESIZE->window_offset_x = x;
cfg::SCREENRESIZE->window_offset_y = y;
} else {
log_warning("graphics-windowed", "failed to parse -sp2x-windowpos");
}
}
// only override if true; don't stomp on user setting
if (GRAPHICS_WINDOW_ALWAYS_ON_TOP) {
cfg::SCREENRESIZE->window_always_on_top = true;
}
log_debug("graphics-windowed", "graphics_load_windowed_parameters returned");
}
void graphics_windowed_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (!GRAPHICS_WINDOWED) {
return;
}
switch (uMsg) {
case WM_MOVE: {
log_debug("graphics-windowed", "graphics_windowed_wndproc called with WM_MOVE");
RECT rect;
if (GetWindowRect(hWnd, &rect)) {
cfg::SCREENRESIZE->window_offset_x = rect.left;
cfg::SCREENRESIZE->window_offset_y = rect.top;
}
break;
}
case WM_SIZE: {
log_debug("graphics-windowed", "graphics_windowed_wndproc called with WM_SIZE");
if (wParam == SIZE_MINIMIZED) {
break;
}
RECT rect;
if (GetClientRect(hWnd, &rect)) {
cfg::SCREENRESIZE->client_width = rect.right - rect.left;
cfg::SCREENRESIZE->client_height = rect.bottom - rect.top;
}
break;
}
case WM_SIZING: {
if (cfg::SCREENRESIZE->client_keep_aspect_ratio) {
graphics_wm_sizing_aspect_ratio(
static_cast<int>(wParam), *reinterpret_cast<LPRECT>(lParam));
}
break;
}
case WM_STYLECHANGED: {
graphics_wm_style_changed(hWnd, true);
break;
}
case WM_GETMINMAXINFO: {
if (cfg::SCREENRESIZE->client_keep_aspect_ratio) {
auto info = reinterpret_cast<MINMAXINFO *>(lParam);
info->ptMinTrackSize.y =
cfg::SCREENRESIZE->window_deco_height +
((info->ptMinTrackSize.x - cfg::SCREENRESIZE->window_deco_width) /
cfg::SCREENRESIZE->init_client_aspect_ratio);
}
break;
}
}
}
void graphics_wm_style_changed(HWND hWnd, bool changed) {
log_debug("graphics-windowed", "graphics_wm_style_changed called");
RECT rect;
// ensure the style change takes in effect before doing the calculations
if (changed) {
// ensure client size doesn't change as a result of this
// since SetWindowPos will still send WM_SIZE and WM_MOVE
const auto client_w = cfg::SCREENRESIZE->client_width;
const auto client_h = cfg::SCREENRESIZE->client_height;
const auto flags = SETWINDOWPOS_NOOP | SWP_FRAMECHANGED;
SetWindowPos(
hWnd,
nullptr,
0, 0, 0, 0,
flags);
cfg::SCREENRESIZE->client_width = client_w;
cfg::SCREENRESIZE->client_height = client_h;
}
// get window size with decoration...
if (!GetWindowRect(hWnd, &rect)) {
log_warning(
"graphics",
"graphics_wm_style_changed - GetWindowRect failed, GLE: {}",
GetLastError());
return;
}
const int window_w = rect.right - rect.left;
const int window_h = rect.bottom - rect.top;
// get client area (without decoration)...
if (!GetClientRect(hWnd, &rect)) {
return;
}
const int client_w = rect.right - rect.left;
const int client_h = rect.bottom - rect.top;
// update window decoration size
cfg::SCREENRESIZE->window_deco_width = window_w - client_w;
cfg::SCREENRESIZE->window_deco_height = window_h - client_h;
log_debug(
"graphics-windowed",
"graphics_wm_style_changed updating frame dimensions {}x{}",
cfg::SCREENRESIZE->window_deco_width,
cfg::SCREENRESIZE->window_deco_height);
// adjust window to ensure client area remains the same
if (changed) {
graphics_move_resize_window(hWnd);
}
log_debug("graphics-windowed", "graphics_wm_style_changed returned");
}
void graphics_wm_sizing_aspect_ratio(int edge, RECT& rect) {
log_debug("graphics-windowed", "graphics_wm_sizing_aspect_ratio called");
const auto deco_w = cfg::SCREENRESIZE->window_deco_width;
const auto deco_h = cfg::SCREENRESIZE->window_deco_height;
const LONG desired_w = (rect.right - rect.left) - deco_w;
const LONG desired_h = (rect.bottom - rect.top) - deco_h;
const auto aspect_ratio = cfg::SCREENRESIZE->init_client_aspect_ratio;
// based on http://playtechs.blogspot.com/2007/10/forcing-window-to-maintain-particular.html
switch (edge) {
case WMSZ_BOTTOM:
case WMSZ_TOP: {
const LONG w = deco_w + (desired_h * aspect_ratio);
rect.right = rect.left + w;
break;
}
case WMSZ_LEFT:
case WMSZ_RIGHT: {
const LONG h = deco_h + (desired_w / aspect_ratio);
rect.bottom = rect.top + h;
break;
}
case WMSZ_TOPLEFT:
case WMSZ_TOPRIGHT:
case WMSZ_BOTTOMLEFT:
case WMSZ_BOTTOMRIGHT: {
int w;
int h;
if (desired_h * aspect_ratio < desired_w) {
w = rect.right - rect.left;
h = deco_h + (desired_w / aspect_ratio);
} else {
w = deco_w + (desired_h * aspect_ratio);
h = rect.bottom - rect.top;
}
if (edge == WMSZ_TOPLEFT) {
rect.left = rect.right - w;
rect.top = rect.bottom - h;
} else if (edge == WMSZ_TOPRIGHT) {
rect.right = rect.left + w;
rect.top = rect.bottom - h;
} else if (edge == WMSZ_BOTTOMLEFT) {
rect.left = rect.right - w;
rect.bottom = rect.top + h;
} else if (edge == WMSZ_BOTTOMRIGHT) {
rect.right = rect.left + w;
rect.bottom = rect.top + h;
}
break;
}
default:
break;
}
log_debug("graphics-windowed", "graphics_wm_sizing_aspect_ratio returned");
}
void graphics_update_window_style(HWND hWnd) {
if (!GRAPHICS_WINDOWED) {
return;
}
if (graphics_window_change_crashes_game()) {
return;
}
log_debug("graphics-windowed", "graphics_update_window_style called");
// update frame style
auto style = cfg::SCREENRESIZE->init_window_style;
switch (cfg::SCREENRESIZE->window_decoration) {
case cfg::WindowDecorationMode::Borderless:
style &= ~WS_OVERLAPPEDWINDOW;
break;
case cfg::WindowDecorationMode::ResizableFrame:
style |= WS_OVERLAPPEDWINDOW;
break;
case cfg::WindowDecorationMode::Default:
default:
break;
}
log_debug(
"graphics-windowed",
"graphics_update_window_style - calling SetWindowLong with Mode {}, style 0x{:x}",
static_cast<int>(cfg::SCREENRESIZE->window_decoration),
style);
SetWindowLong(hWnd, GWL_STYLE, style);
// SetWindowPos must be called after SetWindowLong if the frame style changed
// this will be done in WM_STYLECHANGED handler
log_debug("graphics-windowed", "graphics_update_window_style returned");
}
void graphics_update_z_order(HWND hWnd) {
if (!GRAPHICS_WINDOWED) {
return;
}
log_debug("graphics-windowed", "graphics_update_z_order called");
HWND insert_after = nullptr;
if (cfg::SCREENRESIZE->window_always_on_top) {
insert_after = HWND_TOPMOST;
} else {
insert_after = HWND_NOTOPMOST;
}
auto flags = SETWINDOWPOS_NOOP;
flags &= ~SWP_NOZORDER;
SetWindowPos(
hWnd,
insert_after,
0, 0, 0, 0,
flags);
log_debug("graphics-windowed", "graphics_update_z_order returned");
}
void graphics_move_resize_window(HWND hWnd) {
if (!GRAPHICS_WINDOWED) {
return;
}
log_debug("graphics-windowed", "graphics_move_resize_window called");
cfg::SCREENRESIZE->client_width =
CLAMP(cfg::SCREENRESIZE->client_width, 640, 1920 * 8);
cfg::SCREENRESIZE->client_height =
CLAMP(cfg::SCREENRESIZE->client_height, 480, 1080 * 8);
const auto w = cfg::SCREENRESIZE->client_width + cfg::SCREENRESIZE->window_deco_width;
const auto h = cfg::SCREENRESIZE->client_height + cfg::SCREENRESIZE->window_deco_height;
auto flags = SETWINDOWPOS_NOOP;
flags &= ~SWP_NOSIZE;
flags &= ~SWP_NOMOVE;
SetWindowPos(
hWnd,
nullptr,
cfg::SCREENRESIZE->window_offset_x,
cfg::SCREENRESIZE->window_offset_y,
w, h,
flags);
log_debug("graphics-windowed", "graphics_move_resize_window returned");
}
bool graphics_window_change_crashes_game() {
static std::once_flag flag;
static bool result = false;
std::call_once(flag, []() {
// ddr crashes when frame style changes
result = avs::game::is_model("MDX");
if (result) {
log_warning(
"graphics-windowed",
"ignoring changes to window style due to incompatibility with this game");
}
});
return result;
}