feat(selection): port retail offscreen target indicator

This commit is contained in:
Erik 2026-07-18 07:41:12 +02:00
parent ea4f52ec51
commit ec1bb19609
9 changed files with 404 additions and 97 deletions

View file

@ -125,23 +125,70 @@ enum values `1..12`. Values `1..4` are the four on-screen corners.
uses the active retail blit mode (`s_BlitMethod == 4`) to colorize the source
art with the same color as the object's radar blip.
`VividTargetIndicator::OnDraw @ 0x004F62B0` (on-screen branch)
`SmartBox::GetObjectBoundingBox @ 0x00452E20`
```text
if disabled, no selected id, or selected part was not reported by this world draw:
hide indicator
resolve the selected id directly through CObjectMaint::GetObjectA
if the object is absent:
return ObjectNotFound
reset to Render::set_default_view
push the object's position
obtain CPhysicsObj::GetSelectionSphere
if no sphere exists:
use an origin-centered sphere with radius 0.1 world units
if Render::viewconeCheck says the sphere intersects the full viewport cone:
project Render::GetViewerBBox's two corners
return ObjectOnscreen and the resulting screen rectangle
target = normalized selection-sphere center in viewer-local coordinates
if target is in front of the viewer:
angle = (450 - degrees(atan2(target.screenRight, target.screenUp))) mod 360
else:
colorize the four DAT corner images with the selected radar-blip color
obtain the selected object's SmartBox screen rectangle
use the actual DAT corner width and height
place the corner images just outside the rectangle
clamp the assembled indicator to an 8-pixel viewport margin
show the on-screen root and hide the off-screen root
angle = (450 - degrees(atan2(target.screenRight, 0))) mod 360
return ObjectOffscreen and angle
```
The indicator is persistent selection presentation. Retail also has a separate,
short-lived click confirmation owned by SmartBox; it is not implemented in
`CPhysicsPart::Draw` or `ACCWeenieObject::SetSelected`.
This path has no object-distance test and does not ask whether the selected
object participated in the visible world draw. `set_default_view` also removes
the per-portal view cone before the test. Consequently, a live selected object
keeps its four corners through walls and at any distance for which it remains in
the client object table.
`VividTargetIndicator::OnDraw @ 0x004F62B0`
```text
if disabled, display-off, or selected id is zero:
hide both roots
else if status is ObjectOnscreen:
colorize source images 1..4 with the selected radar-blip color
use the actual DAT corner width and height
place the corners just outside the SmartBox screen rectangle
clamp the assembled indicator to an 8-pixel viewport margin
show the on-screen root and hide the off-screen root
else if status is ObjectOffscreen:
choose one authored source image by angle:
[338,360) or [0,23) -> 6
[23,68) -> 7
[68,113) -> 9
[113,158) -> 12
[158,203) -> 11
[203,248) -> 10
[248,293) -> 8
[293,338) -> 5
colorize it with the selected radar-blip color
intersect the angle ray from viewport center with the screen edge
center the image on that intersection
clamp its top-left to the 8-pixel viewport margin
hide the on-screen root and show the off-screen image
```
Installed retail DAT verification pins images 1..4 at 12×12 pixels and images
5..12 at 24×24 pixels. The larger off-screen marker is authored art, not a
procedural arrow. The indicator is persistent selection presentation. Retail
also has a separate, short-lived click confirmation owned by SmartBox; it is not
implemented in `CPhysicsPart::Draw` or `ACCWeenieObject::SetSelected`.
## SmartBox click lighting pulse