BT410 5.3.69: the cockpit eye sits in the canopy -- site handling in the walk
RecurseSKLFile now walks "site=" children. Sites get no draw component -- which is why the walk's 26 nodes matched the real capture all along: sites were never DCS nodes -- and siteeyepoint spawns the cockpit camera with the donor's exact construction (bt411 btl4vid.cpp:462, decomp FUN_004579a8): offset = the site's own local rest transform, parent = the site's PARENT joint's DCS, not the hull root. World orientation, torso twist and gait all arrive through chain composition. The root-DCS eye remains only as the zero-construction fallback for skeletons with no siteeyepoint. Measured on the live pod with the RIO streaming: [eye] cockpit eye on 'jointeye', 26 nodes / 19 objects / 1 eye, and the bridge camera sits at Y = hull + 7.7 -- the exact chain sum jointlocal 5.29 + hip 0.37 + torso 0.31 + jointeye 1.69. canopy_eye1.png is the pilot's view, the mech's own nose wedge visible below the sightline. Own-mech cage handling is the next layer. Also: eye_count threading through ReadSKLFile/RecurseSKLFile, and the [skl] summary now reports it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -125,10 +125,12 @@ dpl_DCS *
|
||||
Entity *entity,
|
||||
dpl_DCS *parent_dcs,
|
||||
const char *skeleton_filename,
|
||||
ViewFrom view_type)
|
||||
ViewFrom view_type,
|
||||
int *eye_count)
|
||||
{
|
||||
Check(this);
|
||||
Check_Pointer(skeleton_filename);
|
||||
Check_Pointer(eye_count);
|
||||
|
||||
char
|
||||
path[256];
|
||||
@@ -167,11 +169,12 @@ dpl_DCS *
|
||||
dpl_DCS
|
||||
*root = RecurseSKLFile(
|
||||
entity, parent_dcs, skeleton, "ROOT", 0, view_type,
|
||||
zone, &node_count, &object_count);
|
||||
zone, &node_count, &object_count, eye_count);
|
||||
|
||||
DEBUG_STREAM << "[skl] " << path
|
||||
<< " -> " << node_count << " nodes, "
|
||||
<< object_count << " objects\n" << flush;
|
||||
<< object_count << " objects, "
|
||||
<< *eye_count << " eye\n" << flush;
|
||||
|
||||
//
|
||||
// The engine guards this the same way (L4VIDEO.CPP, DPLReadEnvironment):
|
||||
@@ -199,7 +202,8 @@ dpl_DCS *
|
||||
ViewFrom view_type,
|
||||
dpl_ZONE *zone,
|
||||
int *node_count,
|
||||
int *object_count)
|
||||
int *object_count,
|
||||
int *eye_count)
|
||||
{
|
||||
Check(this);
|
||||
Check(skeleton);
|
||||
@@ -348,7 +352,7 @@ dpl_DCS *
|
||||
{
|
||||
RecurseSKLFile(
|
||||
entity, dcs, skeleton, child_page, recursion_depth + 1,
|
||||
view_type, zone, node_count, object_count);
|
||||
view_type, zone, node_count, object_count, eye_count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,6 +360,100 @@ dpl_DCS *
|
||||
delete children;
|
||||
}
|
||||
|
||||
//
|
||||
// "site=" children. Sites get NO draw component of their own -- the
|
||||
// real pod's capture decodes exactly 26 DCS bodies for this skeleton,
|
||||
// which is joints+root only, and this walk matched that count precisely
|
||||
// BECAUSE it ignored sites. One site spawns hardware instead of
|
||||
// geometry: siteeyepoint is the COCKPIT CAMERA.
|
||||
//
|
||||
// The authentic construction comes from the donor's decompile
|
||||
// (bt411 btl4vid.cpp:462, decomp FUN_004579a8): the eye's offset matrix
|
||||
// is the SITE'S OWN local rest transform, and the eye is parented on the
|
||||
// site's PARENT segment's draw component -- this page's DCS -- NOT the
|
||||
// hull root. World orientation and all live motion (torso twist, gait)
|
||||
// then come from the parent-chain composition for free. For MAD.SKL the
|
||||
// chain is jointtorso -> jointeye (trany +1.687, tranz -1.318) ->
|
||||
// siteeyepoint (identity), which puts the eye in the canopy where the
|
||||
// cockpit sits, instead of at the hull origin staring through the torso
|
||||
// panels.
|
||||
//
|
||||
if (view_type == insideEntity)
|
||||
{
|
||||
NameList
|
||||
*sites = skeleton->MakeEntryList(page_name, "site");
|
||||
if (sites != NULL)
|
||||
{
|
||||
Register_Object(sites);
|
||||
|
||||
NameList::Entry
|
||||
*site_entry;
|
||||
for (site_entry = sites->GetFirstEntry();
|
||||
site_entry != NULL;
|
||||
site_entry = site_entry->GetNextEntry())
|
||||
{
|
||||
const char
|
||||
*site_page = (const char *)site_entry->dataReference;
|
||||
if (
|
||||
site_page != NULL &&
|
||||
strcmp(site_page, "siteeyepoint") == 0 &&
|
||||
skeleton->PageExists(site_page)
|
||||
)
|
||||
{
|
||||
Scalar
|
||||
site_tx = 0.0f, site_ty = 0.0f, site_tz = 0.0f,
|
||||
site_pitch = 0.0f, site_yaw = 0.0f, site_roll = 0.0f;
|
||||
skeleton->GetEntry(site_page, "tranx", &site_tx);
|
||||
skeleton->GetEntry(site_page, "trany", &site_ty);
|
||||
skeleton->GetEntry(site_page, "tranz", &site_tz);
|
||||
skeleton->GetEntry(site_page, "pitch", &site_pitch);
|
||||
skeleton->GetEntry(site_page, "yaw", &site_yaw);
|
||||
skeleton->GetEntry(site_page, "roll", &site_roll);
|
||||
|
||||
//
|
||||
// Default ctor identities; the EulerAngles assignment
|
||||
// writes ONLY the 3x3 rotation (AFFNMTRX.CPP:179), so
|
||||
// the identity's zero translation survives it and the
|
||||
// site translation goes in after.
|
||||
//
|
||||
LinearMatrix
|
||||
site_offset;
|
||||
site_offset =
|
||||
EulerAngles(site_pitch, site_yaw, site_roll);
|
||||
site_offset(3,0) = site_tx;
|
||||
site_offset(3,1) = site_ty;
|
||||
site_offset(3,2) = site_tz;
|
||||
|
||||
EulerAngles
|
||||
*eyepoint_rotation =
|
||||
(EulerAngles *)entity->GetAttributePointer(
|
||||
"EyepointRotation");
|
||||
DPLEyeRenderable
|
||||
*cockpit_eye = new DPLEyeRenderable(
|
||||
entity,
|
||||
dplMainZone,
|
||||
site_offset,
|
||||
dcs,
|
||||
dplMainView,
|
||||
eyepoint_rotation);
|
||||
Register_Object(cockpit_eye);
|
||||
++(*eye_count);
|
||||
|
||||
if (getenv("BT_MER_LOG"))
|
||||
{
|
||||
DEBUG_STREAM << " [eye] cockpit eye on '"
|
||||
<< page_name << "' offset=("
|
||||
<< site_tx << "," << site_ty << ","
|
||||
<< site_tz << ")\n" << flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Unregister_Object(sites);
|
||||
delete sites;
|
||||
}
|
||||
}
|
||||
|
||||
return dcs;
|
||||
}
|
||||
|
||||
@@ -506,17 +604,28 @@ void
|
||||
//
|
||||
// 2. The skeleton hangs UNDER the root DCS -- so the whole
|
||||
// model rides the entity's localToWorld instead of
|
||||
// being parked at the world origin.
|
||||
// being parked at the world origin. The walk also
|
||||
// builds the COCKPIT EYE when it meets the
|
||||
// siteeyepoint site (donor construction: offset =
|
||||
// the site's local rest, parent = the site's parent
|
||||
// joint DCS -- so the eye sits in the canopy and
|
||||
// rides torso twist through chain composition).
|
||||
//
|
||||
int
|
||||
eye_count = 0;
|
||||
ReadSKLFile(entity, root_DCS,
|
||||
video_object->GetObjectFilename(), view_type);
|
||||
video_object->GetObjectFilename(), view_type,
|
||||
&eye_count);
|
||||
|
||||
//
|
||||
// 3. Inside view: the eyepoint, driven off the same root
|
||||
// DCS plus the mech's published EyepointRotation --
|
||||
// this is what the camera follows.
|
||||
// 3. FALLBACK eyepoint only. A skeleton without a
|
||||
// siteeyepoint still needs a camera for the inside
|
||||
// view, and the hull root with a zero offset is the
|
||||
// engine's own zero-construction default
|
||||
// (L4VIDEO.CPP:4849). For MAD.SKL this no longer
|
||||
// runs -- the walk builds the real cockpit eye.
|
||||
//
|
||||
if (view_type == insideEntity)
|
||||
if (view_type == insideEntity && eye_count == 0)
|
||||
{
|
||||
EulerAngles
|
||||
*eyepoint_rotation =
|
||||
|
||||
@@ -78,7 +78,8 @@
|
||||
Entity *entity,
|
||||
dpl_DCS *parent_dcs,
|
||||
const char *skeleton_filename,
|
||||
ViewFrom view_type);
|
||||
ViewFrom view_type,
|
||||
int *eye_count);
|
||||
|
||||
dpl_DCS *
|
||||
RecurseSKLFile(
|
||||
@@ -90,7 +91,8 @@
|
||||
ViewFrom view_type,
|
||||
dpl_ZONE *zone,
|
||||
int *node_count,
|
||||
int *object_count);
|
||||
int *object_count,
|
||||
int *eye_count);
|
||||
|
||||
protected:
|
||||
int reserved[16];
|
||||
|
||||
@@ -1447,3 +1447,27 @@ same streamed table our code hands to archive code, name what will not
|
||||
resolve) turned a two-day intermittent heap-corruption hunt into a one-run
|
||||
lookup. The streamed RES tables are BINDING CONTRACTS on our attribute
|
||||
enums; every subsystem the RES maps should get the same audit treatment.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
THE COCKPIT EYE SITS IN THE CANOPY -- SITE HANDLING IN THE SKELETON WALK
|
||||
--------------------------------------------------------------------------------
|
||||
The eye no longer rides the hull root. RecurseSKLFile now walks "site="
|
||||
children (sites get NO draw component -- which is WHY the walk's 26 nodes
|
||||
matched the real capture: sites were never DCS nodes), and siteeyepoint
|
||||
spawns the cockpit camera with the donor's exact construction (bt411
|
||||
btl4vid.cpp:462, decomp FUN_004579a8):
|
||||
|
||||
offset = the SITE's own local rest transform (siteeyepoint = identity)
|
||||
parent = the site's PARENT joint's DCS (jointeye, NOT the root)
|
||||
|
||||
so world orientation, torso twist and gait all arrive through chain
|
||||
composition, with no per-mech forward-axis assumption. The old root-DCS eye
|
||||
remains only as the zero-construction fallback for a skeleton with no
|
||||
siteeyepoint (the engine's own default, L4VIDEO.CPP:4849).
|
||||
|
||||
MEASURED on the live pod (RIO streaming, post-5.3.68): [eye] cockpit eye on
|
||||
'jointeye', [skl] 26 nodes / 19 objects / 1 eye, and the bridge camera sits at
|
||||
Y = hull + 7.7 -- the exact chain sum jointlocal 5.29 + hip 0.37 + torso 0.31
|
||||
+ jointeye 1.69 = 7.66. canopy_eye1.png: the pilot's view, with the MadCat's
|
||||
own nose wedge visible below the sightline -- own-mech cage handling
|
||||
(COCKPIT-CAGE-NOTES.md punch cutouts) is the known next layer.
|
||||
|
||||
Reference in New Issue
Block a user