Widescreen experiment: native render size via dxwrapper, classic menus

- mods/widescreen: redirect the world view's reads of the 1024.0/768.0
  constants and the 3D ortho extents to our variables; render size =
  monitor; relocate the world view's tile draw list (1750 entries, no
  bounds check) into an enlarged object (16384 entries).
- mods/dxwrapper: route DirectDraw through dxwrapper (Dd7to9, D3D9) since
  Windows' D3D7 cannot render to targets larger than 2048; fix the game's
  device info GUID pointer that dxwrapper's enumeration leaves invalid.
  Pinned release fetched by CMake (hash-checked), installed next to the DLL.
- Main menu (UI thread) and loading screen render in a 1024x768 viewport
  and are presented scaled ("classic" layout); in-game uses the full size.
- re/patch: verified code patches (operand redirect, push immediates,
  displacements) and startup hooks; build.ps1/CMake download fixes.

In-game view untested yet; HUD still at the top-left.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
khallaandClaude Opus 5.5 committed 2026-10-14 00:47:03 +02:00
1 parent c8dc689bc6
commit 795fe8f087
19 files changed
+860 -28

No files matched your search

+38 -2
View File
@@ -14,6 +14,10 @@ constexpr uint32_t GetMouseClientPos = 0x0066e500;
constexpr uint32_t MainWindowProc = 0x008122a0;
constexpr uint32_t DxDriver7_SetDisplayMode = 0x00645390;
constexpr uint32_t DxDriver7_Flip = 0x00645f70;
constexpr uint32_t DxDriver7_BeginScene = 0x00646f50;
constexpr uint32_t DxDriver7_LoadingScreen = 0x006469d0; // GDI progress screen, 1024x768
constexpr uint32_t UiManager_ThreadLoop = 0x00756940; // main menu render loop (own thread)
constexpr uint32_t Engine_RenderThreadLoop = 0x0060e3f0; // in-game render loop
constexpr uint32_t WorldView0_SetupView = 0x00624ae0;
constexpr uint32_t WorldView0_SetZoom = 0x00628210;
constexpr uint32_t WorldView0_Render = 0x006322b0;
@@ -39,8 +43,40 @@ constexpr uint32_t kViewHeightUsers[] = {
0x0062ea5e, 0x0062f345, 0x0063068a, 0x00630f77,
};
// push sequences of the 3D models' ortho extents (-267, 267, -200, 200).
constexpr uint32_t kOrthoExtentPushes[] = {
// cWorldView0 is allocated with `push 970F4h; call operator new` here.
constexpr uint32_t kWorldViewAllocSizePush = 0x006101aa;
constexpr uint32_t kWorldViewSize = 0x970f4;
// cWorldView0's tile draw list: entries of 0x98 bytes at +0x3ff2c, count at
// +0x80e3c, room for ~1750 entries and no bounds check (enough for 1024x768
// only). Instructions addressing it by displacement (+0x3ff2c + field):
constexpr uint32_t kTileListOffset = 0x3ff2c;
constexpr uint32_t kTileListEntrySize = 0x98;
constexpr uint32_t kTileListUsers[] = {
0x0062b6d9, 0x0062b6ec, 0x0062b709, 0x0062b730, 0x0062b74b, 0x0062b763, // writer, row renderer 0x62b000
0x0062b777, 0x0062b797, 0x0062b7b7, 0x0062b7d7,
0x0062df47, 0x0062e252, // readers (lea base pointer)
};
// Ortho projection of the 3D models: x -267..267, y -200..200 world units
// span the 1024x768 screen (times zoom). Doubles, read with `fmul qword ptr`.
constexpr uint32_t kOrthoLeftD = 0x0088ee40; // double -267.0
constexpr uint32_t kOrthoRightD = 0x0088ee48; // double 267.0
constexpr uint32_t kOrthoBottomD = 0x0088ee50; // double -200.0
constexpr uint32_t kOrthoTopD = 0x0088ee58; // double 200.0
// World view instructions `fmul st, qword ptr [kOrtho*D]` (zoomed projection),
// four per site, in the order top, bottom, right, left.
constexpr uint32_t kOrthoZoomedUsers[][4] = {
{0x00624fdb, 0x00624ff3, 0x00625001, 0x0062500f},
{0x00628355, 0x0062836d, 0x0062837b, 0x00628389},
{0x0062852f, 0x00628547, 0x00628555, 0x00628563},
{0x00628cd7, 0x00628cef, 0x00628d00, 0x00628d11},
};
// Unzoomed projection pushed as immediates: 4 consecutive `push imm32`
// (5 bytes each) starting here, in the order top, bottom, right, left.
constexpr uint32_t kOrthoPushSequences[] = {
0x0060c1f7, 0x0060da54, 0x00625039, 0x006283b3, 0x0062858d, 0x00628d3b,
};
+14 -1
View File
@@ -34,11 +34,16 @@ struct DxDriver7 {
void* directDraw; // +0xb4 IDirectDraw7*
void* primarySurface; // +0xb8 IDirectDrawSurface7*
void* backBuffer; // +0xbc IDirectDrawSurface7*
uint8_t unknown0c0[0x11c];
uint8_t unknown0c0[0x0c];
void* device; // +0xcc IDirect3DDevice7*
uint8_t unknown0d0[0x108];
int32_t sceneDepth; // +0x1d8 nesting of BeginScene/EndScene
RECT blitSource; // +0x1dc back-buffer rect copied by Flip (windowed)
RECT blitDest; // +0x1ec screen-space destination of that copy
};
static_assert(offsetof(DxDriver7, window) == 0xb0);
static_assert(offsetof(DxDriver7, device) == 0xcc);
static_assert(offsetof(DxDriver7, sceneDepth) == 0x1d8);
static_assert(offsetof(DxDriver7, blitSource) == 0x1dc);
static_assert(offsetof(DxDriver7, blitDest) == 0x1ec);
@@ -55,4 +60,12 @@ int __fastcall DxDriver7_SetDisplayMode(DxDriver7* self, void* edx, void* device
// primary->Blt(blitDest, backBuffer, blitSource) in windowed mode.
int __fastcall DxDriver7_Flip(DxDriver7* self, void* edx);
// sacred.exe 0x00646f50. device->BeginScene() unless already inside a scene
// (counted in sceneDepth). Returns 1.
int __fastcall DxDriver7_BeginScene(DxDriver7* self, void* edx);
// sacred.exe 0x006469d0. Draws the loading screen (bitmap + progress bar +
// text) into the back buffer with GDI at fixed 1024x768 coordinates, then Flip.
void __fastcall DxDriver7_LoadingScreen(DxDriver7* self, void* edx, uint32_t progress, const char* text);
} // namespace game
+10
View File
@@ -0,0 +1,10 @@
#pragma once
namespace game {
// sacred.exe 0x00756940. cUI_Manager's thread body: renders the main menu
// (clear, UI update, BeginScene, UI render 0x7587b0, EndScene, Flip) in a loop
// until the manager is stopped. In-game the UI is drawn by the render thread.
void __fastcall UiManager_ThreadLoop(void* self, void* edx);
} // namespace game