Update to spice2x-23-06-08
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user