Files
TeslaRel410/restoration/source410/MUNGA_L4/L4GREND.CPP
T
CydandClaude Fable 5 df8c2552d0 BT410 5.3.87: OPERATOR-CONFIRMED -- both artifacts gone on a live mission
Full arena1 mission on the pod rig (podrun.sh pod_render_norio, 5.3.83-86
staged), run clean to steady state with no fault.  Operator: "the artifact
appears to be gone and the bleed from the control mode seems to be gone as
well."

Both reported symptoms -- the yellow-orange bar on the colour head and the
bleed into the MFDs -- from the one uninitialised read, closed by the one
zero-fill.

WEIGHT OF THE EVIDENCE, stated plainly rather than banked as a win:

  This is ONE run of an INTERMITTENT, heap-content-dependent artifact.  A
  clean run is exactly what the UNFIXED build also produced on the gauge A/B
  rig, three boots running, which is the whole reason the fix could not be
  verified there.  So the observation is not logically airtight on its own.

  What makes it convincing anyway is the shape of the fix rather than the
  count of runs: after it, no index in 64..255 can return anything but zero,
  whatever the heap holds.  The behaviour is deterministic by construction,
  where before it was a lottery.  Combined with the operator having seen the
  artifact repeatedly across BOTH this reconstruction and BT411, one clean
  run on the rig that was showing it is meaningful.

  Further clean runs strengthen it.  A recurrence would mean a SECOND source
  -- most likely whatever blits the *CRIT/*HEAT silhouettes, still
  unidentified, still carrying 1500-2500px of index 231 apiece -- and NOT a
  failed fix.  That distinction is worth keeping straight if it ever comes
  back.

Still open and unchanged by this: the 354px runtime-generated cluster, and
which widget blits the 231-bearing avatar art.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 08:19:44 -05:00

1010 lines
28 KiB
C++

//===========================================================================//
// File: l4grend.cc //
// Project: MUNGA Brick: LBE4 Gauge Renderer //
// Contents: //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 02/10/95 CPB Initial coding. //
// 04/12/95 CPB Moved BuildGraphicsPorts in from RP/BTL4GRND.CPP. //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. All rights reserved //
// PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include <mungal4.hpp>
#pragma hdrstop
#if !defined(L4APP_HPP)
# include <l4app.hpp>
#endif
#if !defined(TIME_HPP)
# include <time.hpp> // for profiling
#endif
#if !defined(L4GREND_HPP)
# include <l4grend.hpp>
#endif
#if !defined(L4GAUGE_HPP)
# include <l4gauge.hpp>
#endif
#if !defined(MISSION_HPP)
# include <mission.hpp>
#endif
#if !defined(L4PLASMA_HPP)
# include <l4plasma.hpp>
#endif
#if !defined(NOTATION_HPP)
# include <notation.hpp>
#endif
// #define LOCAL_TEST
#if defined(LOCAL_TEST)
# define Test_Tell(n) cout << n
#else
# define Test_Tell(n)
#endif
//
//#############################################################################
// L4MethodDescription list
//#############################################################################
//
MethodDescription
ChainToPrevious = METHOD_DESCRIPTION_CHAIN(NULL); // Null:end of chain
MethodDescription
*L4MethodDescription[] =
{
&MakeConfigMethodDescription,
&MakeExternConfigMethodDescription,
&BackgroundReconfig::methodDescription,
&BackgroundLine::methodDescription,
&BackgroundRect::methodDescription,
&BackgroundFilledRect::methodDescription,
&BackgroundPixelmap::methodDescription,
&BackgroundBitmap::methodDescription,
&NumericDisplayScalar::methodDescription,
&NumericDisplaySpeed::methodDescription,
&NumericDisplayInteger::methodDescription,
&DigitalClock::methodDescription,
&RankAndScore::methodDescription,
&BarGraphSolidScalar::methodDescription,
&BarGraphPixelMapScalar::methodDescription,
&ColorState::methodDescription,
&TwoState::methodDescription,
&SegmentArcNormalized::methodDescription,
&ChainToPrevious
};
//
//#############################################################################
// L4GaugeRenderer
//#############################################################################
//
L4GaugeRenderer::L4GaugeRenderer():
GaugeRenderer()
{
//
//---------------------------------------------------------------------
// Ensure that graphicsDisplay is NULL
//---------------------------------------------------------------------
//
graphicsDisplay = NULL;
externalDisplay = NULL;
palettesAreActive = True;
scrambleVideoFlag = False;
char
*mode_string = getenv("L4GAUGE");
//
//---------------------------------------------------------------------
// NOTE that L4Application::Initialize() searches for the environment
// variable "L4GAUGE" to determine whether or not to create
// a gauge renderer.
//---------------------------------------------------------------------
//
if (mode_string != NULL)
{
//
//---------------------------------------------------------------------
// Attempt to initialize external display
//---------------------------------------------------------------------
//
char
*plasma_string = getenv("L4PLASMA");
if (plasma_string != NULL)
{
if (strnicmp(plasma_string, "COM2", 4) == 0)
{
Tell("Plasma display created on COM2\n");
externalDisplay = new PlasmaDisplay(PCS_COM2);
}
else
{
Tell("Plasma display created on COM1\n");
externalDisplay = new PlasmaDisplay(PCS_COM1);
}
if (externalDisplay != NULL)
{
Register_Object(externalDisplay);
}
}
//
//---------------------------------------------------------------------
// Attempt to initialize main display
//---------------------------------------------------------------------
//-------------------------------------------------
// Search notation file for specified resolution
//-------------------------------------------------
//
NotationFile
notation_file("GAUGE\\L4GAUGE.INI");
if (!notation_file.PageExists(mode_string))
{
Tell("L4GaugeRenderer::L4GaugeRenderer - '" <<
mode_string <<
"' not found in L4GAUGE.INI!\n"
);
}
else
{
//
//-------------------------------------------------
// Requested resolution exists, read parameters
//-------------------------------------------------
//
int
mode(0),
width(640),
height(480),
page_size(64),
gran(64),
bpl(640*2),
pfp(0),
special(0),
q(0);
q += notation_file.GetEntry(mode_string, "mode", &mode);
q += notation_file.GetEntry(mode_string, "width", &width);
q += notation_file.GetEntry(mode_string, "height", &height);
q += notation_file.GetEntry(mode_string, "sizeInKB", &page_size);
q += notation_file.GetEntry(mode_string, "granularityInKB", &gran);
q += notation_file.GetEntry(mode_string, "bytesPerLine", &bpl);
q += notation_file.GetEntry(mode_string, "pageFcnPtr", &pfp);
q += notation_file.GetEntry(mode_string, "special", &special);
if (q == 8)
{
graphicsDisplay = new
SVGA16(
mode,
width,
height,
page_size,
gran,
bpl,
pfp,
special
);
if (graphicsDisplay != NULL)
{
Register_Object(graphicsDisplay);
}
}
}
}
Check_Fpu();
}
//
//#############################################################################
// ~L4GaugeRenderer
//#############################################################################
//
L4GaugeRenderer::~L4GaugeRenderer()
{
# if defined (LOCAL_TEST)
Tell("L4GaugeRenderer::~L4GaugeRenderer()\n");
# endif
Check(this);
int i;
//----------------------------------------------------
// Make sure all gauges removed first
//----------------------------------------------------
Remove(0);
//----------------------------------------------------
// Delete the graphics ports
//----------------------------------------------------
for(i=0; i<maximumGraphicsPorts; ++i)
{
if (graphicsPort[i] != NULL)
{
Check(graphicsPort[i]);
Unregister_Object(graphicsPort[i]);
delete graphicsPort[i];
}
}
if (graphicsDisplay != NULL)
{
Check(graphicsDisplay);
Unregister_Object(graphicsDisplay);
delete graphicsDisplay;
}
if (externalDisplay != NULL)
{
Check(externalDisplay);
Unregister_Object(externalDisplay);
delete externalDisplay;
}
Check_Fpu();
}
//
//#############################################################################
// LocalEmergencyShutdown - restore the ABSOLUTE MINIMUM to get back
// to the system!
//#############################################################################
//
void
L4GaugeRenderer::LocalEmergencyShutdown()
{
if (graphicsDisplay != NULL)
{
// It's an EMERGENCY: a 'verify' somewhere may have already failed.
// Therefore don't check it, just kill it!
delete graphicsDisplay;
}
GaugeRenderer::LocalEmergencyShutdown();
}
//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
L4GaugeRenderer::TestInstance() const
{
return GaugeRenderer::TestInstance();
}
//
//#############################################################################
// StartImplementation
//#############################################################################
//
void
L4GaugeRenderer::LoadMissionImplementation(Mission *mission)
{
Check(this);
# if defined (LOCAL_TEST)
Tell("L4GaugeRenderer::LoadMissionImplementation()\n");
# endif
GaugeRenderer::LoadMissionImplementation(mission);
Check_Fpu();
}
//
//#############################################################################
// StopImplementation
//#############################################################################
//
void
L4GaugeRenderer::ShutdownImplementation()
{
Check(this);
# if defined (LOCAL_TEST)
Tell("L4GaugeRenderer::ShutdownImplementation()\n");
# endif
// EVENTUALLY kill all interrupt-driven processes (if they exist)
GaugeRenderer::ShutdownImplementation();
Check_Fpu();
}
//
//#############################################################################
// SuspendImplementation
//#############################################################################
//
void
L4GaugeRenderer::SuspendImplementation()
{
Check(this);
# if defined (LOCAL_TEST)
Tell("L4GaugeRenderer::SuspendImplementation()\n");
# endif
GaugeRenderer::SuspendImplementation();
Check_Fpu();
}
//
//#############################################################################
// ResumeImplementation
//#############################################################################
//
void
L4GaugeRenderer::ResumeImplementation()
{
Check(this);
# if defined (LOCAL_TEST)
Tell("L4GaugeRenderer::ResumeImplementation()\n");
# endif
GaugeRenderer::ResumeImplementation();
Check_Fpu();
}
//
//#############################################################################
// ExecuteForeground
//#############################################################################
//
void
L4GaugeRenderer::ExecuteForeground()
{
Check(this);
//---------------------------------------
// We must call the ancestral method!
//---------------------------------------
GaugeRenderer::ExecuteForeground();
//---------------------------------------
// Process special effects
//---------------------------------------
if (graphicsDisplay != NULL)
{
Check(graphicsDisplay);
ProcessVideoEffects();
((SVGA16 *) graphicsDisplay)->UpdatePalette();
}
Check_Fpu();
}
//
//#############################################################################
// ExecuteImplementation
//#############################################################################
//
Logical
L4GaugeRenderer::ExecuteBackgroundDisplayUpdate()
{
Check(this);
Logical
result = False; // False == 'all done'
//--------------------------------------------------------
// Update external annunciator
//
// Allow the plasma display to continue if there's
// more background time available.
//
// This method is still called if taskmode is set to
// 'foreground'. If it's called in 'foreground' mode,
// it really means that we're still waiting for foreground
// to begin processing, so we might as well update the
// external display (if needed).
//--------------------------------------------------------
if (externalDisplay != NULL)
{
Check(externalDisplay);
result = externalDisplay->Update(False); // returns 'False' if done
}
//-------------------------------------------------------
// Update display ONLY in 'copy' mode
//--------------------------------------------------------
if (taskMode == copy)
{
if (graphicsDisplay != NULL)
{
Check(graphicsDisplay);
if (graphicsDisplay->Update(False) == False)
{
//--------------------------------------------------------
// Tell executionImplementation that we're basically done.
//--------------------------------------------------------
taskMode = foreground;
}
else
{
result = True; // We're not done yet!
}
}
}
return result;
}
//
//#############################################################################
// NotifyOfNewInterestingEntity
//#############################################################################
//
void
L4GaugeRenderer::NotifyOfNewInterestingEntity(
Entity *interesting_entity
)
{
SET_GAUGE_RENDERER();
Check(this);
Check(interesting_entity);
//----------------------------------------------
// Make sure gaugeImage exists for entity
//----------------------------------------------
Check(warehousePointer);
((L4Warehouse*)warehousePointer)->gaugeImageBin.Get(
interesting_entity->GetResourceID()
);
//----------------------------------------------
// Update gaugeRenderer
//----------------------------------------------
GaugeRenderer::NotifyOfNewInterestingEntity(interesting_entity);
Check_Fpu();
CLEAR_GAUGE_RENDERER();
}
//
//#############################################################################
// NotifyOfBecomingUninterestingEntity
//#############################################################################
//
void
L4GaugeRenderer::NotifyOfBecomingUninterestingEntity(
Entity *uninteresting_entity
)
{
SET_GAUGE_RENDERER();
Check(this);
Check(uninteresting_entity);
//----------------------------------------------
// Remove gaugeImage if no longer used
//----------------------------------------------
Check(warehousePointer);
((L4Warehouse*)warehousePointer)->gaugeImageBin.Release(
uninteresting_entity->GetResourceID()
);
//----------------------------------------------
// Update gaugeRenderer
//----------------------------------------------
GaugeRenderer::NotifyOfBecomingUninterestingEntity(uninteresting_entity);
Check_Fpu();
CLEAR_GAUGE_RENDERER();
}
//
//#############################################################################
// BuildGraphicsPort
//#############################################################################
//===========================================================================//
// RECONSTRUCTION SHADOW (source410 overrides CODE per build410.sh srcfor).
//
// Verbatim copy of CODE/RP/MUNGA_L4/L4GREND.CPP with ONE change: the port
// construction below builds a BTL4GraphicsPort instead of an L4GraphicsPort,
// to close the MFD-bleed artifact. Everything else is the archive's.
//
// THE ARTIFACT (operator report 2026-07-29: "artifacts bleeding over from the
// radar display into the MFDs ... I have noticed this in the BT411 builds as
// well, but does not happen in the original"):
//
// * The colour head is SIX BITS (L4GAUGE.CFG:4395, sec mask 0x003F) and the
// MFDs are bits 8-15 of the SAME 16-bit words -- one plane-packed
// framebuffer, so a colour-head defect can only surface as MFD garbage.
// * L4GraphicsPort::BuildSecondaryTranslation (L4VB16.CPP:5419) enumerates
// only the ACTIVE-bit combinations, filling 1<<numberOfBits entries of
// int translationTable[256] -- 64 for this port. Entries 64..255 are
// never written. Note the asymmetry: BuildAuxiliaryTranslation nests an
// IncrementInactive loop inside IncrementActive and so fills all 256,
// which is why the MONO MFD ports are safe by construction.
// * DrawPixelMap8 (L4VB16.CPP:2708) indexes that table with an 8-BIT source
// pixel and DrawPoint ORs the result in UNMASKED, so an out-of-range
// entry puts arbitrary bits into other ports' planes.
// * The colour head's own art carries out-of-range SENTINELS: AVACRIT.PCC
// is 94% <= 63 with 6% at exactly 231; BTSEC1.PCX is 99.8% <= 63 with
// 0.2% at 254. Drawn transparent they are skipped; drawn OPAQUE every
// pixel goes through the table.
//
// Why the original is PROBABLY clean (hypothesis, not proven): the port is
// heap-allocated, and an allocation that happens to arrive zeroed makes those
// reads colour 0 -- black, and invisible on a black head. Our heap has a
// different history. That would also explain why the artifact is
// INTERMITTENT and why the operator sees it in the BT411 builds too: it
// depends on heap CONTENTS, not on any drawing logic, and both reconstructions
// inherit the same latent read from the archive.
//
// The fix does not change drawing behaviour -- it only guarantees the
// out-of-range case draws colour 0, i.e. contributes no bits under DrawPoint's
// OR. That is the most conservative possible outcome and matches what the
// shipped binary is observed to do.
//
// THE OFFENDER IS NAMED (2026-07-29). BT_TRANS_PROVOKE (below) fills the
// tail with 0xFF00 instead of 0, which makes every out-of-range draw light
// all eight high-byte heads -- turning an invisible bug into a measurable
// one. On the boot cockpit it lights exactly 1030 pixels, and the mask
// splits into a glyph cluster plus ONE SOLID 13x52 BAR at screen
// (526,228)-(538,279).
//
// Decoding the art finds the source of that bar with no ambiguity left:
//
// BTSEC1.PCX, the colour head's own 480x640 background, contains exactly
// ONE out-of-range value in the whole image -- index 254, exactly 676
// pixels, a SOLID 52x13 RECTANGLE at (199,526)-(250,538).
//
// The sec port is configured at ROTATION 270 (L4GAUGE.CFG), which maps
// source (x,y) -> screen (y, 479-x). That places the rectangle at screen
// x 526..538, y 229..280. The measured mask is x 526..538, y 228..279.
// Same rectangle, to the pixel.
//
// So one uninitialised read produces BOTH reported symptoms, depending only
// on which bits the heap garbage happens to have set:
//
// low 6 bits set -> a coloured block on the COLOUR head. This is the
// operator's second report the same day, "that yellow
// orange artifact", a vertical bar beside the RANGE
// readout -- which is precisely where the rotated
// rectangle lands.
// high 8 bits set -> garbage in the MFD / ENG / COMM planes. This is the
// first report, "bleeding over ... into the MFDs".
//
// VERIFICATION STATUS:
//
// * MECHANISM: proven from source (asymmetric builders) AND live (the
// provoke control lights 1030 pixels that the fix zeroes).
// * OFFENDING ART: proven by decode (BTSEC1.PCX index 254, 676px, and the
// rotation arithmetic lands it on the reported spot).
// * NON-REGRESSIVE: gauge A/B, three boots (unfixed x2, fixed x1) score
// identically on every head -- Mfd1 132/0, Mfd2 37/7, Mfd3 23/0 --
// against a ~6px across-boot noise floor.
// * OPERATOR-CONFIRMED CURED, 2026-07-30. A full arena1 mission run on
// the pod rig (podrun.sh pod_render_norio, this build staged): "the
// artifact appears to be gone and the bleed from the control mode seems
// to be gone as well." Both reported symptoms, one run, no fault.
//
// The honest weight of that: it is ONE run of an INTERMITTENT,
// heap-content-dependent artifact, and a clean run is exactly what the
// UNFIXED build also produced on the gauge A/B rig. So it is not
// logically airtight on its own. What makes it convincing anyway is
// that the fix is deterministic by construction -- after it, no index
// in 64..255 can return anything but 0, whatever the heap holds -- and
// that the operator had been seeing the artifact repeatedly, across
// both this reconstruction and BT411. Further clean runs strengthen
// it; a recurrence would mean a SECOND source, not a failed fix.
//
// A first "fixed" capture appeared to REGRESS the MFDs by ~2700px. It was a
// bad grab (caught mid-draw); the rebuild-and-rerun matched the unfixed
// numbers exactly. Recorded here because the two-runs rule is what caught it.
//===========================================================================//
class BTL4GraphicsPort :
public L4GraphicsPort
{
public:
BTL4GraphicsPort(
Video16BitBuffered *graphics_display,
const char *name,
int rotation,
int bit_mask,
SVGA16::PaletteID palette_ID,
L4GraphicsPort::ChannelEnableID channel_enable
):
L4GraphicsPort(
graphics_display, name, rotation, bit_mask,
palette_ID, channel_enable
)
{
//
// SECONDARY ports only. The low byte non-zero is exactly the
// test BuildSecondaryTranslation asserts on
// (Verify((bitMask & 0xFF) != 0)); an AUXILIARY port fills all
// 256 entries itself and must not be touched.
//
if ((bit_mask & 0xFF) != 0)
{
int
first = 1 << numberOfBits,
i;
//
// POSITIVE CONTROL. Zero is the fix; it is also invisible,
// so on its own it cannot tell us whether the out-of-range
// path is ever TAKEN on a given screen. BT_TRANS_PROVOKE
// fills the same tail with every MFD bit instead: if the
// path fires, the MFD heads flood with garbage and the A/B
// scoreboard's "extra" columns explode. If they do not
// move, the sec port never sees an out-of-range index on
// that screen and the fix is inert there.
//
int
fill = (getenv("BT_TRANS_PROVOKE") != NULL) ? 0xFF00 : 0;
for (i = first; i < 256; ++i)
{
translationTable[i] = fill;
}
}
}
};
//
void
L4GaugeRenderer::BuildGraphicsPort(
int port_number,
const char *name,
int rotation,
int bitAllocation,
SVGA16::PaletteID palette_ID,
L4GraphicsPort::ChannelEnableID enable_ID,
Palette8 *palette
)
{
Test_Tell("L4GaugeRenderer::BuildGraphicsPort\n");
Check(this);
if (graphicsDisplay != NULL)
{
Test_Tell("...non-NULL display\n");
Verify(port_number < maximumGraphicsPorts);
Verify(port_number >= 0);
Test_Tell("...port_number= " << port_number << "\n");
//
//---------------------------------------------------------
// If it already exists, delete it
//---------------------------------------------------------
//
L4GraphicsPort
*graphics_port = (L4GraphicsPort *) graphicsPort[port_number];
if (graphics_port != NULL)
{
Test_Tell("...deleting existing port\n");
Check(graphics_port);
Unregister_Object(graphics_port);
delete graphics_port;
}
//
//---------------------------------------------------------
// Attempt to create it
//---------------------------------------------------------
//
graphicsPort[port_number] = new BTL4GraphicsPort(
(Video16BitBuffered *) graphicsDisplay,
name,
rotation,
bitAllocation,
palette_ID,
enable_ID
);
graphics_port = (L4GraphicsPort *) graphicsPort[port_number];
Test_Tell("...new port at " << graphics_port << "\n");
//
//---------------------------------------------------------
// If created, register it and build the palette
//---------------------------------------------------------
//
if (graphics_port != NULL)
{
Check(graphics_port);
Register_Object(graphics_port);
//
// Set the palette for the port
// (Note: secondary uses lowest 8 bits)
//
if ((bitAllocation > 0) && (bitAllocation < 0x0100))
{
Test_Tell("...secondary\n");
graphics_port->SetSecondaryPalette(palette);
}
else
{
Test_Tell("...auxiliary\n");
graphics_port->SetAuxiliaryPalette();
}
}
}
Check_Fpu();
}
//
//#############################################################################
// RemapGraphicsPort
//#############################################################################
//
void
L4GaugeRenderer::RemapGraphicsPort(
int port_number,
SVGA16::PaletteID palette_ID,
L4GraphicsPort::ChannelEnableID enable_ID,
Palette8 *palette
)
{
Check(this);
Test_Tell("L4GaugeRenderer::RemapGraphicsPort\n");
if (graphicsDisplay != NULL)
{
Test_Tell("...non-NULL display\n");
Verify(port_number < maximumGraphicsPorts);
Verify(port_number >= 0);
Test_Tell("...port_number= " << port_number << "\n");
//---------------------------------------------------------
// If it exists, change the palette ID and set the palette
//---------------------------------------------------------
L4GraphicsPort
*graphics_port = (L4GraphicsPort *) graphicsPort[port_number];
if (graphics_port != NULL)
{
Check(graphics_port);
//
// Set the palette ID
//
graphics_port->SetPaletteID(palette_ID);
graphics_port->SetEnableID(enable_ID);
//
// Set the palette for the port
// (Note: secondary uses lowest 8 bits)
//
int
bit_mask = graphics_port->GetBitMask();
if (bit_mask & 0x00FF) // must be secondary
{
Test_Tell("...secondary\n");
Verify(palette != NULL);
graphics_port->SetSecondaryPalette(palette);
}
else
{
Test_Tell("...auxiliary\n");
graphics_port->SetAuxiliaryPalette();
}
}
}
Check_Fpu();
}
//
//#############################################################################
// BuildExternalGraphicsPort
//#############################################################################
//
void
L4GaugeRenderer::BuildExternalGraphicsPort(
int port_number,
const char *name,
int /*bitAllocation*/
)
{
Check(this);
Test_Tell(
"L4GaugeRenderer::BuildExternalGraphicsPort(" << port_number << ")\n"
);
if (externalDisplay != NULL)
{
Test_Tell("...non-NULL display\n");
Verify(port_number < maximumGraphicsPorts);
Verify(port_number >= 0);
Test_Tell("...port_number= " << port_number << "\n");
//
//---------------------------------------------------------
// If it already exists, delete it
//---------------------------------------------------------
//
L4GraphicsPort
*graphics_port = (L4GraphicsPort *) graphicsPort[port_number];
if (graphics_port != NULL)
{
Test_Tell("...deleting existing port\n");
Check(graphics_port);
Unregister_Object(graphics_port);
delete graphics_port;
}
//
//---------------------------------------------------------
// Attempt to create it
//---------------------------------------------------------
//
graphicsPort[port_number] = new L4BytePort(
(Video8BitBuffered *) externalDisplay,
name,
0 // rotation
);
graphics_port = (L4GraphicsPort *) graphicsPort[port_number];
Test_Tell("...new port at " << graphics_port << "\n");
//
//---------------------------------------------------------
// If created, register it
//---------------------------------------------------------
//
if (graphics_port != NULL)
{
Check(graphics_port);
Register_Object(graphics_port);
}
}
Check_Fpu();
}
//
//#############################################################################
// FadeToWhite, FadeToGame
//#############################################################################
//
void
L4GaugeRenderer::FadeToWhite(Scalar number_of_seconds)
{
Check(this);
Verify(number_of_seconds >= 0.0); // zero is allowed (instant change)
// cout << "L4GaugeRenderer::FadeToWhite(" << number_of_seconds << ")\n";
if (graphicsDisplay != NULL)
{
Check(graphicsDisplay);
((SVGA16 *)graphicsDisplay)->FadeToWhite(number_of_seconds);
}
Check_Fpu();
}
void
L4GaugeRenderer::FadeToNormal(Scalar number_of_seconds)
{
Check(this);
Verify(number_of_seconds >= 0.0); // zero is allowed (instant change)
// cout << "L4GaugeRenderer::FadeToNormal(" << number_of_seconds << ")\n";
if (graphicsDisplay != NULL)
{
Check(graphicsDisplay);
((SVGA16 *)graphicsDisplay)->FadeToPalettes(number_of_seconds);
}
Check_Fpu();
}
//
//#############################################################################
// Configure
//#############################################################################
//
void
L4GaugeRenderer::ConfigureForModel(
const char *configuration_name,
Entity *entity
)
{
Check(this);
Check_Pointer(configuration_name);
Test_Tell(
"L4GaugeRenderer::ConfigureForModel(" <<
configuration_name << ", " <<
entity << ")\n"
);
Check(application);
Check(entity);
Mission
*mission = application->GetCurrentMission();
Check(mission);
const char
*model_name = mission->GetGameModel();
Check_Pointer(model_name);
char
full_name[64];
Str_Copy(full_name, model_name, sizeof(full_name));
Str_Cat(full_name, configuration_name, sizeof(full_name));
Test_Tell(
"L4GaugeRenderer::ConfigureForModel, full_name=" << full_name <<
")\n"
);
Configure(full_name, entity);
Check_Fpu();
}
//
//#############################################################################
// SpecialEffect
//#############################################################################
//
void
L4GaugeRenderer::SpecialEffect(
VideoEffectType type,
Scalar duration
)
{
Check(this);
switch (type)
{
case scrambleVideo:
if (graphicsDisplay != NULL)
{
scrambleVideoFlag = True;
scrambleVideoTimeout = ((Scalar)Now()) + duration;
Check(graphicsDisplay);
((SVGA16*) graphicsDisplay)->FunkyVideo(True);
}
break;
// other modes go here
}
Check_Fpu();
}
void
L4GaugeRenderer::ProcessVideoEffects()
{
Check(this);
Check(graphicsDisplay);
Time
now = Now();
if (scrambleVideoFlag)
{
if (now >= scrambleVideoTimeout)
{
scrambleVideoFlag = False;
((SVGA16*) graphicsDisplay)->FunkyVideo(False);
}
}
Check_Fpu();
}
//--------------------------------------------------------------------
// Profiling support
//--------------------------------------------------------------------
Scalar
L4GaugeRenderer::GetCurrentFramePercentage()
{
Check(this);
return Get_Frame_Percent_Used();
}