The wireframe key works and Steam is optional

Alt+W had been a no-op since the 2007 DPL->Direct3D port, which stubbed
DPLToggleWireframe along with every other dpl_ call. D3D9 has no global
wireframe property, so the toggle now records the intent in gWireframe
and ExecuteImplementation applies D3DRS_FILLMODE once per frame - which
also means it re-asserts itself after a device Reset. The sky dome and
the 2D pass are held solid: a wireframed dome buries the geometry you
turned the key on to look at, and the gunsight would otherwise come out
as bare diagonals.

Proving it needed a working copy, and that turned up a separate problem.
steam_api.dll was a hard import, so a machine without it died at load
time with 0xC0000135 - before a window, before a log line. It is now
delay-loaded, and because delay loading only moves that failure to the
first call, every Steam path is gated on
SteamNetTransport_ClientLibraryPresent(): Install and the two lobby
entries, with everything else downstream of one of them. Absent DLL
boots and races; absent DLL with RP412STEAM=1 logs the reason and stays
on TCP; DLL present brings the transport up exactly as before.

The documentation now says which debug keys are real. Five of the seven
are still 2007 stubs and always have been, so they are named as inert in
environ.ini's template and at the dispatch site - that beats letting the
next person debug a dead key, which is how this started. BUILD.md gains
a debug-key table, the delay-load contract for anyone adding a Steam
call site, and the environ.ini BOM trap that silently reverts
L4CONTROLS to KEYBOARD and then fail-fasts for want of a pod mapper.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-08-10 11:15:11 -05:00
co-authored by Claude Opus 5
parent 34abf40e7f
commit 0f4592c39a
10 changed files with 265 additions and 27 deletions
+56 -12
View File
@@ -83,6 +83,19 @@ DWORD
// (NULL = present to the device window as always).
HWND gMainPresentWindow = NULL;
//
// Alt+W wireframe (RP412DEVKEYS). File scope rather than a DPLRenderer
// member because a fresh renderer is built per mission - a member would
// drop the toggle every time the race restarted, which is exactly when
// you are looking at geometry.
//
// DPLToggleWireframe only flips this; the fill mode is applied once per
// frame in ExecuteImplementation. Setting it there rather than in the key
// handler means it re-asserts itself after a device Reset, which reverts
// the fill mode to D3DFILL_SOLID underneath us.
//
static Logical gWireframe = 0;
//STUBBED: DPL RB 1/14/07
// when this is resolved it can be removed
#include "..\DPLSTUB.h"
@@ -6402,6 +6415,17 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte
hr = mDevice->BeginScene();
//
// Alt+W wireframe. Set every frame from the flag rather than once at
// toggle time - see gWireframe. It is turned back off for the sky pass
// and again for the 2D pass below; everything between here and there
// draws as edges.
//
mDevice->SetRenderState(
D3DRS_FILLMODE,
gWireframe ? D3DFILL_WIREFRAME : D3DFILL_SOLID
);
mDevice->SetFVF(L4VERTEX_FVF);
D3DXMATRIX viewTransform;
@@ -6478,6 +6502,17 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte
mDevice->SetTransform(D3DTS_PROJECTION, &mProjectionMatrix);
//
// The sky stays solid under Alt+W. Wireframing the dome fills the top
// of the screen with its own tessellation and buries the geometry you
// turned wireframe on to look at; a solid sky gives the edges something
// to read against.
//
if (gWireframe)
{
mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
}
if (!l4_application->IsDead())
{
@@ -6492,6 +6527,11 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte
for (d3d_OBJECT *obj = mRenderLists[PASS_SKY]; obj != NULL; obj = obj->GetNext(PASS_SKY))
obj->Draw(PASS_SKY, &viewTransform, mTargetRenderTime);
if (gWireframe)
{
mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
}
//Reactivate fog
mDevice->SetRenderState(D3DRS_FOGSTART, *((DWORD*)(&currentFogNear)));
mDevice->SetRenderState(D3DRS_FOGEND, *((DWORD*)(&currentFogFar)));
@@ -6535,6 +6575,12 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte
// Wrap it up by doing the 2D pass
//
mDevice->SetFVF(L4VERTEX_2D_FVF);
//
// Always solid from here on: the gunsight and the cam-ship HUD are
// textured quads on this device, and in wireframe they come out as bare
// diagonals.
//
mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
mDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
@@ -6818,19 +6864,17 @@ void
void
DPLRenderer::DPLToggleWireframe()
{
//STUBBBED: DPL RB 1/14/07
//static Logical wireframe_on = 0;
//
// The DPL original set a renderer property here
// (dpl_render_prop_wireframe) and was stubbed out with the rest of the
// DPL calls in the 2007 D3D port. D3D9 has no equivalent global: the
// fill mode is device state, so all this does is record the intent and
// let the frame apply it. See gWireframe at the top of this file.
//
gWireframe = !gWireframe;
//if ((wireframe_on ^= 1) != 0)
//{
// DEBUG_STREAM << "wireframe ON" << std::endl << std::flush;
// dpl_SetRenderProperty(dpl_render_prop_wireframe, dpl_render_value_on, NULL );
//}
//else
//{
// DEBUG_STREAM << "wireframe OFF" << std::endl << std::flush;
// dpl_SetRenderProperty(dpl_render_prop_wireframe, dpl_render_value_off, NULL );
//}
DEBUG_STREAM << "wireframe " << (gWireframe ? "ON" : "OFF")
<< std::endl << std::flush;
}
//
//#############################################################################