Files
BT412/engine/MUNGA/RENDERER.h
T
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

741 lines
17 KiB
C++

#pragma once
#include "interest.h"
#include "rndorgn.h"
#include "resource.h"
class DamageZone;
class Subsystem;
//~~~~~~~~~~~~~~~~~~~~~~~~~ Renderer support types ~~~~~~~~~~~~~~~~~~~~~~~~~
typedef Scalar RendererRate;
extern const RendererRate DefaultRendererRate;
typedef Scalar RendererComplexity;
extern const RendererComplexity MaxRendererComplexity;
extern const RendererComplexity MinRendererComplexity;
typedef Scalar RendererFrameBudget;
extern const RendererFrameBudget DefaultRendererFrameBudget;
enum RendererPriority
{
LowRendererPriority = 0,
DefaultRendererPriority,
HighRendererPriority
};
enum RendererStatus
{
InactiveRendererStatus,
LoadingRendererStatus,
RunningRendererStatus
};
//##########################################################################
//########################### Renderer ###############################
//##########################################################################
class Renderer__NotifyOfNewInterestingEntityMessage;
class Renderer__NotifyOfBecomingUninterestingEntityMessage;
class Renderer__StartEntityEffectMessage;
class Renderer__StopAllEntityEffectsMessage;
class Renderer__StartEntityAlarmMessage;
class Renderer__StopEntityAlarmMessage;
class Renderer:
public Receiver
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Destruction, and Testing
//
public:
~Renderer();
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Control and processing
//
public:
//
//-----------------------------------------------------------------------
// LoadMission, Shutdown
//-----------------------------------------------------------------------
//
void
LoadMission(Mission *mission);
void
Shutdown();
//
//-----------------------------------------------------------------------
// LinkToEntity
//
// This method links the renderer to an entity. Overrides must call
// the inherited method.
//-----------------------------------------------------------------------
//
virtual void
LinkToEntity(Entity *entity);
//
//-----------------------------------------------------------------------
// UnlinkFromEntity
//-----------------------------------------------------------------------
//
virtual void
UnlinkFromEntity();
//
//-----------------------------------------------------------------------
// SetRendererStatusToRunning
//-----------------------------------------------------------------------
//
void
SetRendererStatusToRunning();
//
//-----------------------------------------------------------------------
// UpdateInterestOrigin
//-----------------------------------------------------------------------
//
void
UpdateInterestOrigin(Time target_render_time);
//
//-----------------------------------------------------------------------
// Execute
//-----------------------------------------------------------------------
//
void Execute(Time target_render_time, RendererComplexity complexity_update);
virtual void ExecuteIdle();
virtual Logical ExecuteBackground();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Accessors
//
public:
//
//-----------------------------------------------------------------------
// GetLinkedEntity
//-----------------------------------------------------------------------
//
Entity*
GetLinkedEntity();
//
//-----------------------------------------------------------------------
// GetRendererStatus
//-----------------------------------------------------------------------
//
RendererStatus
GetRendererStatus();
//
//-----------------------------------------------------------------------
// Misc
//-----------------------------------------------------------------------
//
RendererComplexity
GetCalibrationComplexity();
Time
GetCalibrationFrameDuration();
RendererRate
GetCalibrationRate();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Interest Manager support
//
public:
//
//-----------------------------------------------------------------------
// NotifyOfNewInterestingEntity
//-----------------------------------------------------------------------
//
virtual void
NotifyOfNewInterestingEntity(Entity *) {}
//
//-----------------------------------------------------------------------
// NotifyOfBecomingUninterestingEntity
//-----------------------------------------------------------------------
//
virtual void
NotifyOfBecomingUninterestingEntity(Entity *) {}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Message Support
//
public:
enum {
NotifyOfNewInterestingEntityMessageID = Receiver::NextMessageID,
NotifyOfBecomingUninterestingEntityMessageID,
StartEntityEffectMessageID,
StopAllEntityEffectsMessageID,
StartEntityAlarmMessageID,
StopEntityAlarmMessageID,
NextMessageID
};
typedef Renderer__NotifyOfNewInterestingEntityMessage
NotifyOfNewInterestingEntityMessage;
typedef Renderer__NotifyOfBecomingUninterestingEntityMessage
NotifyOfBecomingUninterestingEntityMessage;
typedef Renderer__StartEntityEffectMessage
StartEntityEffectMessage;
typedef Renderer__StopAllEntityEffectsMessage
StopAllEntityEffectsMessage;
typedef Renderer__StartEntityAlarmMessage
StartEntityAlarmMessage;
typedef Renderer__StopEntityAlarmMessage
StopEntityAlarmMessage;
static const HandlerEntry
MessageHandlerEntries[];
//static MessageHandlerSet MessageHandlers;
static MessageHandlerSet& GetMessageHandlers();
void
NotifyOfNewInterestingEntityMessageHandler(
NotifyOfNewInterestingEntityMessage *message
);
void
NotifyOfBecomingUninterestingEntityMessageHandler(
NotifyOfBecomingUninterestingEntityMessage *message
);
void
StartEntityEffectMessageHandler(
StartEntityEffectMessage *message
);
void
StopAllEntityEffectsMessageHandler(
StopAllEntityEffectsMessage *message
);
void
StartEntityAlarmMessageHandler(
StartEntityAlarmMessage *message
);
void
StopEntityAlarmMessageHandler(
StopEntityAlarmMessage *message
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//
public:
static Derivation *GetClassDerivations();
static SharedData DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction
//
protected:
//
//-----------------------------------------------------------------------
// Construction
//
// Where calibration_rate indicates the update rate, and
// calibration_complexity indicates an arbitrary "maximum" complexity
// level passed to the renderer. The renderer manager will dynamically
// vary the value of complexity based on the actual frame rate that the
// renderer is able to maintain (if the total system load exceeds
// 100% of the maximum, each renderer's actual frame rate will drop
// below the requested rate: the renderer manager will detect this and
// lower the complexity value). The renderer manager will then
// periodically invoke the renderer's execute function, passing it the
// value indicated in complexity.
//-----------------------------------------------------------------------
//
Renderer(
RendererRate calibration_rate,
RendererComplexity calibration_complexity,
RendererPriority calibration_priority,
InterestType interest_type,
InterestDepth depth_calibration,
ClassID class_ID=TrivialReceiverClassID,
SharedData &virtual_data=DefaultData
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Protected accessors
//
protected:
//
//-----------------------------------------------------------------------
// GetInterestOrigin
//-----------------------------------------------------------------------
//
RendererOrigin*
GetInterestOrigin();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Protected implementations
//
protected:
Time mTargetRenderTime;
//
//-----------------------------------------------------------------------
// Execute
//
// This method is called by the rendering manager to execute renderer
// updates. Overrides must call the inherited method.
//-----------------------------------------------------------------------
//
virtual void
ExecuteImplementation(
RendererComplexity complexity_update,
RendererOrigin::InterestingEntityIterator *iterator
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private implementations
//
private:
virtual void
LoadMissionImplementation(Mission *mission);
virtual void
ShutdownImplementation();
virtual void
StartEntityEffectImplementation(
Entity *entity,
DamageZone *damage_zone,
ResourceDescription::ResourceID resource_ID
)
{}
virtual void
StopAllEntityEffectsImplementation(Entity *entity)
{}
virtual void
StartEntityAlarmImplementation(
Entity *entity,
Subsystem *subsystem,
Enumeration condition,
ResourceDescription::ResourceID resource_ID
)
{}
virtual void
StopEntityAlarmImplementation(
Entity *entity,
Subsystem *subsystem,
Enumeration condition
)
{}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
//
// Current running state of the renderer
//
RendererStatus
rendererStatus;
//
// Renderer frame rate related valriables
//
RendererRate
calibrationRate;
Time
calibrationFrameDuration,
nextRenderTime;
//
// Renderer complexity, depth, and priority
// control related variables
//
RendererComplexity
calibrationComplexity;
RendererPriority
calibrationPriority;
InterestType
interestType;
InterestDepth
depthCalibration;
RendererFrameBudget
framePercentBudget;
//
// Sockets
//
SlotOf<RendererOrigin*>
rendererOriginSocket;
SlotOf<Entity*>
entitySocket;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Renderer inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~
inline Entity*
Renderer::GetLinkedEntity()
{
Check(&entitySocket);
return entitySocket.GetCurrent();
}
inline RendererOrigin*
Renderer::GetInterestOrigin()
{
Check(&rendererOriginSocket);
return rendererOriginSocket.GetCurrent();
}
inline RendererStatus
Renderer::GetRendererStatus()
{
Check(this);
return rendererStatus;
}
inline RendererComplexity
Renderer::GetCalibrationComplexity()
{
Check(this);
return calibrationComplexity;
}
inline Time
Renderer::GetCalibrationFrameDuration()
{
Check(this);
return calibrationFrameDuration;
}
inline RendererRate
Renderer::GetCalibrationRate()
{
Check(this);
return calibrationRate;
}
inline void Renderer::ExecuteIdle()
{
Check(this);
return;
}
inline Logical Renderer::ExecuteBackground()
{
Check(this);
return False;
}
//##########################################################################
//######################## RendererManager ###########################
//##########################################################################
class RendererManager:
public Receiver
{
friend class Renderer;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction. Testing
//
public:
RendererManager();
~RendererManager();
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Control, and processing
//
public:
//
//-----------------------------------------------------------------------
// UpdateInterestOrigins
//
// Called by the application to update the renderers interest origins
// before the interest manager performs its execute method.
//-----------------------------------------------------------------------
//
void
UpdateInterestOrigins(Time target_render_time);
//
//-----------------------------------------------------------------------
// Execute
//
// Perform renderer management functions
//-----------------------------------------------------------------------
//
void
Execute(
Time target_render_time,
Time target_frame_duration,
Time actual_frame_duration
);
//
//-----------------------------------------------------------------------
// ExecuteIdle
//
// Allow renderers to perform functions during idle (WaitingForEgg)
//-----------------------------------------------------------------------
//
void ExecuteIdle();
//
//-----------------------------------------------------------------------
// AreRenderersRunning
//-----------------------------------------------------------------------
//
Logical
AreRenderersRunning();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Effects and Alarms
//
public:
void
StartEntityEffect(
Entity *entity,
DamageZone *damage_zone,
ResourceDescription::ResourceID resource_ID
);
void
StopAllEntityEffects(Entity *entity);
void
StartEntityAlarm(
Entity *entity,
Subsystem *subsystem,
Enumeration condition,
ResourceDescription::ResourceID resource_ID
);
void
StopEntityAlarm(
Entity *entity,
Subsystem *subsystem,
Enumeration condition
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private methods
//
private:
void
StartRenderer(Renderer *renderer);
void
StopRenderer(Renderer *renderer);
void
RendererManager::PostRendererEvent(
Entity *entity,
Receiver::Message *message
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
SChainOf<Renderer*>
renderers;
};
//~~~~~~~~~~~~~~ Renderer__NotifyOfNewInterestingEntityMessage ~~~~~~~~~~~~~
class Renderer__NotifyOfNewInterestingEntityMessage:
public Receiver::Message
{
public:
Renderer__NotifyOfNewInterestingEntityMessage(
Entity *interesting_entity
);
Entity*
GetInterestingEntity();
private:
EntityID
entityID;
};
//~~~~~~~~~~ Renderer__NotifyOfBecomingUninterestingEntityMessage ~~~~~~~~~~
class Renderer__NotifyOfBecomingUninterestingEntityMessage:
public Receiver::Message
{
public:
Renderer__NotifyOfBecomingUninterestingEntityMessage(
Entity *uninteresting_entity
);
Entity*
GetUninterestingEntity()
{return uninterestingEntity;}
private:
Entity
*uninterestingEntity;
};
//~~~~~~~~~~~~~~~~~~~~~~~ Renderer__EntityMessage ~~~~~~~~~~~~~~~~~~~~~~~~~~
class Renderer__EntityMessage:
public Receiver::Message
{
public:
Renderer__EntityMessage(
Receiver::MessageID message_ID,
size_t message_size,
Entity *entity
);
Entity*
GetEntity();
private:
EntityID
entityID;
};
//~~~~~~~~~~~~~~~~~~ Renderer__StartEntityEffectMessage ~~~~~~~~~~~~~~~~~~~~
class Renderer__StartEntityEffectMessage:
public Renderer__EntityMessage
{
public:
Renderer__StartEntityEffectMessage(
Entity *entity,
DamageZone *damage_zone,
ResourceDescription::ResourceID resource_ID
);
DamageZone*
GetDamageZone()
{return damageZone;}
ResourceDescription::ResourceID
GetResourceID()
{return resourceID;}
private:
DamageZone
*damageZone;
ResourceDescription::ResourceID
resourceID;
};
//~~~~~~~~~~~~~~~~~~ Renderer__StopAllEntityEffectsMessage ~~~~~~~~~~~~~~~~~
class Renderer__StopAllEntityEffectsMessage:
public Renderer__EntityMessage
{
public:
Renderer__StopAllEntityEffectsMessage(Entity *entity);
};
//~~~~~~~~~~~~~~~~~~ Renderer__StartEntityAlarmMessage ~~~~~~~~~~~~~~~~~~~~~
class Renderer__StartEntityAlarmMessage:
public Renderer__EntityMessage
{
public:
Renderer__StartEntityAlarmMessage(
Entity *entity,
Subsystem *alarm_subsystem,
Enumeration alarm_condition,
ResourceDescription::ResourceID resource_ID
);
Subsystem*
GetSubsystem()
{return subsystem;}
Enumeration
GetCondition()
{return condition;}
ResourceDescription::ResourceID
GetResourceID()
{return resourceID;}
private:
Subsystem
*subsystem;
Enumeration
condition;
ResourceDescription::ResourceID
resourceID;
};
//~~~~~~~~~~~~~~~~~~ Renderer__StopEntityAlarmMessage ~~~~~~~~~~~~~~~~~~~~~~
class Renderer__StopEntityAlarmMessage:
public Renderer__EntityMessage
{
public:
Renderer__StopEntityAlarmMessage(
Entity *entity,
Subsystem *alarm_subsystem,
Enumeration alarm_condition
);
Subsystem*
GetSubsystem()
{return subsystem;}
Enumeration
GetCondition()
{return condition;}
private:
Subsystem
*subsystem;
Enumeration
condition;
};
//~~~~~~~~~~~~~~~~~~~~~~ RendererManager inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline void
RendererManager::StartEntityEffect(
Entity *entity,
DamageZone *damage_zone,
ResourceDescription::ResourceID resource_ID
)
{
Renderer::StartEntityEffectMessage
message(entity, damage_zone, resource_ID);
PostRendererEvent(entity, &message);
}
inline void
RendererManager::StopAllEntityEffects(Entity *entity)
{
Renderer::StopAllEntityEffectsMessage
message(entity);
PostRendererEvent(entity, &message);
}
inline void
RendererManager::StartEntityAlarm(
Entity *entity,
Subsystem *alarm_subsystem,
Enumeration alarm_condition,
ResourceDescription::ResourceID resource_ID
)
{
Renderer::StartEntityAlarmMessage
message(entity, alarm_subsystem, alarm_condition, resource_ID);
PostRendererEvent(entity, &message);
}
inline void
RendererManager::StopEntityAlarm(
Entity *entity,
Subsystem *alarm_subsystem,
Enumeration alarm_condition
)
{
Renderer::StopEntityAlarmMessage
message(entity, alarm_subsystem, alarm_condition);
PostRendererEvent(entity, &message);
}