- 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>
3.6 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.
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)
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+0x96ad0with capacity 0x200) - do they overflow at 3440x1440 (47 columns x 54 rows)? - Mouse picking (screen -> world).