Frame the Winners Circle for the shape it was built for

The stand was composed to be looked at from a 4:3 pod monitor. On a 16:9
canvas its platform runs out at the sides and the shot fills up with sky
and void, so the podium is now pillarboxed: the scene renders into a
centred 4:3 viewport with the surround left black.

The projection has to use the cropped shape too, or the scene comes out
squashed into the narrower viewport instead of cropped by it.
RP412PODIUMASPECT overrides the ratio, 0 turns it off.

The camera also came in closer, from 33 units rather than 45, and now
aims slightly below the group rather than above it. That tilt is what
buys back the sky above the grandstand - aiming above the group tips the
camera up instead and walks the winner's spot off the bottom of the
frame, which is the one position that has to be in shot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-27 10:05:45 -05:00
co-authored by Claude Fable 5
parent 461dcfb6b9
commit 28df53aa31
3 changed files with 81 additions and 6 deletions
+66 -1
View File
@@ -1802,6 +1802,7 @@ DPLRenderer::DPLRenderer(
// the next race re-reads viewangle from RPDPL.INI.
mPresentationCamera = False;
mPresentationFog = False;
mPresentationAspect = 0.0f;
D3DXMatrixIdentity(&mPresentationView);
dplMainView = NULL;
dplDeathZone = NULL;
@@ -2374,6 +2375,20 @@ void
// tells the end-of-mission fade to stand down
mPresentationFog = True;
//
// Crop to the shape the stand was composed for. 4:3 unless
// RP412PODIUMASPECT says otherwise; 0 turns it off and lets
// the podium run full width.
//
mPresentationAspect = 4.0f / 3.0f;
{
const char *aspect = getenv("RP412PODIUMASPECT");
if (aspect != NULL)
{
mPresentationAspect = (float) atof(aspect);
}
}
// unconditional: fogUpdating is off while a vehicle drives its own
// headlight fog, and the podium overrides all of that
if (mDevice != NULL)
@@ -6094,6 +6109,36 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte
lastFrameTime = mTargetRenderTime;
currentFrameTime = Now();
//
// Pillarbox: black the whole target first, then narrow the viewport so
// everything after this - clear, scene, reticle - lands inside the crop
// and the surround stays black. Restored after Present.
//
if (mPresentationAspect > 0.0f)
{
D3DVIEWPORT9 full;
full.X = 0;
full.Y = 0;
full.Width = mPresentParams.BackBufferWidth;
full.Height = mPresentParams.BackBufferHeight;
full.MinZ = 0.0f;
full.MaxZ = 1.0f;
mDevice->SetViewport(&full);
mDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
DWORD cropped = (DWORD)
(mPresentParams.BackBufferHeight * mPresentationAspect);
if (cropped > mPresentParams.BackBufferWidth)
{
cropped = mPresentParams.BackBufferWidth;
}
D3DVIEWPORT9 crop = full;
crop.Width = cropped;
crop.X = (mPresentParams.BackBufferWidth - cropped) / 2;
mDevice->SetViewport(&crop);
}
DWORD currentFog;
mDevice->GetRenderState(D3DRS_FOGCOLOR, &currentFog);
hr = mDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, currentFog, 1.0f, 0);
@@ -6253,6 +6298,19 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte
hr = mDevice->Present(NULL, NULL, gMainPresentWindow, NULL);
// hand the whole target back
if (mPresentationAspect > 0.0f)
{
D3DVIEWPORT9 full;
full.X = 0;
full.Y = 0;
full.Width = mPresentParams.BackBufferWidth;
full.Height = mPresentParams.BackBufferHeight;
full.MinZ = 0.0f;
full.MaxZ = 1.0f;
mDevice->SetViewport(&full);
}
//
// RP412RENDERDIAG=1: did the ending frame actually reach the window, and
// what colour did it clear to? A black clear with a blue-violet fog set
@@ -6889,11 +6947,18 @@ void DPLRenderer::SetViewAngle(Degree new_angle)
viewRatio = (float) tan(view_angle / 2.0f);
aspectRatio = (float) y_size / (float) x_size;
// pillarboxed shots render into a narrower viewport, so the projection
// has to use that shape or the scene comes out squashed rather than
// cropped
float projection_aspect = (mPresentationAspect > 0.0f)
? mPresentationAspect
: ((float) x_size / (float) y_size);
D3DXMatrixIdentity(&mProjectionMatrix);
D3DXMatrixPerspectiveFovLH(
&mProjectionMatrix,
viewAngle * (PI / 180.0f),
(float) x_size / (float) y_size,
projection_aspect,
clipNear,
clipFar);
mProjectionMatrix(0, 0) *= -1; // handedness flip - the view is RH