Authentic target acquisition LIVE: reticle slew + pick-ray lock + aimed zone damage (task #36)
The engine Reticle model (MUNGA/RETICLE.h [T0]) reconstructed end to end: - Mech::targetReticle is a real Reticle member bound to the TargetReticle attribute (0x1d), per the RP VTV analog (VTV.h targetReticle). - Crosshair slew: mouse -> client rect -> reticle coords (the pod stick free-aim channel's dev-box stand-in); BT_AIM="x y" pins it headless. LMB fires lasers / RMB missiles (alongside SPACE/CTRL). - Pick ray: the ACTIVE eye publishes pos + LookAtRH basis (BTSetAimCamera, L4VIDRND view-write site) + the render loop publishes proj._22; BTGetAimRay builds the world ray, Mech::PickRayHit slab-tests it against the collision template's ExtentBox via the engine's BoundingBox::HitBy (local frame; clips the Line at entry) -> world hull point. - Designation: the mech under the crosshair designates (sticky; re-hover refreshes; cleared when the target leaves the roster at burial); the entity target slots 0x37c/0x388/0x38c feed the whole weapon path. - Aimed fire: while HOT the impact point is the PICKED hull point -> the STEP-6 cylinder lookup resolves the zone under the crosshair (verified: center-aim -> head-band zone 13 dominant). Off-crosshair the sticky designation converges on center mass. - HUD: the aim group draws at the slewed position ([0x9a] translate, contained by push/pop); the designator ring tracks the target's projected point (subB9 hot / subB8 designated, BTProjectToReticle); edge arrows when off-screen/behind. - AUTHENTIC gating: no fire arc exists in the binary (FireWeapon fires whenever HasActiveTarget, part_013.c:7758) -> BT_FIRE_ARC is now an explicit OPT-IN presentation clamp; the hardwired gEnemyMech lock and the projectile path's gEnemyMech fallback are removed. - Fixed en route: every renderable rebuild stomped mCamera back to the chase eye (start-inside silently lost the cockpit camera; the aim feed exposed it). BTL4VideoRenderer::mViewInside persists the chosen view. Verified headless: BT_AIM="0 0" -> HOT lock, pick hits the hull face at exact range, aimed zones resolve; BT_AIM="0.8 0.3" -> no lock, zero damage, zero missile launches; kill chain completes to wreck + smoke. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
6988821525
commit
d78bde066d
@@ -86,6 +86,102 @@ void BTSetLodEye(float x, float y, float z)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AIM CAMERA FEED (task #36 authentic targeting): the ACTIVE eye publishes its
|
||||
// world pose here (DPLEyeRenderable, the mCamera==this write site) and the
|
||||
// render loop publishes the live projection's FOV term; the game side then
|
||||
// derives the reticle PICK RAY (crosshair -> world, the engine Reticle's
|
||||
// "pick point intersection" input) and the inverse projection (world ->
|
||||
// reticle coords, the target-designator box position). Reticle coordinate
|
||||
// convention = the dpl2d frame: centered origin, +y down, unit = half the
|
||||
// viewport height (see dpl2d.cpp MapX/MapY).
|
||||
// ---------------------------------------------------------------------------
|
||||
static float gBTAimCamPos[3] = {0, 0, 0};
|
||||
static float gBTAimCamX[3] = {1, 0, 0}; // camera right (LookAtRH xaxis)
|
||||
static float gBTAimCamY[3] = {0, 1, 0}; // camera up (LookAtRH yaxis)
|
||||
static float gBTAimCamZ[3] = {0, 0, 1}; // camera BACK (LookAtRH zaxis; view dir = -Z)
|
||||
static float gBTAimTanHalf = 0.0f; // tan(fovY/2) = 1 / proj._22
|
||||
static int gBTAimCamValid = 0;
|
||||
|
||||
void BTSetAimCamera(const float pos[3], const float xax[3],
|
||||
const float yax[3], const float zax[3])
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
gBTAimCamPos[i] = pos[i];
|
||||
gBTAimCamX[i] = xax[i];
|
||||
gBTAimCamY[i] = yax[i];
|
||||
gBTAimCamZ[i] = zax[i];
|
||||
}
|
||||
gBTAimCamValid = 1;
|
||||
}
|
||||
|
||||
void BTSetAimProjection(float proj22)
|
||||
{
|
||||
if (proj22 > 1e-6f)
|
||||
gBTAimTanHalf = 1.0f / proj22;
|
||||
}
|
||||
|
||||
//
|
||||
// Crosshair (reticle coords) -> world pick ray. RH camera looks down -Z;
|
||||
// a point at reticle (rx, ry) sits at camera-space (rx*t, -ry*t, -1)
|
||||
// (reticle +y is DOWN, camera +y is UP; t = tan(fovY/2), and the reticle's
|
||||
// half-viewport-height unit cancels the aspect term exactly).
|
||||
//
|
||||
int BTGetAimRay(float rx, float ry, float outStart[3], float outDir[3])
|
||||
{
|
||||
if (!gBTAimCamValid || gBTAimTanHalf <= 0.0f)
|
||||
return 0;
|
||||
const float cx = rx * gBTAimTanHalf;
|
||||
const float cy = -ry * gBTAimTanHalf;
|
||||
float d[3];
|
||||
float len = 0.0f;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
d[i] = cx * gBTAimCamX[i] + cy * gBTAimCamY[i] - gBTAimCamZ[i];
|
||||
len += d[i] * d[i];
|
||||
}
|
||||
len = sqrtf(len);
|
||||
if (len < 1e-6f) return 0;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
outStart[i] = gBTAimCamPos[i];
|
||||
outDir[i] = d[i] / len;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
// World point -> reticle coords (the inverse; the designator box position).
|
||||
// Returns 1 when the point is IN FRONT of the camera (rx/ry valid for
|
||||
// on-screen placement); 0 when behind (rx still carries the correct SIDE
|
||||
// sign so the caller can pick the left/right off-screen arrow).
|
||||
//
|
||||
int BTProjectToReticle(const float world[3], float *rx, float *ry)
|
||||
{
|
||||
if (!gBTAimCamValid || gBTAimTanHalf <= 0.0f)
|
||||
{
|
||||
*rx = 0.0f; *ry = 0.0f;
|
||||
return 0;
|
||||
}
|
||||
float rel[3];
|
||||
for (int i = 0; i < 3; ++i)
|
||||
rel[i] = world[i] - gBTAimCamPos[i];
|
||||
const float xc = rel[0]*gBTAimCamX[0] + rel[1]*gBTAimCamX[1] + rel[2]*gBTAimCamX[2];
|
||||
const float yc = rel[0]*gBTAimCamY[0] + rel[1]*gBTAimCamY[1] + rel[2]*gBTAimCamY[2];
|
||||
const float zc = rel[0]*gBTAimCamZ[0] + rel[1]*gBTAimCamZ[1] + rel[2]*gBTAimCamZ[2];
|
||||
const float depth = -zc; // camera looks down -Z
|
||||
if (depth < 0.1f)
|
||||
{
|
||||
*rx = (xc >= 0.0f) ? 2.0f : -2.0f; // side sign only
|
||||
*ry = 0.0f;
|
||||
return 0;
|
||||
}
|
||||
*rx = xc / (gBTAimTanHalf * depth);
|
||||
*ry = -yc / (gBTAimTanHalf * depth);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void BTPushBeamKind(float fx, float fy, float fz, float tx, float ty, float tz,
|
||||
unsigned color, float ttl, float width, int kind)
|
||||
{
|
||||
@@ -7158,6 +7254,13 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte
|
||||
// the render lists
|
||||
memset(mRenderLists, 0, sizeof(mRenderLists));
|
||||
|
||||
// aim-ray feed (task #36): publish the live projection's FOV term so the
|
||||
// game side can build the reticle pick ray / designator projection.
|
||||
{
|
||||
extern void BTSetAimProjection(float proj22);
|
||||
BTSetAimProjection(mProjectionMatrix._22);
|
||||
}
|
||||
|
||||
HierarchicalDrawComponent *drawComp;
|
||||
SChainIteratorOf<HierarchicalDrawComponent*> iterator(&mRenderables);
|
||||
while ((drawComp = iterator.ReadAndNext()) != NULL)
|
||||
|
||||
Reference in New Issue
Block a user