- 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>
103 lines
4.7 KiB
Markdown
103 lines
4.7 KiB
Markdown
# 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:
|
|
|
|
1. clear (D3D device `+0x28`)
|
|
2. updates: `0x401660`, `0x640b50`, `0x634210`, weather `0x417e50`/`0x41a4d0`
|
|
3. world: `view->vf14(device)` where `view = engine[+8 + idx*4]` (cWorldView0)
|
|
4. UI: `0x756820()->0x7587b0(device)`, debug overlays `0x60f3e0`/`0x60f500`
|
|
5. 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 ±267*zoom, y ±200*zoom, 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. Native ultrawide therefore needs dxwrapper (`Dd7to9`,
|
|
D3D7 -> D3D9), see `src/mods/dxwrapper.cpp`; without it the render size is
|
|
clamped to 2048.
|
|
|
|
## 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)
|
|
|
|
- `0x00613710` engine capture (save-game thumbnail), `0x006483f0` TGA writer
|
|
- `0x0060e3f0` GDI BitBlt of a 1024x768 bitmap (startup/movie path)
|
|
- `0x00627260` name/HP labels while Alt is held (no constants, uses view)
|
|
|
|
## Open questions
|
|
|
|
- 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 `+0x96ad0` with
|
|
capacity 0x200) - do they overflow at 3440x1440 (47 columns x 54 rows)?
|
|
- Mouse picking (screen -> world).
|