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
@@ -5571,7 +5571,11 @@ void
|
||||
++dbgEyeExec;
|
||||
}
|
||||
|
||||
myDevice->SetTransform(D3DTS_VIEW, &view);
|
||||
// Only the ACTIVE camera writes the view: the BT view toggle builds
|
||||
// BOTH the cockpit and chase eyes; an unconditional write here let
|
||||
// whichever eye executed LAST stomp the toggled camera every frame.
|
||||
if (myRenderer->mCamera == this)
|
||||
myDevice->SetTransform(D3DTS_VIEW, &view);
|
||||
myRenderer->GetMatrixStack()->Pop();
|
||||
}
|
||||
else if (dbgEyeExec < 8)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -564,6 +564,7 @@ class BTReticleRenderable:
|
||||
struct MechRenderTree
|
||||
{
|
||||
int skeletonType; // EntitySegment::SkeletonType used at build
|
||||
int viewSkeleton; // the skeleton currently DISPLAYED (view toggle)
|
||||
HierarchicalDrawComponent *rootRenderable;// the tree root (wreck hulk parent)
|
||||
int wrecked; // 1 = swapped to the <mech>dbr hulk
|
||||
DPLStaticChildRenderable *wreckHulk; // the <mech>dbr piece (sinks)
|
||||
@@ -586,6 +587,20 @@ class BTReticleRenderable:
|
||||
int
|
||||
TickWreck(Entity *victim, float dt);
|
||||
|
||||
//
|
||||
// VIEW TOGGLE: the player's mech builds BOTH cameras -- the authentic
|
||||
// cockpit eyepoint (DPLEyeRenderable at 'siteeyepoint', the pod's only
|
||||
// view) and the port's external chase camera (a usability addition for
|
||||
// the windowed build). SetViewInside switches the renderer's live
|
||||
// camera between them (V key via the BTSetViewInside bridge).
|
||||
//
|
||||
void
|
||||
SetViewInside(int inside);
|
||||
|
||||
protected:
|
||||
DPLEyeRenderable *mEyeCockpit; // the authentic cockpit eyepoint
|
||||
DPLEyeRenderable *mEyeChase; // the external chase camera
|
||||
|
||||
public:
|
||||
//
|
||||
// The death-wreck swap (ExplosionScripts effect 104, reconstructed): the
|
||||
@@ -683,6 +698,12 @@ extern void BTSwapMechToWreck(Entity *victim);
|
||||
//
|
||||
extern int BTWreckSinkTick(Entity *victim, float dt);
|
||||
|
||||
//
|
||||
// View-mode bridge (the V key): 1 = the authentic cockpit eyepoint,
|
||||
// 0 = the external chase camera.
|
||||
//
|
||||
extern void BTSetViewInside(int inside);
|
||||
|
||||
#endif // BTL4VID_HPP
|
||||
|
||||
//===========================================================================//
|
||||
|
||||
@@ -531,7 +531,7 @@ const Mech::IndexEntry
|
||||
ATTRIBUTE_ENTRY(Mech, CollisionMaterialType, attrPad), // 0x19
|
||||
ATTRIBUTE_ENTRY(Mech, CurrentSpeed, legCycleSpeed), // 0x1a (existing @0x348)
|
||||
ATTRIBUTE_ENTRY(Mech, MaxRunSpeed, reverseStrideLength), // 0x1b (existing @0x34c = run/top speed)
|
||||
ATTRIBUTE_ENTRY(Mech, EyepointRotation, attrPad), // 0x1c
|
||||
ATTRIBUTE_ENTRY(Mech, EyepointRotation, eyepointRotation), // 0x1c (real member -- the eye reads it per frame)
|
||||
ATTRIBUTE_ENTRY(Mech, TargetReticle, attrPad), // 0x1d
|
||||
ATTRIBUTE_ENTRY(Mech, FootStep, attrPad), // 0x1e
|
||||
ATTRIBUTE_ENTRY(Mech, AnimationState, attrPad), // 0x1f
|
||||
@@ -1318,7 +1318,8 @@ Mech::Mech(
|
||||
deathHandler = (int)new MechDeathHandler(this); // FUN_0042a984
|
||||
critRes->Unlock();
|
||||
}
|
||||
wreckSmokeTimer = 0.0f;
|
||||
wreckSmokeTimer = 0.0f;
|
||||
eyepointRotation = EulerAngles(Radian(0.0f), Radian(0.0f), Radian(0.0f));
|
||||
|
||||
//
|
||||
// Cylinder hit-location table (resource type 0x1d = DamageLookupTableStream) --
|
||||
|
||||
@@ -501,6 +501,12 @@ protected:
|
||||
// smoke plume (psfx 1, DDTHSMK) every 10s (its authored emission window)
|
||||
// while the mech is a destroyed wreck, so a dead mech keeps smoking.
|
||||
Scalar wreckSmokeTimer;
|
||||
// The cockpit eye-slew angles (the "EyepointRotation" attribute the
|
||||
// binary's DPLEyeRenderable composes into the view every frame). Was
|
||||
// bound to the shared junk attrPad -> the cockpit camera got rotated by
|
||||
// garbage (the canted-horizon / black-screen views). Zero until the
|
||||
// eye-slew system (HUD freeAimSlew / gyro eye chain) writes it.
|
||||
EulerAngles eyepointRotation;
|
||||
|
||||
// Three ref-counted creation-name objects (badge/color/insignia).
|
||||
void *resourceNameA; // @0x844 this[0x211]
|
||||
|
||||
@@ -1207,6 +1207,17 @@ void
|
||||
const int xNow = focused && (pAsync('X') & dn) ? 1 : 0;
|
||||
if (xNow && !sPrevX) gBTDrive.allStop = 1; // edge -> one all-stop
|
||||
sPrevX = xNow;
|
||||
// V: toggle the view between the authentic COCKPIT eyepoint
|
||||
// (the pod's only view) and the external chase camera.
|
||||
static int sPrevV = 0, sViewInside = 0;
|
||||
const int vNow = focused && (pAsync('V') & dn) ? 1 : 0;
|
||||
if (vNow && !sPrevV)
|
||||
{
|
||||
sViewInside = !sViewInside;
|
||||
extern void BTSetViewInside(int inside);
|
||||
BTSetViewInside(sViewInside);
|
||||
}
|
||||
sPrevV = vNow;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user