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>
6.1 KiB
Widescreen: how the game sizes its view
Goal: render the world 1:1 at the monitor's native resolution, showing more of the world instead of scaling the 1024x768 image. Render and activity (animation/AI) distance must grow with it. UI keeps its 1024x768 layout.
Frame (render thread)
cEngine::renderThread loop, 0x0060e3f0, per frame:
- clear (D3D device
+0x28) - updates:
0x401660,0x640b50,0x634210, weather0x417e50/0x41a4d0 - world:
view->vf14(device)whereview = engine[+8 + idx*4](cWorldView0) - UI:
0x756820()->0x7587b0(device), debug overlays0x60f3e0/0x60f500 - FPS overlay
0x60aa90,DxDriver7::Flip
Skipped entirely while g_appFlags & 0x20000 (app inactive).
World view (cWorldView0, vtable 0x008900f8)
| Offset | Meaning |
|---|---|
+0x14/+0x18 |
camera position (world pixels) |
+0x1c/+0x20 |
requested camera position (scroll target) |
+0xb60 |
zoom (float, clamped to 0.5 .. 2.0) |
+0x96ab0 |
view width = zoom * 1024.0 |
+0x96ab4 |
view height = zoom * 768.0 |
+0x96ac0 |
extra rows (4) |
+0x96ac8 |
columns = width/96 + 12 |
+0x96acc |
rows = height/48 + 24 |
Functions:
| Address | Name | Notes |
|---|---|---|
0x00624ae0 |
cWorldView0::SetupView |
computes the size fields above from zoom and the float constants 1024.0 (0x0088e6f4) and 768.0 (0x00890040); tile corner offsets ±48.2/zoom, ±24.2/zoom |
0x006322b0 |
cWorldView0::Render (vf14) |
iso tile grid: tiles 96x48, two staggered half-rows per row (0x62b000), first tile = camera - (width/192, height/96) |
0x0062a730 |
cWorldView0::UpdateCamera (vf0c) |
scroll blocking against sector edges uses width/2, height/2 |
0x00628210 |
cWorldView0::SetZoom |
clamps zoom, sets the ortho projection for 3D models: x ±267zoom, y ±200zoom, z -600..2500, then calls SetupView |
0x00623c40 |
world -> screen projection | x * 1024.0 / (2/P00), y * 768.0 / (2/P11) |
0x006426a0 |
build ortho matrix | (l, r, b, t, n, f) |
All tile/screen positions are pre-transformed (FVF 0x1c4: XYZRHW, diffuse,
specular, tex1); 3D models use the ortho projection.
Users of the 1024.0 / 768.0 float constants
World view (should follow the new size): 0x61e5c2, 0x61e5ec, 0x623c82,
0x623c9c, 0x624af2, 0x624b03, 0x628f65, 0x628f8f, 0x629294,
0x6292bc, 0x62b43a, 0x62dc32, 0x62ea2b, 0x62ea5e, 0x62f30d,
0x62f345, 0x630656, 0x63068a, 0x630f3f, 0x630f77 (mostly on-screen
clip tests).
Elsewhere (unknown / UI, leave alone for now): 0x40694a, 0x4ec036,
0x593c25, 0x593c3a, 0x6ccb87, 0x6ce156, 0x758a34, 0x75f79a,
0x75f7b8.
Ortho projection extents (±267 / ±200 pushed as floats)
0x60c1f7, 0x60da54, 0x625039, 0x6283b3, 0x62858d, 0x628d3b.
Other frame producers (laid out for 1024x768: "classic" frames)
| Address | What | Thread |
|---|---|---|
0x00756940 |
cUI_Manager thread loop: main menu (clear, update, BeginScene 0x646f50, UI render 0x7587b0 incl. the menu's 3D scene, EndScene 0x646fd0, Flip) |
own UI thread |
0x006469d0 |
loading screen: GDI BitBlt of bitmap + progress bar + text into the back buffer (fixed 1024x768) | render thread |
0x006a0c60 |
video/intro playback (unexamined) |
The widescreen mod gives these frames a 1024x768 D3D viewport (set at
BeginScene when the scene depth +0x1d8 is 0) and the borderless mod
presents only that area, scaled to the monitor.
Direct3D 7 render target limit
Windows' D3D7 runtime refuses IDirect3D7::CreateDevice on any render
target wider or taller than 2048 (DDERR_INVALIDOBJECT, 0x88760082),
measured with a standalone test: 2048x1440 works, 2049x1440 / 2560x1080 /
3440x1440 fail. The default render size (768 high, e.g. 1835x768) stays
below it; larger sizes are clamped to 2048. (A D3D7 -> D3D9 wrapper,
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
DxDriver7::SetDisplayMode (0x00645390) creates back buffer, z-buffer and
D3D viewport from DxDisplayMode::width/height (hardcoded 1024x768 by
InitGame, 0x00815620, which also calls ChangeDisplaySettings(1024x768)
in fullscreen).
Fixed 1024x768 elsewhere (later)
0x00613710engine capture (save-game thumbnail),0x006483f0TGA writer0x0060e3f0GDI BitBlt of a 1024x768 bitmap (startup/movie path)0x00627260name/HP labels while Alt is held (no constants, uses view)
Render size
Default: 768 world pixels high (the original vertical view), width from the
monitor aspect (3440x1440 -> 1835x768), scaled to the monitor by the
borderless mod. Everything keeps the on-screen size players know; the view
only grows horizontally. [widescreen] Height=0 renders natively 1:1
(everything about half size on a 1440p monitor).
Things that had to follow the render size
- view size / centre / clip floats and their integer immediates (world view)
- tile draw list and ground quad list (fixed 1750 / 1749 entries) moved into an enlarged view object
- 3D ortho extents: world (+-267 x +-200, zoomed and unzoomed) and cGranny (+-512 x +-384, incl. cUI_NetGranny for HUD items)
- the inverse projection
0x623a20(screen -> view) uses 1/1024 and 1/768: game logic (camera follow0x44d9f0) converts world -> screen -> view with the device's current projection; unpatched it sent the camera off-world
Open questions
-
Above ~2300 px render width (between 2304 and 2816) the player is not drawn although monsters are (
cCreature::vf14still called). Not hit at the default size; some per-view limit of ~40 tile columns, not found yet. -
HUD: drawn in the top-left 1024x768 of the render target; 3D belt items use the scaled HUD projection and sit off their slots.
-
Activity radius: which creatures/objects are updated and animated (
cWorld/cSector,0x00603e90= player?,0x005fe060= object by id). -
Fixed-size per-view buffers (e.g.
+0x80e40, 5 vectors at+0x96ad0with capacity 0x200) - do they overflow at 3440x1440 (47 columns x 54 rows)? -
Mouse picking (screen -> world).