Files
arcattackandClaude Opus 4.8 7b7d465e5e Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.

Layout:
  engine/   MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
            work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
            models) + image codec; the minimal rp/ headers the audio HAL needs
  game/     reconstructed BT logic + surviving-original BT source + fwd shims
            + WinMain launcher
  content/  full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
  docs/     format specs + reconstruction ledgers
  reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
  tools/    MP console emulator + map/resource scanners

One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 21:03:40 -05:00

478 lines
15 KiB
C++

#include "mungal4.h"
#pragma hdrstop
#include "l4vidper.h"
//STUBBED: VIDEO RB 1/15/07
//extern "C" const int32 __sect_time;
//extern "C" const int32 __last_cull_time;
//extern "C" const int32 __last_draw_time;
//extern "C" const int32 __last_frame_time;
//extern "C" const int32 __last_pxpl_time;
//extern "C" const int32 __last_frame_prims;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor for the StripChartRenderable
// Used to performance monitor a variable that can change every frame
//
StripChartRenderable::StripChartRenderable(
Entity *entity, // Entity to attach the renderable to
ExecutionType execution_type, // How/when to execute the renderable
dpl_VIEW *this_view, // the view associated with our eye
float left,
float right,
float top,
float bottom,
int max_samples, // The number of samples to hold
int max_value, // The maximum value allowed
int min_value, // the minimum value allowed
int *value_to_chart, // the value we will be graphing
int update_interval // How frequently (in frames) to update the graphics
):
VideoRenderable(entity, execution_type)
{
//STUBBED: DPL RB 1/14/07
//int
// i;
////
//// Save the incoming data inside this class
////
//myView = this_view;
//myLeft = left;
//myRight = right;
//myTop = top;
//myBottom = bottom;
//myMaxSamples = max_samples;
//myMaxValue = max_value;
//myMinValue = min_value;
//myValue = value_to_chart;
//myUpdateInterval = update_interval;
//myFrameCount = 0;
//myCurrentSample = 0;
////
//// Allocate the RAM to store the values we are charting and clear them out
////
//myValueStorage = new int[max_samples];
//if(!myValueStorage)
// Fail("stripchart couldn't allocate value storage\n");
//Check_Pointer(myValueStorage);
//for(i = 0; i<max_samples; i++)
//{
// myValueStorage[i] = 0;
//}
////
//// Allocate space for the display list
////
//myDisplayList = dpl2d_NewDisplayList();
//if(!myDisplayList)
// Fail("stripchart couldn't allocate a display list\n");
////
//// Draw the bounding box for the chart
////
//dpl2d_OpenDisplayList (myDisplayList, dpl2d_open_mode_clear);
//dpl2d_AddFullScreenClipRegion (myDisplayList);
//dpl2d_AddSetColor (myDisplayList, 0.0f, 0.75f, 0.0f);
//dpl2d_AddOpenPolyline (myDisplayList);
//dpl2d_AddPoint (myDisplayList, myLeft, myBottom);
//dpl2d_AddPoint (myDisplayList, myRight, myBottom);
//dpl2d_AddPoint (myDisplayList, myRight, myTop);
//dpl2d_AddPoint (myDisplayList, myLeft, myTop);
//dpl2d_AddPoint (myDisplayList, myLeft, myBottom);
//dpl2d_AddClosePolyline (myDisplayList);
//dpl2d_CloseDisplayList (myDisplayList);
//dpl2d_FlushDisplayList (myDisplayList);
////
//// Bind the chart to our eyepoint
////
//dpl2d_SetViewDisplayList ( myView, myDisplayList );
//dpl_FlushView ( myView );
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Destructor for the StripChartRenderable
//
StripChartRenderable::~StripChartRenderable()
{
//STUBBED: DPL RB 1/14/07
////
//// Make sure our structure is still in one piece
////
//Check(this);
////
//// Unhook the display list from the view, then delete both lists
////
//dpl2d_SetViewDisplayList ( myView, NULL );
//dpl_FlushView ( myView );
//dpl2d_DeleteDisplayList(myDisplayList);
//delete myValueStorage;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// TestInstance for the StripChartRenderable
//
Logical
StripChartRenderable::TestInstance() const
{
VideoRenderable::TestInstance();
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute for the StripChartRenderable
//
void
StripChartRenderable::Execute()
{
//STUBBED: DPL RB 1/14/07
//int
// i;
////
//// Increment frame counter
////
//myFrameCount++;
////
//// Grab the statistic we're tracking and stuff it into the buffer
////
//myValueStorage[myCurrentSample] = *myValue;
////
//// If it's time to redraw the graph, do it
////
//if(myFrameCount >= myUpdateInterval)
//{
// myFrameCount = 0;
// //
// // Figure the scale factor for the graph
// //
// float
// current_x,
// current_y,
// x_increment,
// y_increment;
// x_increment = (myRight - myLeft)/ (float)(myMaxSamples);
// y_increment = (myBottom - myTop)/((float)myMaxValue - (float)myMinValue);
// dpl2d_OpenDisplayList (myDisplayList, dpl2d_open_mode_clear);
// dpl2d_AddFullScreenClipRegion (myDisplayList);
// dpl2d_AddSetColor (myDisplayList, 0.0f, 0.75f, 0.0f);
// dpl2d_AddOpenPolyline (myDisplayList);
// dpl2d_AddPoint (myDisplayList, myLeft, myBottom);
// dpl2d_AddPoint (myDisplayList, myRight, myBottom);
// dpl2d_AddPoint (myDisplayList, myRight, myTop);
// dpl2d_AddPoint (myDisplayList, myLeft, myTop);
// dpl2d_AddPoint (myDisplayList, myLeft, myBottom);
// dpl2d_AddClosePolyline (myDisplayList);
// dpl2d_AddOpenPolyline (myDisplayList);
// current_x = myLeft;
// for(i = 0; i < myMaxSamples; i++)
// {
// current_y = myBottom-((float)myValueStorage[i] * y_increment);
// dpl2d_AddPoint(myDisplayList,current_x,current_y);
// current_x += x_increment;
// }
// dpl2d_AddClosePolyline (myDisplayList);
// dpl2d_AddOpenLines (myDisplayList);
// dpl2d_AddPoint (myDisplayList,
// myLeft + (x_increment*myCurrentSample),
// myBottom);
// dpl2d_AddPoint (myDisplayList,
// myLeft + (x_increment*myCurrentSample),
// myTop);
// dpl2d_AddCloseLines (myDisplayList);
// dpl2d_CloseDisplayList (myDisplayList);
// dpl2d_FlushDisplayList (myDisplayList);
//}
////
//// Update the current sample pointer
////
//myCurrentSample ++;
//if(myCurrentSample >= myMaxSamples)
// myCurrentSample = 0;
////
//// Call the execute method in our parent
////
//VideoRenderable::Execute();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor for the RendererChartRenderable
// Used to performance monitor a variable that can change every frame
//
RendererChartRenderable::RendererChartRenderable(
Entity *entity, // Entity to attach the renderable to
ExecutionType execution_type, // How/when to execute the renderable
dpl_VIEW *this_view, // the view associated with our eye
float left,
float right,
float top,
float bottom,
int max_samples, // The number of samples to hold
int max_value, // The maximum value allowed
int min_value, // the minimum value allowed
int update_interval // How frequently (in frames) to update the graphics
):
VideoRenderable(entity, execution_type)
{
//STUBBED: DPL RB 1/14/07
//int
// i;
////
//// Save the incoming data inside this class
////
//myView = this_view;
//myLeft = left;
//myRight = right;
//myTop = top;
//myBottom = bottom;
//myMaxSamples = max_samples;
//myMaxValue = max_value;
//myMinValue = min_value;
//myUpdateInterval = update_interval;
//myFrameCount = 0;
//myCurrentSample = 0;
////
//// Allocate the RAM to store the values we are charting and clear them out
////
//myCullStorage = new int[max_samples];
//myDrawStorage = new int[max_samples];
//myFrameStorage = new int[max_samples];
//myPixelPlanesStorage = new int[max_samples];
//myPrimativeStorage = new int[max_samples];
//if(!myCullStorage || !myDrawStorage || !myFrameStorage || !myPixelPlanesStorage || !myPrimativeStorage)
// Fail("RendererChartRenderable couldn't allocate storage\n");
//Check_Pointer(myValueStorage);
//for(i = 0; i<max_samples; i++)
//{
// myCullStorage[i] = 0;
// myDrawStorage[i] = 0;
// myFrameStorage[i] = 0;
// myPixelPlanesStorage[i] = 0;
// myPrimativeStorage[i] = 0;
//}
////
//// Allocate space for the display list
////
//myDisplayList = dpl2d_NewDisplayList();
//if(!myDisplayList)
// Fail("stripchart couldn't allocate a display list\n");
////
//// Draw the bounding box for the chart
////
//dpl2d_OpenDisplayList (myDisplayList, dpl2d_open_mode_clear);
//dpl2d_AddFullScreenClipRegion (myDisplayList);
//dpl2d_AddSetColor (myDisplayList, 0.0f, 0.75f, 0.0f);
//dpl2d_AddSetLineWidth (myDisplayList,1.0);
//dpl2d_AddOpenPolyline (myDisplayList);
//dpl2d_AddPoint (myDisplayList, myLeft, myBottom);
//dpl2d_AddPoint (myDisplayList, myRight, myBottom);
//dpl2d_AddPoint (myDisplayList, myRight, myTop);
//dpl2d_AddPoint (myDisplayList, myLeft, myTop);
//dpl2d_AddPoint (myDisplayList, myLeft, myBottom);
//dpl2d_AddClosePolyline (myDisplayList);
////
//// Bind the chart to our eyepoint
////
//mySystemDisplayList = dpl2d_GetViewDisplayList (myView);
//if(mySystemDisplayList)
//{
// // If a display list was already installed, call it at the end of this
// // 2d display list so it will still show up. (ugley, but as this is
// // test code only it should be sufficient)
// dpl2d_AddCallDisplayList (myDisplayList, mySystemDisplayList );
//}
//dpl2d_CloseDisplayList (myDisplayList);
//dpl2d_FlushDisplayList (myDisplayList);
////
//// hook our dlist up to the view so it will be drawn
////
//dpl2d_SetViewDisplayList ( myView, myDisplayList );
//dpl_FlushView ( myView );
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Destructor for the RendererChartRenderable
//
RendererChartRenderable::~RendererChartRenderable()
{
//STUBBED: DPL RB 1/14/07
////
//// Make sure our structure is still in one piece
////
//Check(this);
////
//// Unhook the display list from the view, then delete both lists
////
//dpl2d_SetViewDisplayList ( myView, NULL );
//dpl_FlushView ( myView );
//dpl2d_DeleteDisplayList(myDisplayList);
//delete myCullStorage;
//delete myDrawStorage;
//delete myFrameStorage;
//delete myPixelPlanesStorage;
//delete myPrimativeStorage;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// TestInstance for the RendererChartRenderable
//
Logical
RendererChartRenderable::TestInstance() const
{
VideoRenderable::TestInstance();
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execute for the RendererChartRenderable
//
void
RendererChartRenderable::Execute()
{
//STUBBED: DPL RB 1/14/07
//int
// i;
////
//// Increment frame counter
////
//myFrameCount++;
////
//// Grab the statistic we're tracking and stuff it into the buffer
////
//myCullStorage[myCurrentSample] = __last_cull_time;
//myDrawStorage[myCurrentSample] = __last_draw_time;
//myFrameStorage[myCurrentSample] = __last_frame_time;
//myPixelPlanesStorage[myCurrentSample] = __last_pxpl_time;
//myPrimativeStorage[myCurrentSample] = __last_frame_prims;
////
//// If it's time to redraw the graph, do it
////
//if(myFrameCount >= myUpdateInterval)
//{
// myFrameCount = 0;
// //
// // Figure the scale factor for the graph
// //
// float
// current_x,
// current_y,
// x_increment,
// y_increment;
// x_increment = (myRight - myLeft)/ (float)(myMaxSamples);
// y_increment = (myBottom - myTop)/((float)myMaxValue - (float)myMinValue);
// dpl2d_OpenDisplayList (myDisplayList, dpl2d_open_mode_clear);
// dpl2d_AddFullScreenClipRegion (myDisplayList);
// dpl2d_AddSetLineWidth (myDisplayList,1.0);
// dpl2d_AddSetColor (myDisplayList, 0.0f, 0.75f, 0.0f);
// dpl2d_AddOpenPolyline (myDisplayList);
// dpl2d_AddPoint (myDisplayList, myLeft, myBottom);
// dpl2d_AddPoint (myDisplayList, myRight, myBottom);
// dpl2d_AddPoint (myDisplayList, myRight, myTop);
// dpl2d_AddPoint (myDisplayList, myLeft, myTop);
// dpl2d_AddPoint (myDisplayList, myLeft, myBottom);
// dpl2d_AddClosePolyline (myDisplayList);
// //
// // Draw the primative count trace
// //
// dpl2d_AddOpenLines (myDisplayList);
// dpl2d_AddPoint(myDisplayList,myLeft, myBottom + (500.0f * y_increment * 50.0f));
// dpl2d_AddPoint(myDisplayList,myRight, myBottom + (500.0f * y_increment * 50.0f));
// dpl2d_AddPoint(myDisplayList,myLeft, myBottom + (1000.0f * y_increment * 50.0f));
// dpl2d_AddPoint(myDisplayList,myRight, myBottom + (1000.0f * y_increment * 50.0f));
// dpl2d_AddCloseLines (myDisplayList);
// dpl2d_AddOpenPolyline (myDisplayList);
// current_x = myLeft;
// for(i = 0; i < myMaxSamples; i++)
// {
// current_y = myBottom+((float)myPrimativeStorage[i] * y_increment * 50.0f);
// dpl2d_AddPoint(myDisplayList,current_x,current_y);
// current_x += x_increment;
// }
// dpl2d_AddClosePolyline (myDisplayList);
// //
// // Draw the frame time trace
// //
// dpl2d_AddSetColor (myDisplayList, 0.75f, 0.75f, 0.75f);
// dpl2d_AddOpenPolyline (myDisplayList);
// current_x = myLeft;
// for(i = 0; i < myMaxSamples; i++)
// {
// current_y = myBottom-((float)myFrameStorage[i] * y_increment);
// dpl2d_AddPoint(myDisplayList,current_x,current_y);
// current_x += x_increment;
// }
// dpl2d_AddClosePolyline (myDisplayList);
// //
// // Draw the draw time trace
// //
// dpl2d_AddSetColor (myDisplayList, 0.75f, 0.0f, 0.0f);
// dpl2d_AddOpenPolyline (myDisplayList);
// current_x = myLeft;
// for(i = 0; i < myMaxSamples; i++)
// {
// current_y = myBottom-((float)myDrawStorage[i] * y_increment);
// dpl2d_AddPoint(myDisplayList,current_x,current_y);
// current_x += x_increment;
// }
// dpl2d_AddClosePolyline (myDisplayList);
// //
// // Draw the pixel planes time trace
// //
// dpl2d_AddSetColor (myDisplayList, 0.0f, 0.0f, 0.75f);
// dpl2d_AddOpenPolyline (myDisplayList);
// current_x = myLeft;
// for(i = 0; i < myMaxSamples; i++)
// {
// current_y = myBottom-((float)myPixelPlanesStorage[i] * y_increment);
// dpl2d_AddPoint(myDisplayList,current_x,current_y);
// current_x += x_increment;
// }
// dpl2d_AddClosePolyline (myDisplayList);
// //
// // Stack the cull time on top of the draw
// //
// dpl2d_AddSetColor (myDisplayList, 0.0f, 0.75f, 0.0f);
// dpl2d_AddOpenPolyline (myDisplayList);
// current_x = myLeft;
// for(i = 0; i < myMaxSamples; i++)
// {
// current_y = myBottom-(((float)myCullStorage[i] + (float)myDrawStorage[i]) * y_increment);
// dpl2d_AddPoint(myDisplayList,current_x,current_y);
// current_x += x_increment;
// }
// dpl2d_AddClosePolyline (myDisplayList);
// //
// // Draw a line indicating the current time
// //
// dpl2d_AddOpenLines (myDisplayList);
// dpl2d_AddPoint (myDisplayList,
// myLeft + (x_increment*myCurrentSample),
// myBottom);
// dpl2d_AddPoint (myDisplayList,
// myLeft + (x_increment*myCurrentSample),
// myTop);
// dpl2d_AddCloseLines (myDisplayList);
// //
// // If there is a pre existing dlist, insert a call to it here
// //
// if(mySystemDisplayList)
// {
// dpl2d_AddCallDisplayList (myDisplayList, mySystemDisplayList );
// }
// //
// // Close up the display list and flush it
// //
// dpl2d_CloseDisplayList (myDisplayList);
// dpl2d_FlushDisplayList (myDisplayList);
//}
////
//// Update the current sample pointer
////
//myCurrentSample ++;
//if(myCurrentSample >= myMaxSamples)
// myCurrentSample = 0;
////
//// Call the execute method in our parent
////
//VideoRenderable::Execute();
}