- docs/widescreen.md: render-thread frame, cWorldView0 layout and methods, view size = zoom * 1024.0/768.0 float constants and all their users, ortho projection extents, open questions (activity radius, buffers). - tools: find-imm (immediate/regex instruction search), rtti (vtables via MSVC RTTI), decompile.ps1 + Ghidra scripts for a persistent project; ApplyRtti recovers 410 vtables / ~1200 functions Ghidra misses. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
82 lines
3.6 KiB
Markdown
82 lines
3.6 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`.
|
|
|
|
## 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).
|