Cockpit view live: V toggle, camera gate, real EyepointRotation, inside skeleton
- V toggles the authentic cockpit eyepoint <-> the chase camera. Both eyes coexist; DPLEyeRenderable::Execute now writes the VIEW only when it IS mCamera (unconditional writes let the last-executed eye stomp the toggle). - EyepointRotation is a real zeroed EulerAngles member on Mech (was bound to the shared junk attrPad -- the eye composes this attribute into the view EVERY frame, so the cockpit camera was rotated by garbage: the canted horizon, then the black screen). The eye-slew systems write it later. - The cockpit eye mounts at the eyepoint's REST position with a clean upright forward basis on the tree root (the live joint chain fed it the site tilt + torso pose; authentic pitch/yaw is the deferred gyro eye chain). - The inside view swaps the player to the INSIDE skeleton mesh set (SkeletonType_A): 19 body segments hide, exactly one mesh remains -- blx_cop.bgf, the authentic cockpit canopy shell around the eyepoint. It currently renders as a black enclosure (the black-screen report), so it is HIDDEN pending its interior/punch-material rendering (BT_INSIDE_COCKPIT=1 shows it for that work). Damage gstates respected in both directions; RemakeEntity keys off the DISPLAYED skeleton. - Dev: BT_START_INSIDE=1 starts in the cockpit view. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
c2f70f6348
commit
56f02b2176
@@ -302,6 +302,7 @@ HierarchicalDrawComponent*
|
||||
MechRenderTree &render_tree = mMechRenderTrees[entity];
|
||||
render_tree = MechRenderTree();
|
||||
render_tree.skeletonType = (int)skeletonType;
|
||||
render_tree.viewSkeleton = (int)skeletonType;
|
||||
render_tree.rootRenderable = this_root;
|
||||
render_tree.wrecked = 0;
|
||||
if (getenv("BT_DEATH_LOG"))
|
||||
@@ -363,17 +364,37 @@ HierarchicalDrawComponent*
|
||||
//
|
||||
if (segment->IsSiteSegment() /* [0x10] */ != 0)
|
||||
{
|
||||
if (type == insideEntity &&
|
||||
// The authentic COCKPIT EYEPOINT. Built for the true inside view
|
||||
// AND for the player's chase build (buildDebugChaseCamera), so the
|
||||
// V-key toggle can switch to it -- the pod's only view was this
|
||||
// eyepoint; the chase camera is the port's usability addition.
|
||||
if ((type == insideEntity || buildDebugChaseCamera) &&
|
||||
strcmp((const char *)segment->GetName() /* [0x11c] */, "siteeyepoint") == 0) // @0051d290
|
||||
{
|
||||
EulerAngles *eye_rot =
|
||||
(EulerAngles *)entity->GetAttributePointer("EyepointRotation"); // @0051d29d
|
||||
//
|
||||
// DPLEyeRenderable installs itself as the renderer's camera
|
||||
// (mCamera) so the main view tracks the cockpit eyepoint.
|
||||
// Mount the eye at the eyepoint's REST position but with a clean
|
||||
// UPRIGHT forward basis, parented on the tree ROOT: riding the
|
||||
// live joint chain fed the camera the site's authored tilt + the
|
||||
// torso pose (a permanently canted horizon). The authentic pitch
|
||||
// /yaw came from the gyro-driven eye-joint chain (deferred); until
|
||||
// that lands, the cockpit view = eyepoint position + mech yaw.
|
||||
//
|
||||
mCamera = new DPLEyeRenderable(
|
||||
entity, offset_matrix, parent_DCS, eye_rot);
|
||||
AffineMatrix restToEntity = segment->GetSegmentToEntity();
|
||||
Point3D eyePos;
|
||||
eyePos = restToEntity; // rest translation (W row)
|
||||
LinearMatrix eyeBasis(True);
|
||||
eyeBasis(0,0) = -1.0f; eyeBasis(0,1) = 0.0f; eyeBasis(0,2) = 0.0f; // X row
|
||||
eyeBasis(1,0) = 0.0f; eyeBasis(1,1) = 1.0f; eyeBasis(1,2) = 0.0f; // Y row (up)
|
||||
eyeBasis(2,0) = 0.0f; eyeBasis(2,1) = 0.0f; eyeBasis(2,2) = -1.0f; // Z row (look = mech forward)
|
||||
eyeBasis(3,0) = (Scalar)eyePos.x;
|
||||
eyeBasis(3,1) = (Scalar)eyePos.y;
|
||||
eyeBasis(3,2) = (Scalar)eyePos.z;
|
||||
mEyeCockpit = new DPLEyeRenderable(
|
||||
entity, eyeBasis, this_root, eye_rot);
|
||||
if (type == insideEntity) // true inside build: it IS the camera
|
||||
mCamera = mEyeCockpit;
|
||||
dbg_eye = 1;
|
||||
}
|
||||
continue;
|
||||
@@ -504,6 +525,11 @@ HierarchicalDrawComponent*
|
||||
SwapToWreck(entity);
|
||||
}
|
||||
|
||||
// DEV: BT_START_INSIDE=1 begins in the cockpit view (also exercises the
|
||||
// inside-skeleton swap headlessly).
|
||||
if (buildDebugChaseCamera && getenv("BT_START_INSIDE"))
|
||||
SetViewInside(1);
|
||||
|
||||
//
|
||||
// TODO(bring-up): inside-view targeting reticle (BTReticleRenderable +
|
||||
// AddWeapon pips) and the per-subsystem weapon/effect renderables (PPC/
|
||||
@@ -572,10 +598,12 @@ HierarchicalDrawComponent*
|
||||
debugOffset(2,0) = zx; debugOffset(2,1) = zy; debugOffset(2,2) = zz; // Z row (look)
|
||||
debugOffset(3,0) = camPx; debugOffset(3,1) = camPy; debugOffset(3,2) = camPz; // W row (pos)
|
||||
|
||||
mCamera = new DPLEyeRenderable(entity, debugOffset, this_root, NULL);
|
||||
mEyeChase = new DPLEyeRenderable(entity, debugOffset, this_root, NULL);
|
||||
mCamera = mEyeChase; // default view: chase (V toggles cockpit)
|
||||
DEBUG_STREAM << "[BTrender] external debug chase camera installed at ("
|
||||
<< camPx << "," << camPy << "," << camPz << ") looking at ("
|
||||
<< tgtX << "," << tgtY << "," << tgtZ << ")\n" << std::flush;
|
||||
<< tgtX << "," << tgtY << "," << tgtZ << ") -- V toggles the cockpit eyepoint"
|
||||
<< (mEyeCockpit ? "" : " (COCKPIT EYE MISSING)") << "\n" << std::flush;
|
||||
}
|
||||
|
||||
return this_root;
|
||||
@@ -614,7 +642,7 @@ void
|
||||
|
||||
JointedMover *jointed_mover = (JointedMover *)entity;
|
||||
EntitySegment::SkeletonType skeletonType =
|
||||
(EntitySegment::SkeletonType)render_tree.skeletonType;
|
||||
(EntitySegment::SkeletonType)render_tree.viewSkeleton; // the DISPLAYED set
|
||||
|
||||
EntitySegment::SegmentTableIterator segment_iterator(jointed_mover->segmentTable);
|
||||
EntitySegment *segment;
|
||||
@@ -1233,6 +1261,110 @@ BTL4VideoRenderer::BTL4VideoRenderer(
|
||||
DPLRenderer(::GetActiveWindow(), 800, 600, false, interest_type, depth_calibration)
|
||||
{
|
||||
Check_Pointer(this);
|
||||
mEyeCockpit = 0;
|
||||
mEyeChase = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// The V-key view toggle: switch the live camera between the authentic cockpit
|
||||
// eyepoint and the port's external chase camera. A missing eye (e.g. the
|
||||
// cockpit eye on a mech with no siteeyepoint) leaves the current view.
|
||||
//
|
||||
void
|
||||
BTL4VideoRenderer::SetViewInside(int inside)
|
||||
{
|
||||
if (inside && mEyeCockpit != 0)
|
||||
mCamera = mEyeCockpit;
|
||||
else if (!inside && mEyeChase != 0)
|
||||
mCamera = mEyeChase;
|
||||
|
||||
//
|
||||
// Swap the player's DISPLAYED skeleton with the view: the INSIDE view uses
|
||||
// the inside-skeleton mesh set (SkeletonType_A -- most body segments have
|
||||
// no inside mesh, so the pilot isn't wrapped in his own torso textures;
|
||||
// the authentic pod view worked exactly this way), the chase view restores
|
||||
// the full outside set. Damage graphic states are respected per segment.
|
||||
//
|
||||
Entity *viewpoint = (application != 0) ? application->GetViewpointEntity() : 0;
|
||||
std::map<Entity*, MechRenderTree>::iterator tree_it =
|
||||
mMechRenderTrees.find(viewpoint);
|
||||
if (tree_it != mMechRenderTrees.end() && !tree_it->second.wrecked)
|
||||
{
|
||||
MechRenderTree &render_tree = tree_it->second;
|
||||
render_tree.viewSkeleton = inside
|
||||
? (int)EntitySegment::SkeletonType_A
|
||||
: render_tree.skeletonType;
|
||||
|
||||
JointedMover *jm = (JointedMover *)viewpoint;
|
||||
EntitySegment::SegmentTableIterator it(jm->segmentTable);
|
||||
EntitySegment *segment;
|
||||
int shown = 0, hidden = 0;
|
||||
while ((segment = it.ReadAndNext()) != NULL)
|
||||
{
|
||||
if (segment->IsSiteSegment() != 0)
|
||||
continue;
|
||||
int slot = segment->GetIndex();
|
||||
std::map<int, HierarchicalDrawComponent*>::iterator r =
|
||||
render_tree.segRenderable.find(slot);
|
||||
if (r == render_tree.segRenderable.end() || r->second == NULL)
|
||||
continue;
|
||||
int gstate = 0;
|
||||
std::map<int, int>::iterator g = render_tree.segGState.find(slot);
|
||||
if (g != render_tree.segGState.end())
|
||||
gstate = g->second;
|
||||
CString *nm = segment->GetVideoObjectName(
|
||||
(EntitySegment::SkeletonType)render_tree.viewSkeleton,
|
||||
(Enumeration)gstate);
|
||||
// The cockpit interior shell (blx_cop -- the canopy frame around the
|
||||
// eyepoint) currently renders as a black enclosure; keep it hidden
|
||||
// until its interior rendering is sorted (BT_INSIDE_COCKPIT=1 shows
|
||||
// it for that investigation).
|
||||
if (inside && nm != NULL && strstr((const char *)*nm, "_cop") != NULL
|
||||
&& !getenv("BT_INSIDE_COCKPIT"))
|
||||
nm = NULL;
|
||||
d3d_OBJECT *obj = NULL;
|
||||
if (nm != NULL)
|
||||
{
|
||||
char filename[44];
|
||||
strcpy(filename, (const char *)*nm);
|
||||
int len = (int)strlen(filename);
|
||||
if (len >= 4)
|
||||
filename[len - 4] = '\0';
|
||||
strcat(filename, ".bgf");
|
||||
obj = d3d_OBJECT::LoadObject(GetDevice(), filename);
|
||||
}
|
||||
r->second->SetDrawObj(obj);
|
||||
if (obj)
|
||||
{
|
||||
++shown;
|
||||
DEBUG_STREAM << "[view] shown: seg '"
|
||||
<< (const char *)segment->GetName() << "' mesh '"
|
||||
<< (nm ? (const char *)*nm : "?") << "'\n" << std::flush;
|
||||
}
|
||||
else ++hidden;
|
||||
}
|
||||
DEBUG_STREAM << "[view] skeleton "
|
||||
<< (inside ? "A (inside)" : "N (outside)") << ": "
|
||||
<< shown << " segment mesh(es) shown, " << hidden
|
||||
<< " hidden\n" << std::flush;
|
||||
}
|
||||
|
||||
DEBUG_STREAM << "[view] " << (inside ? "COCKPIT eyepoint" : "external chase")
|
||||
<< (mCamera == mEyeCockpit ? " (cockpit live)" : " (chase live)")
|
||||
<< "\n" << std::flush;
|
||||
}
|
||||
|
||||
//
|
||||
// Sim-side bridge (the mech4 keyboard poll drives it).
|
||||
//
|
||||
void BTSetViewInside(int inside)
|
||||
{
|
||||
if (application == NULL)
|
||||
return;
|
||||
BTL4VideoRenderer *renderer =
|
||||
(BTL4VideoRenderer *)application->GetVideoRenderer();
|
||||
if (renderer != NULL)
|
||||
renderer->SetViewInside(inside);
|
||||
}
|
||||
|
||||
BTL4VideoRenderer::~BTL4VideoRenderer()
|
||||
|
||||
Reference in New Issue
Block a user