Remove dxwrapper; test scripts focus the game window
The default render size (1835x768) is below Direct3D 7's 2048 limit, so the D3D7 -> D3D9 wrapper and its device-info workaround are no longer needed. The game pauses start-up until its window is active; game-input.ps1 now activates it reliably (Alt + SetForegroundWindow, polled), which dxwrapper had masked. borderless logs the first failed presents. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
df31c9c105
commit
f73c4154ad
9 files changed
+38
-344
No files matched your search
+1
-4
@@ -17,7 +17,6 @@ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
|||||||
add_compile_definitions(WIN32_LEAN_AND_MEAN NOMINMAX _CRT_SECURE_NO_WARNINGS)
|
add_compile_definitions(WIN32_LEAN_AND_MEAN NOMINMAX _CRT_SECURE_NO_WARNINGS)
|
||||||
|
|
||||||
include(cmake/Detours.cmake)
|
include(cmake/Detours.cmake)
|
||||||
include(cmake/DxWrapper.cmake)
|
|
||||||
|
|
||||||
set(SACRED_RE_CXX_FLAGS /W4 /permissive- /utf-8)
|
set(SACRED_RE_CXX_FLAGS /W4 /permissive- /utf-8)
|
||||||
|
|
||||||
@@ -33,12 +32,10 @@ add_library(sacred_re SHARED
|
|||||||
src/game/engine/cmdline.cpp
|
src/game/engine/cmdline.cpp
|
||||||
src/mods/borderless.cpp
|
src/mods/borderless.cpp
|
||||||
src/mods/widescreen.cpp
|
src/mods/widescreen.cpp
|
||||||
src/mods/dxwrapper.cpp
|
|
||||||
)
|
)
|
||||||
target_include_directories(sacred_re PRIVATE src)
|
target_include_directories(sacred_re PRIVATE src)
|
||||||
target_compile_options(sacred_re PRIVATE ${SACRED_RE_CXX_FLAGS})
|
target_compile_options(sacred_re PRIVATE ${SACRED_RE_CXX_FLAGS})
|
||||||
target_link_libraries(sacred_re PRIVATE detours ddraw)
|
target_link_libraries(sacred_re PRIVATE detours)
|
||||||
sacred_re_install_dxwrapper(sacred_re)
|
|
||||||
|
|
||||||
# --- sacred_re.exe: launches sacred.exe with sacred_re.dll injected ----------
|
# --- sacred_re.exe: launches sacred.exe with sacred_re.dll injected ----------
|
||||||
add_executable(sacred_re_launcher WIN32 src/launcher/main.cpp)
|
add_executable(sacred_re_launcher WIN32 src/launcher/main.cpp)
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
# dxwrapper (zlib; github.com/elishacloud/dxwrapper): translates the game's
|
|
||||||
# DirectDraw 7 / Direct3D 7 to Direct3D 9, lifting D3D7's 2048x2048 render
|
|
||||||
# target limit. Pinned release, verified by hash; installed next to
|
|
||||||
# sacred_re.dll in dxwrapper/ and loaded by src/mods/dxwrapper.cpp, so the
|
|
||||||
# game folder stays untouched.
|
|
||||||
include(FetchContent)
|
|
||||||
|
|
||||||
# Some CMake builds (e.g. WinLibs/MinGW) ship curl without a CA store, so
|
|
||||||
# HTTPS downloads fail certificate verification. Fall back to Git for
|
|
||||||
# Windows' bundle when nothing else is configured.
|
|
||||||
if(NOT CMAKE_TLS_CAINFO AND NOT DEFINED ENV{SSL_CERT_FILE})
|
|
||||||
file(TO_CMAKE_PATH "$ENV{ProgramFiles}" _program_files)
|
|
||||||
foreach(_bundle "${_program_files}/Git/mingw64/etc/ssl/certs/ca-bundle.crt"
|
|
||||||
"${_program_files}/Git/mingw64/ssl/certs/ca-bundle.crt")
|
|
||||||
if(EXISTS "${_bundle}")
|
|
||||||
set(CMAKE_TLS_CAINFO "${_bundle}")
|
|
||||||
break()
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
FetchContent_Declare(dxwrapper_bin
|
|
||||||
URL https://github.com/elishacloud/dxwrapper/releases/download/v1.8.8600.25/dxwrapper.zip
|
|
||||||
URL_HASH SHA256=3894368ebce69f348d08e189c2f0818c49aa3b18ad01e06348743bf6a29af97a
|
|
||||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
|
||||||
)
|
|
||||||
FetchContent_MakeAvailable(dxwrapper_bin)
|
|
||||||
|
|
||||||
function(sacred_re_install_dxwrapper target)
|
|
||||||
set(_dest "$<TARGET_FILE_DIR:${target}>/dxwrapper")
|
|
||||||
add_custom_command(TARGET ${target} POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${_dest}"
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
||||||
"${dxwrapper_bin_SOURCE_DIR}/Stub/ddraw.dll"
|
|
||||||
"${dxwrapper_bin_SOURCE_DIR}/dxwrapper.dll"
|
|
||||||
"${dxwrapper_bin_SOURCE_DIR}/License.txt"
|
|
||||||
"${CMAKE_SOURCE_DIR}/config/dxwrapper.ini"
|
|
||||||
"${_dest}"
|
|
||||||
VERBATIM)
|
|
||||||
endfunction()
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
;; sacred_re: dxwrapper settings (copied next to dxwrapper.dll at build time).
|
|
||||||
;; Only change from the release defaults: Dd7to9 = 1 (DirectDraw/D3D7 -> D3D9).
|
|
||||||
;; Config file for DirectX DLL Wrapper
|
|
||||||
;;
|
|
||||||
;; For details, see: https://github.com/elishacloud/dxwrapper/wiki/Configuration
|
|
||||||
;;
|
|
||||||
[General]
|
|
||||||
RealDllPath = AUTO
|
|
||||||
WrapperMode = AUTO
|
|
||||||
LoadCustomDllPath =
|
|
||||||
ExcludeProcess =
|
|
||||||
IncludeProcess =
|
|
||||||
RunProcess =
|
|
||||||
WaitForProcess = 0
|
|
||||||
DisableLogging = 0
|
|
||||||
|
|
||||||
[Plugins]
|
|
||||||
LoadPlugins = 0
|
|
||||||
LoadFromScriptsOnly = 0
|
|
||||||
|
|
||||||
[Compatibility]
|
|
||||||
Dd7to9 = 1
|
|
||||||
D3d8to9 = 0
|
|
||||||
D3d9to9Ex = 0
|
|
||||||
D3d9on12 = 0
|
|
||||||
DDrawCompat = 0
|
|
||||||
Dinputto8 = 0
|
|
||||||
DisableGameUX = 0
|
|
||||||
EnableDdrawWrapper = 0
|
|
||||||
EnableD3d9Wrapper = 0
|
|
||||||
EnableDinput8Wrapper = 0
|
|
||||||
EnableDsoundWrapper = 0
|
|
||||||
DisableGDIGammaRamp = 0
|
|
||||||
EnableOpenDialogHook = 0
|
|
||||||
WinVersionLie = off
|
|
||||||
WinVersionLieSP = 0
|
|
||||||
ForceKeyboardLayout = 0
|
|
||||||
FixPerfCounterUptime = 0
|
|
||||||
HandleExceptions = 0
|
|
||||||
SingleProcAffinity = 0
|
|
||||||
ProcAffinityMask = 0
|
|
||||||
|
|
||||||
[DDrawCompat]
|
|
||||||
DDrawCompat20 = 0
|
|
||||||
DDrawCompat21 = 0
|
|
||||||
DDrawCompat32 = 0
|
|
||||||
DDrawCompatDisableGDIHook = 0
|
|
||||||
DDrawCompatNoProcAffinity = 0
|
|
||||||
|
|
||||||
[ddraw]
|
|
||||||
DdrawOverrideBitMode = 0
|
|
||||||
DdrawUseDirect3D9Caps = 0
|
|
||||||
|
|
||||||
[Dd7to9]
|
|
||||||
DdrawAutoFrameSkip = 0
|
|
||||||
DdrawEmulateSurface = 0
|
|
||||||
DdrawEmulateLock = 0
|
|
||||||
DdrawUseShadowSurface = 0
|
|
||||||
DdrawKeepAllInterfaceCache = 0
|
|
||||||
DdrawAllowMultiSampling = 0
|
|
||||||
DdrawForceMipMapAutoGen = 0
|
|
||||||
DdrawClampVertexZDepth = 0
|
|
||||||
DdrawEnableByteAlignment = 0
|
|
||||||
DdrawFixByteAlignment = 0
|
|
||||||
DdrawIntroVideoFix = 0
|
|
||||||
DdrawFilterActivateApp = 0
|
|
||||||
DdrawRemoveScanlines = 0
|
|
||||||
DdrawRemoveInterlacing = 0
|
|
||||||
DdrawReadFromGDI = 0
|
|
||||||
DdrawWriteToGDI = 0
|
|
||||||
DdrawLimitTextureFormats = 0
|
|
||||||
DdrawLimitDisplayModeCount = 0
|
|
||||||
DdrawCustomWidth = 0
|
|
||||||
DdrawCustomHeight = 0
|
|
||||||
DdrawLinearTextureFilter = 0
|
|
||||||
DdrawUseNativeResolution = 0
|
|
||||||
DdrawOverrideWidth = 0
|
|
||||||
DdrawOverrideHeight = 0
|
|
||||||
DdrawOverrideStencilFormat = 0
|
|
||||||
DdrawIntegerScalingClamp = 0
|
|
||||||
DdrawMaintainAspectRatio = 0
|
|
||||||
|
|
||||||
[d3d9]
|
|
||||||
AnisotropicFiltering = 0
|
|
||||||
AntiAliasing = 0
|
|
||||||
EnableMultisamplingATOC = 0
|
|
||||||
EnvironmentCubeMapFix = 0
|
|
||||||
ForceMipMapUsage = 0
|
|
||||||
DepthBiasFactor = 0
|
|
||||||
DepthBiasDropOffValue = 0
|
|
||||||
EnableVSync = 0
|
|
||||||
ForceVsyncMode = 0
|
|
||||||
ShowFPSCounter = 0
|
|
||||||
OverrideRefreshRate = 0
|
|
||||||
LimitRefreshRates = 0
|
|
||||||
LimitDisplayModeCount = 0
|
|
||||||
CustomDisplayWidth = 0
|
|
||||||
CustomDisplayHeight = 0
|
|
||||||
LimitPerFrameFPS = 0
|
|
||||||
EnableWindowMode = 0
|
|
||||||
WindowModeBorder = 0
|
|
||||||
WindowModeGammaShader = 0
|
|
||||||
DisplayBrightness = 0
|
|
||||||
DisplayContrast = 0
|
|
||||||
SetInitialWindowPosition = 0
|
|
||||||
InitialWindowPositionLeft = 0
|
|
||||||
InitialWindowPositionTop = 0
|
|
||||||
FullscreenWindowMode = 0
|
|
||||||
HideWindowFocusChanges = 0
|
|
||||||
EnableCursorClip = 0
|
|
||||||
ForceExclusiveFullscreen = 0
|
|
||||||
ForceMixedVertexProcessing = 0
|
|
||||||
ForceSystemMemVertexCache = 0
|
|
||||||
UseShadowBackbuffer = 0
|
|
||||||
OverrideStencilFormat = 0
|
|
||||||
FlipEx = 0
|
|
||||||
SetSwapEffectShim = 0
|
|
||||||
DisableMaxWindowedMode = 0
|
|
||||||
GraphicsHybridAdapter = 0
|
|
||||||
|
|
||||||
[FullScreen]
|
|
||||||
FullScreen = 0
|
|
||||||
ForceWindowResize = 0
|
|
||||||
WaitForWindowChanges = 0
|
|
||||||
|
|
||||||
[dinput8]
|
|
||||||
DeviceLookupCacheTime = 0
|
|
||||||
FilterNonActiveInput = 0
|
|
||||||
InvertForceDirection = 0
|
|
||||||
FixHighFrequencyMouse = 0
|
|
||||||
MouseMovementFactor = 0
|
|
||||||
MouseMovementFactorX = 0
|
|
||||||
MouseMovementFactorY = 0
|
|
||||||
MouseMovementPadding = 0
|
|
||||||
MouseMovementPaddingX = 0
|
|
||||||
MouseMovementPaddingY = 0
|
|
||||||
|
|
||||||
[dsound]
|
|
||||||
Num2DBuffers = 0
|
|
||||||
Num3DBuffers = 0
|
|
||||||
ForceCertification = 0
|
|
||||||
ForceExclusiveMode = 0
|
|
||||||
ForceSoftwareMixing = 0
|
|
||||||
ForceHardwareMixing = 0
|
|
||||||
ForceHQ3DSoftMixing = 0
|
|
||||||
ForceNonStaticBuffers = 0
|
|
||||||
ForceVoiceManagement = 0
|
|
||||||
ForcePrimaryBufferFormat = 0
|
|
||||||
PrimaryBufferBits = 16
|
|
||||||
PrimaryBufferSamples = 44100
|
|
||||||
PrimaryBufferChannels = 2
|
|
||||||
AudioClipDetection = 0
|
|
||||||
+6
-3
@@ -76,9 +76,12 @@ presents only that area, scaled to the monitor.
|
|||||||
Windows' D3D7 runtime refuses `IDirect3D7::CreateDevice` on any render
|
Windows' D3D7 runtime refuses `IDirect3D7::CreateDevice` on any render
|
||||||
target wider or taller than 2048 (`DDERR_INVALIDOBJECT`, 0x88760082),
|
target wider or taller than 2048 (`DDERR_INVALIDOBJECT`, 0x88760082),
|
||||||
measured with a standalone test: 2048x1440 works, 2049x1440 / 2560x1080 /
|
measured with a standalone test: 2048x1440 works, 2049x1440 / 2560x1080 /
|
||||||
3440x1440 fail. Native ultrawide therefore needs dxwrapper (`Dd7to9`,
|
3440x1440 fail. The default render size (768 high, e.g. 1835x768) stays
|
||||||
D3D7 -> D3D9), see `src/mods/dxwrapper.cpp`; without it the render size is
|
below it; larger sizes are clamped to 2048. (A D3D7 -> D3D9 wrapper,
|
||||||
clamped to 2048.
|
dxwrapper, lifted the limit but was dropped again in commit history once the
|
||||||
|
render size no longer needed it; it also required fixing the device info GUID
|
||||||
|
pointer at +4 of SetDisplayMode's first argument, which its enumeration left
|
||||||
|
invalid.)
|
||||||
|
|
||||||
## Renderer
|
## Renderer
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
|
|
||||||
#include "game/engine/input.h"
|
#include "game/engine/input.h"
|
||||||
#include "game/render/dx_driver7.h"
|
#include "game/render/dx_driver7.h"
|
||||||
#include "mods/dxwrapper.h"
|
|
||||||
#include "mods/widescreen.h"
|
#include "mods/widescreen.h"
|
||||||
#include "re/config.h"
|
#include "re/config.h"
|
||||||
#include "game/addresses.h"
|
#include "game/addresses.h"
|
||||||
@@ -168,7 +167,6 @@ RE_HOOK(addr::MainWindowProc, MainWindowProc);
|
|||||||
|
|
||||||
int __fastcall DxDriver7_SetDisplayMode(DxDriver7* self, void* edx, void* deviceCaps, const DxDisplayMode* mode,
|
int __fastcall DxDriver7_SetDisplayMode(DxDriver7* self, void* edx, void* deviceCaps, const DxDisplayMode* mode,
|
||||||
uint32_t unknown) {
|
uint32_t unknown) {
|
||||||
mods::dxwrapper::FixDeviceInfo(deviceCaps);
|
|
||||||
if (!Enabled()) {
|
if (!Enabled()) {
|
||||||
return DxDriver7_SetDisplayMode_original(self, edx, deviceCaps, mode, unknown);
|
return DxDriver7_SetDisplayMode_original(self, edx, deviceCaps, mode, unknown);
|
||||||
}
|
}
|
||||||
@@ -197,7 +195,14 @@ int __fastcall DxDriver7_Flip(DxDriver7* self, void* edx) {
|
|||||||
self->blitSource = {0, 0, layout.gameWidth, layout.gameHeight};
|
self->blitSource = {0, 0, layout.gameWidth, layout.gameHeight};
|
||||||
self->blitDest = layout.screen;
|
self->blitDest = layout.screen;
|
||||||
}
|
}
|
||||||
return DxDriver7_Flip_original(self, edx);
|
const int result = DxDriver7_Flip_original(self, edx);
|
||||||
|
static std::atomic<int> failures = 0;
|
||||||
|
if (result != 0 && failures++ < 5) {
|
||||||
|
re::Log("borderless: present failed (0x%08x), source %ldx%ld -> dest (%ld,%ld)-(%ld,%ld)",
|
||||||
|
static_cast<unsigned>(result), self->blitSource.right, self->blitSource.bottom, self->blitDest.left,
|
||||||
|
self->blitDest.top, self->blitDest.right, self->blitDest.bottom);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __cdecl GetMouseClientPos(HWND window, POINT* position) {
|
void __cdecl GetMouseClientPos(HWND window, POINT* position) {
|
||||||
|
|||||||
@@ -1,116 +0,0 @@
|
|||||||
// Route the game's DirectDraw 7 / Direct3D 7 through dxwrapper (Dd7to9:
|
|
||||||
// translation to Direct3D 9). Windows' own D3D7 runtime cannot render to
|
|
||||||
// surfaces larger than 2048x2048, which the widescreen mod needs.
|
|
||||||
//
|
|
||||||
// The build puts dxwrapper's ddraw.dll stub, dxwrapper.dll and our
|
|
||||||
// config/dxwrapper.ini into dxwrapper/ next to sacred_re.dll; the game folder
|
|
||||||
// is not touched. sacred.exe imports three functions from DDRAW.dll; we hook
|
|
||||||
// them and forward to the wrapper, which is loaded on the first call (never
|
|
||||||
// from DllMain). Calls made while the wrapper is running (it may use the real
|
|
||||||
// DirectDraw itself) go to the original functions.
|
|
||||||
//
|
|
||||||
// sacred_re.ini:
|
|
||||||
// [renderer]
|
|
||||||
// DxWrapper=1 ; 0 = Windows' DirectDraw (render size limited to 2048)
|
|
||||||
|
|
||||||
#include "mods/dxwrapper.h"
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <ddraw.h>
|
|
||||||
|
|
||||||
#include "re/config.h"
|
|
||||||
#include "re/hook.h"
|
|
||||||
#include "re/log.h"
|
|
||||||
|
|
||||||
namespace mods::dxwrapper {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
HMODULE g_wrapper = nullptr;
|
|
||||||
bool g_loadAttempted = false;
|
|
||||||
thread_local int g_insideWrapper = 0;
|
|
||||||
|
|
||||||
std::wstring WrapperPath() {
|
|
||||||
return re::ModuleDirectory() + L"dxwrapper\\ddraw.dll";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Enabled() {
|
|
||||||
return re::ConfigInt("renderer", "DxWrapper", 1) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
FARPROC WrapperFunction(const char* name) {
|
|
||||||
if (!g_loadAttempted) {
|
|
||||||
g_loadAttempted = true;
|
|
||||||
const std::wstring path = WrapperPath();
|
|
||||||
g_wrapper = LoadLibraryW(path.c_str());
|
|
||||||
if (g_wrapper) {
|
|
||||||
re::Log("dxwrapper: loaded %ls", path.c_str());
|
|
||||||
} else {
|
|
||||||
re::Log("dxwrapper: could not load %ls (error %lu), using Windows' DirectDraw", path.c_str(),
|
|
||||||
GetLastError());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return g_wrapper ? GetProcAddress(g_wrapper, name) : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calls `function` from the wrapper if possible, else `original`.
|
|
||||||
template <typename Function, typename... Args>
|
|
||||||
HRESULT Forward(const char* name, Function original, Args... args) {
|
|
||||||
if (g_insideWrapper == 0 && Enabled()) {
|
|
||||||
if (auto wrapped = reinterpret_cast<Function>(WrapperFunction(name))) {
|
|
||||||
++g_insideWrapper;
|
|
||||||
const HRESULT result = wrapped(args...);
|
|
||||||
--g_insideWrapper;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return original(args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
bool IsActive() {
|
|
||||||
if (!Enabled()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (g_loadAttempted) {
|
|
||||||
return g_wrapper != nullptr;
|
|
||||||
}
|
|
||||||
return GetFileAttributesW(WrapperPath().c_str()) != INVALID_FILE_ATTRIBUTES;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FixDeviceInfo(void* deviceInfo) {
|
|
||||||
auto* bytes = static_cast<uint8_t*>(deviceInfo);
|
|
||||||
const uint32_t guidAddress = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(bytes + 0x3f4));
|
|
||||||
uint32_t guidPointer;
|
|
||||||
memcpy(&guidPointer, bytes + 4, 4);
|
|
||||||
if (guidPointer != guidAddress) {
|
|
||||||
re::Log("dxwrapper: device info GUID pointer was 0x%08x, set to 0x%08x", guidPointer, guidAddress);
|
|
||||||
memcpy(bytes + 4, &guidAddress, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT WINAPI DirectDrawCreateExViaWrapper(GUID* guid, LPVOID* directDraw, REFIID iid, IUnknown* outer);
|
|
||||||
HRESULT WINAPI DirectDrawCreateViaWrapper(GUID* guid, LPDIRECTDRAW* directDraw, IUnknown* outer);
|
|
||||||
HRESULT WINAPI DirectDrawEnumerateExAViaWrapper(LPDDENUMCALLBACKEXA callback, LPVOID context, DWORD flags);
|
|
||||||
|
|
||||||
RE_HOOK_API(DirectDrawCreateEx, DirectDrawCreateExViaWrapper);
|
|
||||||
RE_HOOK_API(DirectDrawCreate, DirectDrawCreateViaWrapper);
|
|
||||||
RE_HOOK_API(DirectDrawEnumerateExA, DirectDrawEnumerateExAViaWrapper);
|
|
||||||
|
|
||||||
HRESULT WINAPI DirectDrawCreateExViaWrapper(GUID* guid, LPVOID* directDraw, REFIID iid, IUnknown* outer) {
|
|
||||||
return Forward("DirectDrawCreateEx", DirectDrawCreateExViaWrapper_original, guid, directDraw, iid, outer);
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT WINAPI DirectDrawCreateViaWrapper(GUID* guid, LPDIRECTDRAW* directDraw, IUnknown* outer) {
|
|
||||||
return Forward("DirectDrawCreate", DirectDrawCreateViaWrapper_original, guid, directDraw, outer);
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT WINAPI DirectDrawEnumerateExAViaWrapper(LPDDENUMCALLBACKEXA callback, LPVOID context, DWORD flags) {
|
|
||||||
return Forward("DirectDrawEnumerateExA", DirectDrawEnumerateExAViaWrapper_original, callback, context, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace mods::dxwrapper
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace mods::dxwrapper {
|
|
||||||
|
|
||||||
// True when the game's DirectDraw calls go to dxwrapper (Direct3D 9), which
|
|
||||||
// has no 2048x2048 render target limit.
|
|
||||||
bool IsActive();
|
|
||||||
|
|
||||||
// The device info the game passes to DxDriver7::SetDisplayMode keeps a pointer
|
|
||||||
// to its own device GUID at +4 (the GUID itself is at +0x3f4); the game uses
|
|
||||||
// it for EnumZBufferFormats. Under dxwrapper the game's device enumeration
|
|
||||||
// leaves garbage there (0x3c0) and dxwrapper crashes dereferencing it.
|
|
||||||
// Restores the pointer Windows' DirectDraw would have produced.
|
|
||||||
void FixDeviceInfo(void* deviceInfo);
|
|
||||||
|
|
||||||
} // namespace mods::dxwrapper
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// Widescreen: render the world 1:1 at the monitor's resolution, showing more
|
// Widescreen: show more of the world horizontally on wide monitors while
|
||||||
// of it, instead of scaling a 1024x768 image.
|
// everything keeps its original on-screen size.
|
||||||
//
|
//
|
||||||
// The world view sizes itself from zoom * 1024.0 / 768.0 (float constants that
|
// The world view sizes itself from zoom * 1024.0 / 768.0 (float constants that
|
||||||
// the UI also reads) and projects 3D models with an ortho camera of
|
// the UI also reads) and projects 3D models with an ortho camera of
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
// ; 0 = monitor height, i.e. native 1:1 (everything smaller)
|
// ; 0 = monitor height, i.e. native 1:1 (everything smaller)
|
||||||
// Width=0 ; 0 = Height * monitor aspect ratio
|
// Width=0 ; 0 = Height * monitor aspect ratio
|
||||||
//
|
//
|
||||||
// Windows' Direct3D 7 limits the render size to 2048x2048 unless the dxwrapper
|
// Windows' Direct3D 7 cannot render to targets larger than 2048x2048, so the
|
||||||
// mod (Direct3D 9) is active; the borderless mod centres a smaller image 1:1.
|
// render size is clamped to that (only reachable with Height=0 / large Width).
|
||||||
//
|
//
|
||||||
// Experimental: the UI is still drawn at the top-left 1024x768, and creatures
|
// Experimental: the UI is still drawn at the top-left 1024x768, and creatures
|
||||||
// are only active within the original distance.
|
// are only active within the original distance.
|
||||||
@@ -32,7 +32,6 @@
|
|||||||
|
|
||||||
#include "game/addresses.h"
|
#include "game/addresses.h"
|
||||||
#include "game/ui/ui_manager.h"
|
#include "game/ui/ui_manager.h"
|
||||||
#include "mods/dxwrapper.h"
|
|
||||||
#include "re/config.h"
|
#include "re/config.h"
|
||||||
#include "re/hook.h"
|
#include "re/hook.h"
|
||||||
#include "re/log.h"
|
#include "re/log.h"
|
||||||
@@ -246,7 +245,7 @@ void ApplyRenderSize(game::DxDisplayMode& mode, HWND window) {
|
|||||||
// wider or taller than 2048 pixels (CreateDevice fails with
|
// wider or taller than 2048 pixels (CreateDevice fails with
|
||||||
// DDERR_INVALIDOBJECT); anything larger needs a different renderer.
|
// DDERR_INVALIDOBJECT); anything larger needs a different renderer.
|
||||||
constexpr int kMaxD3D7Surface = 2048;
|
constexpr int kMaxD3D7Surface = 2048;
|
||||||
if (!mods::dxwrapper::IsActive() && (width > kMaxD3D7Surface || height > kMaxD3D7Surface)) {
|
if (width > kMaxD3D7Surface || height > kMaxD3D7Surface) {
|
||||||
re::Log("widescreen: %dx%d exceeds the Direct3D 7 limit, clamping to %d", width, height, kMaxD3D7Surface);
|
re::Log("widescreen: %dx%d exceeds the Direct3D 7 limit, clamping to %d", width, height, kMaxD3D7Surface);
|
||||||
width = std::min(width, kMaxD3D7Surface);
|
width = std::min(width, kMaxD3D7Surface);
|
||||||
height = std::min(height, kMaxD3D7Surface);
|
height = std::min(height, kMaxD3D7Surface);
|
||||||
|
|||||||
+18
-4
@@ -19,13 +19,27 @@ Add-Type -Namespace SacredRe -Name Input -MemberDefinition @'
|
|||||||
|
|
||||||
$script:Root = Split-Path $PSScriptRoot
|
$script:Root = Split-Path $PSScriptRoot
|
||||||
|
|
||||||
|
# The game pauses its start-up until its window is active, and Windows does
|
||||||
|
# not hand the foreground to a window started from a background process; a
|
||||||
|
# synthetic Alt press lifts that restriction for SetForegroundWindow.
|
||||||
|
function Focus-Sacred($Game) {
|
||||||
|
$Game.Refresh()
|
||||||
|
if ($Game.MainWindowHandle -eq [IntPtr]::Zero) { return $false }
|
||||||
|
[SacredRe.Input]::keybd_event(0x12, 0, 0, [UIntPtr]::Zero)
|
||||||
|
[SacredRe.Input]::keybd_event(0x12, 0, 2, [UIntPtr]::Zero)
|
||||||
|
[SacredRe.Input]::SetForegroundWindow($Game.MainWindowHandle)
|
||||||
|
}
|
||||||
|
|
||||||
function Start-Sacred([string]$Arguments = "log", [int]$WaitSeconds = 18) {
|
function Start-Sacred([string]$Arguments = "log", [int]$WaitSeconds = 18) {
|
||||||
if (Get-Process sacred -ErrorAction SilentlyContinue) { throw "sacred.exe is already running" }
|
if (Get-Process sacred -ErrorAction SilentlyContinue) { throw "sacred.exe is already running" }
|
||||||
$null = Start-Process (Join-Path $script:Root "build\x86-debug\sacred_re.exe") -ArgumentList $Arguments
|
$null = Start-Process (Join-Path $script:Root "build\x86-debug\sacred_re.exe") -ArgumentList $Arguments
|
||||||
Start-Sleep $WaitSeconds
|
$game = $null
|
||||||
$game = Get-Process sacred -ErrorAction SilentlyContinue | Select-Object -First 1
|
for ($i = 0; $i -lt $WaitSeconds * 4; $i++) {
|
||||||
if (-not $game) { throw "sacred.exe did not start (or crashed)" }
|
Start-Sleep -Milliseconds 250
|
||||||
[SacredRe.Input]::SetForegroundWindow($game.MainWindowHandle) | Out-Null
|
if (-not $game) { $game = Get-Process sacred -ErrorAction SilentlyContinue | Select-Object -First 1 }
|
||||||
|
if ($game) { Focus-Sacred $game | Out-Null }
|
||||||
|
}
|
||||||
|
if (-not $game -or $game.HasExited) { throw "sacred.exe did not start (or crashed)" }
|
||||||
$game
|
$game
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user