Dual-lens Opus review of 7e0c1303 (reports committed under
docs/research/). The law, gate, and vertical application are CONFIRMED
at instruction-byte level against the PDB-paired acclient.exe (the BN
text FPU-elides this whole area); the fix round addresses the findings:
- Blast MUST-FIX 1: real schema migration instead of a hand-edited dev
file. SettingsStore v2->v3: a pre-v3 display.fieldOfView was the
applied vertical FOV in degrees; v3 means retail's m_fGameFOV.
LoadDisplay migrates on read - the untouched old default 60 maps to
the retail default 90; a deliberate other value preserves its visible
16:9 framing (x (16/9 - 0.1)), clamped to the registered [10,160];
the next save stamps v3 and migration never reruns. The dev
settings.json hand-edit was reverted so the migration owns it.
- Blast MUST-FIX 2 / mechanism M2: the Field of View now applies LIVE on
Save (retail: Render::GRPCallback_OnRenderPreferenceChanged @0x0054d999
-> SmartBox::SetDefaultFov). RuntimeSettingsTargets gains the camera
graph and applies through ApplyDisplayWindowState - the update-phase
seam, deliberately NOT the render-phase preview path (the review's
WATCH-3 cull-vs-raster landmine).
- Mechanism M1 -> register row AD-90: retail's divisor aspect runs
through the Render.AspectRatio preference (ComputeAspectForViewport
@0x0054f150, (w/h) x pref x 0.75) - exactly raw w/h at the registered
default, which is what acdream assumes; retail's NaN-through-the-gate
quirk (M3) is folded into the same row as deliberately not reproduced.
- Docs: RetailFieldOfView now cites the decisive vertical proof
(D3DXMatrixPerspectiveFovLH fovy slot @0x0059ab71), the unconditional
SmartBox::RenderNormalMode site, and M4's exact horizontal numbers
(89.0/83.9/80.6 deg); the Config FOV row comment updated to LIVE.
- Blast WATCH 4 disposition: the 15 replay-harness PI/3 constants stay -
they are CAPTURE-TIME camera parameters for recorded fixtures, not
production framing; changing them would invalidate the replays.
Tests: +6 SettingsStore migration facts, +1 live-apply fact.
App suite 4,962/3 skips; UI.Abstractions 922.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
24 KiB
#389 SmartboxFOV — MECHANISM review of commit 7e0c1303
Date: 2026-08-13
Reviewer lens: MECHANISM (is the ported law the law retail actually runs?)
Subject: 7e0c1303 — fix #389: port retail's SmartboxFOV law; retire AD-89 (display slice 1)
Oracle: docs/research/named-retail/acclient_2013_pseudo_c.txt +
docs/research/named-retail/acclient.h, plus byte-level disassembly of the
PDB-paired binary C:\Users\erikn\Downloads\acclient.exe
(check_exe_pdb.py → MATCH, GUID 9e847e2f-777c-4bd9-886c-22256bb87f32,
linker 2013-09-06). Every x87 comparison and division in this area is
FPU-elided or ambiguous in the Binary Ninja pseudo-C, so all polarity and
operand-order claims below are decided from the instruction bytes, not from
BN's rendering. Raw disassembly is in the appendix.
Report only — no files under src/ or tests/ were modified.
Verdict summary
| # | Question | Verdict |
|---|---|---|
| 1 | Formula transcription exact (operand order, 0.1, aspect variable, direct feed) | CONFIRMED, with one qualification: retail's m_ViewportAspectRatio is not raw w/h in general — see M1 |
| 2 | What m_bUseSmartboxFOV == 0 selects; does acdream apply the law where retail uses the fixed branch |
CONFIRMED — no misapplication. Paperdoll/appraisal/char-gen = fixed branch (π/4, byte-verified); portal space = smartbox law, and acdream's portal camera derives from the world projection |
| 3 | Does 0x00453b14 differ from the CreatureMode site |
CONFIRMED (differs, benignly) — it is SmartBox::RenderNormalMode, a different class, with no m_bUseSmartboxFOV gate at all; the arithmetic is byte-identical |
| 4 | Gate is open (0, π), silent keep-previous; SetFOVInternal applies it vertically |
CONFIRMED — open on both ends, return 0 without touching Render::fov; and the value reaches D3DXMatrixPerspectiveFovLH's fovy slot. The port is not inverted. One NaN corner: M3 |
| 5 | 0x00451e6a is the FOV option's setter; [10,160]/default 90 registered |
CONFIRMED — SmartBox::SetDefaultFov, fed by Render::UpdateFromPreferences; range and default byte-verified |
| 6 | Other writers of Render::fov / other SetFOVRad callers the port ignores |
CONFIRMED (none ignored) — only 3 SetFOVRad call sites exist; the one other FOV writer (Render::set_vdst, the teleport override) is already ported in TeleportViewPlaneController, and my byte-decode vindicates its 2·atan(1/d) against BN's misleading __fpatan(arg1, 1.0) |
No MUST-FIX defect was found in the law, the gate, or its application. Three bookkeeping/doc items are ranked below; the highest (M1) is a divergence-register obligation created by this commit, not a wrong number at retail's defaults.
Q1 — Is the formula transcription exact?
CONFIRMED for the expression; QUALIFIED for what "the aspect" is.
Both smartbox sites are byte-identical arithmetic. CreatureMode::Render
(pseudo-C line 91727, 0x00452b0d–0x00452b2f):
00452b0d mov ecx, [0x86f330] ; RenderDevice::render_device
00452b13 fld dword [ecx + 0xa8] ; ST0 = m_ViewportAspectRatio
00452b1a fsub dword [0x7948cc] ; ST0 = aspect - 0.1f (0x3dcccccd)
00452b20 fdivr dword [eax + 0xc0] ; ST0 = m_fGameFOV / ST0 <-- fdivr: mem / ST0
00452b26 fstp dword [esp] ; float-rounded quotient
00452b2f call 0x54b2d0 ; Render::SetFOVRad(quotient)
- Operand order:
fdivris reverse divide —ST0 = memory / ST0, i.e.m_fGameFOV / (aspect − 0.1). The numerator is the game FOV. Correct in the port. (This is exactly the operand-order trap the question was aimed at; BN's((long double)m_fGameFOV) / (aspect - 0.1)happens to agree, but only the bytes prove it.) - The 0.1 literal:
[0x7948cc] = 0x3dcccccd = 0.10000000149011612. The port'sAspectBias = 0.100000001fparses to that identical float. Exact. - Direct feed: the quotient is stored to the stack slot and immediately passed
to
SetFOVRad; no clamp, scale, or half-angle in between.SetFOVRad→SetFOVInternal(arg)→D3DXMatrixPerspectiveFovLH(pOut, arg, aspect, zn, zf)(0x0059ab71). No further transformation. Correct in the port. - Retail evaluates in x87 80-bit and stores one
float; acdream evaluates infloat. Sub-ULP; immaterial.
The qualification (see M1): which variable holds the aspect
The divisor's left operand is RenderDevice::m_ViewportAspectRatio (offset
0xa8, confirmed by the store in RenderDevice::SetViewport at
0054f22e fstp dword [esi+0xa8]). That field is not width/height in the
path the game view uses. RenderDevice::ComputeAspectForViewport (0x0054f150,
pseudo-C line 345708) is FPU-elided in BN to a meaningless return arg4 / arg5.
The bytes say:
0054f150 mov al, [esp+0x14] ; arg6
0054f154 fild dword [esp+0xc] ; width
0054f15a je 0x54f181 ; arg6 == 0 -> second path
; arg6 != 0 : ST0 = width / height <-- raw viewport aspect
0054f17c fdivp st(1)
0054f17e ret 0x14
0054f181: ; arg6 == 0 :
0054f1a1 fdivp st(1) ; ST0 = width / height
0054f1a3 fmul dword [ecx+0xa4] ; * m_DisplayAspectRatio
0054f1a9 fmul dword [0x79b6dc] ; * 0.75
0054f1af ret 0x14
m_DisplayAspectRatio (offset 0xa4, confirmed by the stores at 0059fc19 /
0059fc24 / 0059fc33) comes from the Render.AspectRatio user preference
(RenderDeviceD3D::SetupDisplayAspectRatio 0x0059fbd0, pseudo-C 428476):
1 → 1.33333337f, 2 → 1.77777779f, otherwise the display's own w/h.
The game view's viewport is installed with arg6 = 0
(gmSmartBoxUI::RecvNotice_UpdateGameView, 0x004d62f5), so in normal gameplay:
m_ViewportAspectRatio = (viewportW / viewportH) × m_DisplayAspectRatio × 0.75
At the registered default AspectRatio = 1 (static initializer
Render::m_RenderPrefs.AspectRatio = 0x1 at 0x0081efa8; also the safe-settings
reset at 0054ef25), 1.33333337f × 0.75f rounds to exactly 1.0f, so
m_ViewportAspectRatio == w/h and the port matches retail bit-for-bit.
It diverges only if the user selects the "widescreen" preference (× 4/3, a
noticeably narrower vertical FOV) — a preference acdream does not implement.
That is the M1 bookkeeping item, not a wrong number today.
Q2 — What m_bUseSmartboxFOV == 0 selects, and does acdream misapply the law?
CONFIRMED — the port does not apply the smartbox law anywhere retail uses the fixed branch.
The flag lives on CreatureMode (acclient.h:52561), which is the base of
UIElement_Viewport (acclient.h:52574) — i.e. it only exists for embedded 3-D
UI viewports, never for the world. CreatureMode::Render 0x00452af0:
00452ae8 mov al, [esi+0x6c] ; m_bUseSmartboxFOV
00452af0 je 0x452b2b ; == 0 -> fixed branch
00452b2b mov edx, [esi+0x68] ; m_fFOVRadians
00452b2f call SetFOVRad
m_fFOVRadians (offset 0x68) has exactly one read and zero writes in the
whole binary — its value is the constructor default, byte-decoded at
004543de mov dword [esi+0x68], 0x3f490fdb = π/4 = 45° (BN hid this inside a
17-byte memcpy literal). So the fixed branch is a constant, aspect-independent
45° vertical FOV.
Who takes which branch (every caller in the binary):
| Site | Caller | Branch |
|---|---|---|
0x004a5aa9 |
gmPaperDollUI (paperdoll) — UseSharpMode |
fixed 45° |
0x004e0440 |
char-gen 3-D view — UseSharpMode |
fixed 45° |
0x004ee9bc |
gmCG3DView — UseSharpMode |
fixed 45° |
0x004d6db3 |
gmSmartBoxUI::PostInit → m_pPortalSpace — UseSmartboxFOV |
smartbox law |
CreatureMode::UseSmartboxFOV (0x00452380, line 91348) is the only writer of
the flag and only ever sets it to 1.
acdream's side, checked exhaustively (grep FovY, grep CreatePerspectiveFieldOfView):
- The four cameras driven by
CameraController(Orbit,Fly,Chase,RetailChase) are all world cameras — retail's world render isSmartBox::RenderNormalMode, which is unconditionally on the smartbox law. Correct. DollCamera.FovRadians = MathF.PI / 4f— matches the byte-decoded fixed-branch constant. The commit's "paperdoll is exempt by design" claim is not just plausible, it is numerically right, and it is outsideCameraController, so the law can never reach it.CreatureAppraisalPresentation's camera is likewiseπ/4and outside the controller — the same fixed-branch class of viewport. Correct.- Portal space: retail's portal space does take the smartbox law
(
0x004d6db3). acdream'sPortalTunnelCamera.UseSmartBoxFov(smartBoxProjection)recovers the FOV from the world camera's projection matrix (fov = 2·atan(1/M22)) each draw (PortalTunnelPresentation.Draw, line 314), so it now inherits the new law automatically. Correct — and the "read the SmartBox each draw" shape matches retail's per-frame re-application. VulkanRhiScene's hardcodedMathF.PI / 3fis the RHI smoke-test scene (quadrant markers, wobble backdrop), not a world path. Not a finding.
Startup ordering was also checked, because the law makes FOV aspect-dependent:
HostInputCameraCompositionPhase calls
FramebufferResize.Resize(InitialFramebufferSize) immediately after binding the
camera target (HostInputCameraComposition.cs:320), so the real framebuffer
aspect — not DefaultAppliedFovY's assumed 16:9 — is in force before the first
frame.
Q3 — Does 0x00453b14 differ from the CreatureMode site?
CONFIRMED — different class, one structural difference, identical arithmetic.
0x00453b14 is inside SmartBox::RenderNormalMode (0x00453aa0, pseudo-C
line 92639) — the world render, not CreatureMode. Differences:
- No
m_bUseSmartboxFOVgate exists there at all. The function goes straight to them_bUseViewDistancetest (00453ae6 mov cl,[esi+0xc8]). The world is always on the smartbox law (modulo the teleport override). This is the stronger statement the port relies on, and it holds. m_fGameFOVis read fromthis(the SmartBox,[esi+0xc0]) rather than from theSmartBox::smartboxglobal ([eax+0xc0]aftera158ca8300 mov eax,[0x83ca58]). Same object in practice —CreatureMode::Renderloads the global explicitly becausethisis a viewport, not the SmartBox.- Otherwise the instruction sequence is the same four ops
(
fld [dev+0xa8]/fsub 0.1f/fdivr m_fGameFOV/fstp), thencall SetFOVRad.
Both sites share the second gate the commit message does not mention: if
m_bUseViewDistance != 0, retail calls Render::set_vdst(m_fViewDistFOV)
instead — see Q6.
Q4 — The gate, and is the value vertical?
CONFIRMED on both halves. The port is not inverted.
The acceptance interval — open (0, π), silent keep-previous
Render::SetFOVRad (0x0054b2d0, pseudo-C line 342158), bytes:
0054b2d0 fld dword [esp+4]
0054b2d4 fcomp dword [0x795344] ; 0x795344 = 0.0f
0054b2da fnstsw ax
0054b2dc test ah, 0x41 ; C0 (less) | C3 (equal)
0054b2df jnp 0x54b312 ; PF=0 <=> exactly one of C0/C3 <=> arg<0 or arg==0 -> reject
0054b2e1 fld dword [esp+4]
0054b2e5 fcomp qword [0x7bdd30] ; 0x7bdd30 = 3.141592653589793
0054b2ed test ah, 1 ; C0 (less)
0054b2f0 je 0x54b312 ; not-less (>= pi) -> reject
0054b2fc mov dword [0x81ec84], 0x3dcccccd ; Render::znear = 0.1f
0054b306 call [eax+0x1c] ; SetFOVInternal(arg)
0054b30c mov eax, 1
0054b311 ret
0054b312 xor eax, eax ; return 0 — no SetFOVInternal, Render::fov untouched
0054b314 ret
arg == 0is rejected (C3 path) andarg == πis rejected (needs strict C0). Interval is open on both ends. MatchesfovY > 0f && fovY < MathF.PI.- The reject path is
xor eax,eax; ret— it never reachesSetFOVInternal, soRender::fov,Render::vdst,Render::znearand the view-to-clip matrix all keep their previous values, silently (theint32_treturn is discarded at every call site).CameraController.ApplyProjection's "return without touchingFovY" is the exact contract. - Note the port also short-circuits
divisor <= 0. Retail reaches the same verdict by arithmetic: a negative divisor yields a negative quotient (rejected by test 1), a zero divisor yields ±∞ (rejected by test 2). Behaviourally equivalent — except for NaN, see M3.
Vertical, not horizontal — three independent proofs
Render::SetFOVInternal(0x0054b340):Render::vdst = ty / tan(arg × 0.5)wherety = (viewportHeight − 1) × 0.5 × yinvscale— half the viewport height over a distance istan(half **vertical** FOV).PrimD3DRender::SetFOVInternal(0x0059ab40) passes the samearg2straight intoD3DXMatrixPerspectiveFovLH(&m, arg2, m_ViewportAspectRatio, znear, zfar). That API's second parameter is fovy and its third is width/height. Decisive.SmartBox::GetOverrideFovDistance(0x00451be0) halves the same smartbox expression beforefptanand reciprocates it (fmul 0.5→fptan→fdivr 1.0), i.e. it returnscot(fov/2)— only meaningful if the expression is a full vertical angle. (It also provesview-plane distance == M22of a perspective matrix, which is whatTeleportViewPlaneController.Beginassumes.)
acdream feeds the value to Matrix4x4.CreatePerspectiveFieldOfView(FovY, Aspect, …)
— same slot, same meaning. Not inverted.
Q5 — Is 0x00451e6a the Field of View option's setter, with [10,160]/default 90?
CONFIRMED on every part.
- Enclosing function:
SmartBox::SetDefaultFov(SmartBox* this, float degrees)at0x00451e60(pseudo-C line 90988) —m_fGameFOV = degrees × 0.017453292519943295. - Its only caller in the binary is
Render::UpdateFromPreferences()(0x0054d850, call at0x0054d999, pseudo-C 344365), guarded by a change test againstCurrent_Render_FieldOfViewand fed fromRender::m_RenderPrefs.FieldOfView. So the chain is option slider → preference →UpdateFromPreferences→SetDefaultFov→m_fGameFOV. - Range:
UIPreferences::SetPreferenceRange(&Render_FieldOfView, 10f, 160f)at0x004043b2, insidegmClient::InitUIPreferences(0x004035b0, pseudo-C line 2740) — exactly as the commit claims. Corroborated by the console command at0x00455d20which validates>= 0xa && <= 0xa0beforeUIPreferences::ModifyPreference(&Render_FieldOfView, …). - Default: the static initializer
Render::m_RenderPrefsat0x0081efb8readsfloat FieldOfView = 90. The UI row is registered viaPlayerOptionPage::AddSliderOption(&Render_FieldOfView, 1)(0x0049e53e). - Ctor default of
m_fGameFOV:0x00454649inSmartBox::SmartBoxsets1.57079637f= π/2 = 90°, consistent with the degrees default. Alsom_fViewDistFOV = 0,m_bUseViewDistance = 0. - acdream's
DisplaySettings.Default.FieldOfView = 90fand the Config row (ConfigOptionsPageControllermin: 10f, max: 160f, defaultValue: 90.0f) now agree with each other and with retail. The pre-#389 mismatch (record default 60, slider default 90) is genuinely closed.
One behavioural difference, pre-existing (see M4): retail applies an FOV change
immediately — Render::UpdateFromPreferences is reached from
SceneTool::PrepareGraphicsDevice (0x0043e4f0), a per-frame device-prep step.
acdream applies DisplaySettings.FieldOfView only through
RuntimeSettingsController.ApplyStartup (next launch), except while a Config
draft preview is open (WorldRenderFrameBuilder.Apply → ApplyFieldOfView).
Q6 — Any other writer of Render::fov / SetFOVRad caller the port ignores?
CONFIRMED — none ignored. The one "other law" is already ported, and my byte-decode corrects the decomp in the port's favour.
SetFOVRad has exactly three call sites in the binary (grep of the full
pseudo-C): 0x00452b2f (CreatureMode, both branches converge on this one call)
and 0x00453b14 (SmartBox::RenderNormalMode). Nothing else calls it.
Render::fov is written only inside Render::SetFOVInternal, reached from:
SetFOVRad— the ported path.Render::set_vdst(float)(0x0054b240) — the view-distance override. Selected bym_bUseViewDistance != 0at both smartbox sites, i.e. it replaces the smartbox law while armed. Armed/disarmed bySmartBox::SetOverrideFovDistance(0x00451bc0), whose only callers are the teleport animation ingmSmartBoxUI:EndTeleportAnimation(0x004d65d5, disarm) andUseTime(0x004d71c4,0x004d725f,0x004d73cearm;0x004d747fdisarm), interpolatingteleportCurVDistbetween the game's value andTRANSITION_VIEW_PLANE_DISTANCEoverTELEPORT_ANIM_FADE_TIME.Render::set_zfar(0x0054b320) — re-applies the existingRender::fovafter changing the far plane. Not an independent FOV writer.
acdream already ports (2) as TeleportViewPlaneController, and it is correct:
0054b240 fld qword [0x7928c0] ; 1.0
0054b246 fld dword [esp+4] ; d (ST0=d, ST1=1.0)
0054b24a fpatan ; atan(ST1/ST0) = atan(1/d)
0054b24c fadd st(0), st(0) ; fov = 2*atan(1/d)
0054b252 fcomp dword [0x7ca9f0] ; 0.4f
0054b25d jp -> znear = 0.1f ; d < 0.4
0054b263 fmul dword [0x7c8a04] ; else znear = d * 0.25
; then clamp fov to [0.001 (0x794720), pi (0x7bdd30)] and call SetFOVInternal
BN renders line 342123 as __fpatan(arg1, 1.0), which reads as atan(d) and would
have made the port's 2f * MathF.Atan(1f / distance) look wrong. The bytes show
x87 fpatan computes atan(ST1/ST0) = atan(1/d) — the port is right and
the decomp text is the misleading party. near = MathF.Max(0.1f, distance*0.25f)
is likewise equivalent to retail's d < 0.4 ? 0.1 : d*0.25 at every input.
Residual (pre-existing, not #389): acdream's world cameras use a 5000 m far plane
where Render::zfar defaults to 4000 (0x0081ec88); PortalTunnelCamera already
documents 4000.
Findings, ranked
M1 — REGISTER/DOC (highest): "the viewport aspect" is a preference-scaled quantity
RetailFieldOfView's class doc and the commit message both describe the divisor's
left operand as the viewport aspect ratio. Retail's m_ViewportAspectRatio for the
game view is (w/h) × m_DisplayAspectRatio × 0.75, where m_DisplayAspectRatio is
driven by the Render.AspectRatio preference (Normal→4:3, widescreen→16:9,
otherwise the display's own ratio). At the registered default (1) the factor is
exactly 1.0f and acdream matches retail bit-for-bit; at the widescreen setting
retail's effective aspect is 4/3 larger and the vertical FOV correspondingly
narrower. acdream implements no aspect-ratio preference.
Why it matters: #389 is the commit that made this field load-bearing, and the
project rule is that a commit introducing a deviation carries its register row.
Action: add a divergence-register row ("acdream feeds the raw framebuffer
aspect; retail scales it by the Render.AspectRatio preference — identical at
retail's default, divergent if that preference is ever implemented") and correct
the one-line description in RetailFieldOfView's doc to name
ComputeAspectForViewport @0x0054f150 as the definition. No behaviour change.
M2 — NOTE: FOV changes do not take effect until next launch
Retail's option applies within one frame (SceneTool::PrepareGraphicsDevice →
Render::UpdateFromPreferences → SetDefaultFov; the smartbox re-reads
m_fGameFOV every RenderNormalMode). acdream applies it via ApplyStartup only
(live only during a Config draft preview). Pre-existing and documented in
DisplaySettings/ConfigOptionsPageController, but the semantics change in this
commit makes the lag more visible (the slider now changes the shape of the view,
not just its zoom). Worth an issue or a register row; not a #389 defect.
M3 — NOTE: NaN corner of the gate is inverted
Retail's first test is test ah,0x41 / jnp: an unordered compare sets both C0 and
C3 → even parity → not taken, and the second test's test ah,1 sees C0 set →
accepted. So retail would pass a NaN FOV through to SetFOVInternal. acdream's
fovY > 0f && fovY < MathF.PI rejects NaN. Reaching it requires m_fGameFOV NaN or
an exact 0/0, neither of which the option range permits. Record it, do not
"fix" it — rejecting NaN is strictly safer and unreachable.
M4 — DOC nit: the "~85–90° horizontal" claim
At the 90° default the law yields horizontal FOV ≈ 89.0° (4:3), 83.9°
(16:9), 80.6° (21:9). The class doc says "~85–90°"; the test asserts
[80°, 90°] (correct). Suggest "~80–89°, near-constant" in the doc so the doc and
the test agree.
Verified-good (no action)
AspectBias = 0.100000001f≡0x3dcccccd. Exact.DefaultGameFovRadians = 1.57079637f≡ the0x00454649ctor literal. Exact.- Golden test values recomputed from the bytes: 4:3 → 1.27362 rad, 16:9 → 0.93624 rad,
21:9 → 0.70334 rad (test asserts 0.70327 at
precision: 4— both round to 0.7033). DollCamera/CreatureAppraisalPresentationat π/4 match the byte-decodedCreatureMode::m_fFOVRadiansdefault0x3f490fdb.- Startup applies the real framebuffer aspect before the first frame.
TeleportViewPlaneController's2·atan(1/d)andmax(0.1, 0.25d)are correct against the bytes, contradicting the BN text.
Appendix — primary citations
| Address | Pseudo-C line | Symbol / meaning |
|---|---|---|
0x00452af0–0x00452b2f |
91717–91727 | CreatureMode::Render FOV branch (fixed vs smartbox vs vdst) |
0x00453ae6–0x00453b14 |
92655–92660 | SmartBox::RenderNormalMode smartbox site (no smartbox-flag gate) |
0x00452380 |
91348 | CreatureMode::UseSmartboxFOV — sets the flag to 1 (only writer) |
0x00452390 |
91356 | CreatureMode::UseSharpMode |
0x004a5aa9 / 0x004e0440 / 0x004ee9bc |
175534 / 228563 / 241997 | paperdoll + char-gen viewports (fixed branch) |
0x004d6db3 |
219378 | gmSmartBoxUI::PostInit — portal space takes the smartbox law |
0x004543de |
(in 93102 ctor) | m_fFOVRadians = 0x3f490fdb = π/4 (byte-decoded) |
0x00451be0–0x00451c18 |
90792–90806 | SmartBox::GetOverrideFovDistance = cot(fov/2) |
0x00451bc0 |
90783 | SmartBox::SetOverrideFovDistance |
0x00451e60/0x00451e6a |
90988–90991 | SmartBox::SetDefaultFov — degrees → radians |
0x00454649 |
93302 | SmartBox ctor m_fGameFOV = 1.57079637f |
0x0054b240 |
342121 | Render::set_vdst — fov = 2·atan(1/d), znear rule, [0.001, π] clamp |
0x0054b2d0 |
342158 | Render::SetFOVRad — open (0, π) gate, silent reject |
0x0054b340 |
342196 | Render::SetFOVInternal — vdst = ty / tan(fov/2) (vertical) |
0x0059ab40 |
423666 | PrimD3DRender::SetFOVInternal → D3DXMatrixPerspectiveFovLH(fovy, aspect, …) |
0x0054f150 |
345708 | RenderDevice::ComputeAspectForViewport — (w/h)·DAR·0.75 when arg6 == 0 |
0x0054f1c0/0x0054f22e |
345720/345749 | RenderDevice::SetViewport — writes m_ViewportAspectRatio (+0xa8) |
0x0059fbd0 |
428476 | RenderDeviceD3D::SetupDisplayAspectRatio — preference → m_DisplayAspectRatio |
0x0054d850/0x0054d999 |
344244/344365 | Render::UpdateFromPreferences → SetDefaultFov |
0x0043e4f0 |
69105 | SceneTool::PrepareGraphicsDevice → UpdateFromPreferences (per-frame) |
0x004035b0/0x004043b2 |
2740/3261 | gmClient::InitUIPreferences — SetPreferenceRange(10, 160) |
0x0081efb8 / 0x0081efa8 |
1102208 ff. | m_RenderPrefs.FieldOfView = 90, .AspectRatio = 1 |
0x004d65d5, 0x004d71c4, 0x004d725f, 0x004d73ce, 0x004d747f |
219002–219775 | teleport-animation FOV override arm/disarm |
Constants byte-read from the paired binary: [0x7948cc] = 0.1f (0x3dcccccd),
[0x79b6dc] = 0.75f, [0x795344] = 0.0f, [0x7bdd30] = π (f64),
[0x794720] = 0.001 (f64), [0x7928c0] = 1.0 (f64), [0x7ca9f0] = 0.4f,
[0x7c8a04] = 0.25f.