Files
TeslaRel410/CODE/RP/MUNGA/CAMSHIP.CPP
T
CydandClaude Fable 5 fdd9ac9d97 Initial import: Tesla Release 4.10 (Tesla:BattleTech & Tesla:Red Planet)
Archival snapshot of the Virtual World Entertainment Tesla cockpit
software, 1994-1996: MUNGA engine and L4 pod layer source (Borland
C++ 5.0), BT/RP game code, and game content (models, audio, maps,
gauges, Division renderer data). Includes third-party libraries:
Division dVS/DPL graphics, HMI SOS audio, WATTCP networking.

Files are preserved byte-for-byte (.gitattributes disables all
line-ending conversion). README.md documents the layout, target
hardware, and toolchain.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 13:21:58 -05:00

768 lines
19 KiB
C++

//===========================================================================//
// File: camship.cc //
// Project: Munga //
// Contents: CameraShip Controls the current viewpoint of the cameraShip & //
// manages the simulation modes //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 08/09/95 JM Initial coding. //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
//
// munga Includes
//
#include <munga.hpp>
#pragma hdrstop
#if !defined(CAMSHIP_HPP)
# include <camship.hpp>
#endif
#if !defined(PLAYER_HPP)
# include <player.hpp>
#endif
#if !defined(MISSION_HPP)
# include <mission.hpp>
#endif
#if !defined(CAMMPPR_HPP)
# include <cammppr.hpp>
#endif
#if !defined(APP_HPP)
#include <app.hpp>
#endif
#if !defined(HOSTMGR_HPP)
#include <hostmgr.hpp>
#endif
//##########################################################################
//############################# CameraShip ################################
//##########################################################################
//#############################################################################
// Shared Data Support
//
Derivation
CameraShip::ClassDerivations(
Mover::ClassDerivations,
"CameraShip"
);
CameraShip::SharedData
CameraShip::DefaultData(
CameraShip::ClassDerivations,
CameraShip::MessageHandlers,
CameraShip::AttributeIndex,
CameraShip::StateCount,
(Entity::MakeHandler)CameraShip::Make
);
//#############################################################################
// Attribute Support
//
const CameraShip::IndexEntry
CameraShip::AttributePointers[]=
{
ATTRIBUTE_ENTRY(CameraShip, MapRange, mapRange),
ATTRIBUTE_ENTRY(CameraShip, MapLinearPosition, mapLinearPosition),
ATTRIBUTE_ENTRY(CameraShip, MapAngularPosition, mapAngularPosition)
};
CameraShip::AttributeIndexSet
CameraShip::AttributeIndex(
ELEMENTS(CameraShip::AttributePointers),
CameraShip::AttributePointers,
Mover::AttributeIndex
);
//#############################################################################
// Messaging Support
//
const Receiver::HandlerEntry
CameraShip::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(CameraShip, Direction)
};
CameraShip::MessageHandlerSet
CameraShip::MessageHandlers(
ELEMENTS(CameraShip::MessageHandlerEntries),
CameraShip::MessageHandlerEntries,
Entity::MessageHandlers
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::DirectionMessageHandler(DirectionMessage *message)
{
Check(this);
Check(message);
Check(application);
HostManager *host = application->GetHostManager();
Check(host);
SetGoalEntity(host->GetEntityPointer(message->goalEntity));
Check(goalEntity);
mapLinearPosition = &goalEntity->localOrigin.linearPosition;
focusOffset = message->focusOffset;
SetSimulationState(DefaultState);
timeOnCamera = message->timeOnCamera;
lastSwitch = Now();
lastSwitch -= timeOnCamera;
Check_Fpu();
}
//#############################################################################
// ControlsMapper Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::SetMappingSubsystem(CameraControlsMapper *mapper)
{
Check(this);
Check(mapper);
if(subsystemArray[ControlsMapperSubsystem])
{
Unregister_Object(subsystemArray[ControlsMapperSubsystem]);
delete subsystemArray[ControlsMapperSubsystem];
}
subsystemArray[ControlsMapperSubsystem] = mapper;
Check_Fpu();
}
//#############################################################################
// Simulation Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::DriveCamera(Scalar time_slice)
{
Check(this);
CameraControlsMapper* controls =
Cast_Object(
CameraControlsMapper*,
GetSubsystem(CameraShip::ControlsMapperSubsystem)
);
Check(controls);
//
//-----------------------------------------------
// If we are in positioning mode, move the camera
//-----------------------------------------------
//
if (controls->driveCamera > 0)
{
ApplyControlledPanAndTilt(controls, time_slice);
ApplyControlledCameraMotion(controls, time_slice);
ApplyControlledCameraHeight(controls);
currentCamera->SetLocalOrigin(localOrigin);
}
//
//------------------------------------------------------------------------
// Operate in camera mode, obeying the limits of the camera as established
// by the clamps
//------------------------------------------------------------------------
//
else
{
//
//-------------------------
// Stop any existing motion
//-------------------------
//
worldLinearVelocity = Vector3D::Identity;
//
//-----------------------------------------------------------------------
// Read the controls for panning the camera, and if the clamp override is
// on, tell the camera to allow this orientation
//-----------------------------------------------------------------------
//
ApplyControlledPanAndTilt(controls, time_slice);
localToWorld = localOrigin;
//
//---------------------------------------------------------------------
// Establish an aim point along negative Z and figure out where that is
// in world space, then point the camera there. The camera clamps will
// automatically do their thing
//---------------------------------------------------------------------
//
Point3D local_aim(0.0f, 0.0f, -1.0f);
Point3D world_aim;
world_aim.Multiply(local_aim, localToWorld);
if (controls->slideOrClamp > 0)
{
currentCamera->AllowLookingAt(world_aim);
}
AimCameraAtPoint(world_aim);
}
localToWorld = localOrigin;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::ApplyControlledPanAndTilt(
CameraControlsMapper *controls,
Scalar time_slice
)
{
Check(this);
Check(controls);
//
//-----------------------------------------
// Point the Camera in the direction of the
// Joystick Position Calc Pitch and Yaw only
//-----------------------------------------
//
Scalar rotation_amount;
if(controls->stickPosition.x < -0.02f)
{
rotation_amount = controls->stickPosition.x + 0.02f;
rotation_amount *= rotation_amount;
rotation_amount *= -1.0f;
}
else if (controls->stickPosition.x > 0.02f)
{
rotation_amount = controls->stickPosition.x - 0.02f;
rotation_amount *= rotation_amount;
}
else
{
rotation_amount = 0.0f;
}
YawPitchRoll ypr;
ypr = localOrigin.angularPosition;
ypr.yaw += rotation_amount * PI * time_slice;
ypr.pitch += controls->stickPosition.y * PI * 0.2f * time_slice;
localOrigin.angularPosition = ypr;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::ApplyControlledCameraHeight(CameraControlsMapper *controls)
{
Check(this);
Check(controls);
//
//----------------------------------------------------
// Raise and lower the cameraShip according to the pedals
//----------------------------------------------------
//
localOrigin.linearPosition.y += controls->pedalsPosition;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::ApplyControlledCameraMotion(
CameraControlsMapper *controls,
Scalar time_slice
)
{
Check(this);
Check(controls);
localAcceleration.linearMotion.z =
-25.0f * controls->throttlePosition * time_slice;
if (controls->reverseThrust > 0)
{
localAcceleration.linearMotion.z = -localAcceleration.linearMotion.z;
}
//
//~~~~~~~~~~~~~~~~~~~
// Apply Linear Drag
//~~~~~~~~~~~~~~~~~~~
//
Vector3D drag_force;
drag_force.Multiply(
localVelocity.linearMotion,
positiveLinearDragCoefficients
);
Vector3D new_accel;
new_accel.Subtract(
localAcceleration.linearMotion,
drag_force
);
localAcceleration.linearMotion = new_accel;
//
//~~~~~~~~~~~~~~~~~~~~~~~~
// ApplyWorldAccelerations
//~~~~~~~~~~~~~~~~~~~~~~~~
localVelocity.linearMotion += localAcceleration.linearMotion;
worldLinearVelocity.Multiply(
localVelocity.linearMotion,
localToWorld
);
localOrigin.linearPosition += worldLinearVelocity;
Check_Fpu();
}
//#############################################################################
// Follow GoalEntity Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::FollowGoal(Scalar time_slice)
{
Check(this);
//
//-----------------------------------------------
// If no goalEntity assigned ask for one and wait
//-----------------------------------------------
//
if (!goalEntity)
{
return;
}
Check(goalEntity);
Point3D target;
target.Multiply(focusOffset, goalEntity->localToWorld);
//
//------------------------------------------------------------------------
// If time has not yet expired on this camera, keep with it if can see the
// goal entity
//------------------------------------------------------------------------
//
Check(currentCamera);
if (
lastPerformance - lastSwitch > timeOnCamera
|| !currentCamera->CanCameraSee(target)
)
{
CameraInstance *old_camera = currentCamera;
GoToClosestCamera(target);
if (!currentCamera)
{
currentCamera = old_camera;
}
Check(currentCamera);
//
//------------------------------------------------------------------------
// If we need to switch cameras, have the new camera point directly at the
// target
//------------------------------------------------------------------------
//
if (currentCamera != old_camera)
{
AimCameraAtPoint(target);
lastSwitch = lastPerformance;
}
else
{
goto Rotate_Camera;
}
}
//
//---------------------------------------------------
// Otherwise, rotate the camera as needed and allowed
//---------------------------------------------------
//
else
{
Rotate_Camera:
RotateCameraToPoint(time_slice, target);
}
//
//------------------------
// Set the tranform matrix
//------------------------
//
localToWorld = localOrigin;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::GoToClosestCamera(const Point3D &point_3D)
{
Check(this);
currentCamera = cameraManager.FindClosestCamera(point_3D);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::AimCameraAtPoint(const Point3D &point_3D)
{
Check(this);
Check(currentCamera);
currentCamera->LookAt(&localOrigin, point_3D);
localVelocity.angularMotion = Vector3D::Identity;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::RotateCameraToPoint(
Scalar time_slice,
const Point3D &point_3D
)
{
Check(this);
Check(currentCamera);
Check(&point_3D);
//
//---------------------------------------------------------
// Calculate the rotation needed to point to the goalEntity
//---------------------------------------------------------
//
Origin target;
currentCamera->LookAt(&target, point_3D);
YawPitchRoll new_yaw_pitch_roll;
new_yaw_pitch_roll = target.angularPosition;
Vector3D new_pos(new_yaw_pitch_roll.pitch, new_yaw_pitch_roll.yaw, 0.0f);
YawPitchRoll old_pos_euler;
old_pos_euler = localOrigin.angularPosition;
Vector3D old_pos(old_pos_euler.pitch, old_pos_euler.yaw, 0.0f);
old_pos.x = Radian::Normalize(old_pos.x);
old_pos.y = Radian::Normalize(old_pos.y);
//
// new - old position
//
if (new_pos.x-old_pos.x > PI) {
new_pos.x -= TWO_PI;
}
else if (new_pos.x-old_pos.x < -PI) {
new_pos.x += TWO_PI;
}
if (new_pos.y-old_pos.y > PI) {
new_pos.y -= TWO_PI;
}
else if (new_pos.y-old_pos.y < -PI) {
new_pos.y += TWO_PI;
}
Vector3D delta_rot;
delta_rot.Subtract(
new_pos,
old_pos
);
//
//-------------------
// Apply Angular Drag
//-------------------
//
Vector3D
drag;
drag.Multiply(
localVelocity.angularMotion,
angularDragCoefficients
);
//
//~~~~~~~~~~~~~~~~~~~~~
// Apply SpringConstant
//~~~~~~~~~~~~~~~~~~~~~
//
Vector3D
delta_rot_spring;
delta_rot_spring.Multiply(
delta_rot,
elasticityCoefficient
);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Calculate the new angular acceleration
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
localAcceleration.angularMotion.Subtract(
delta_rot_spring,
drag
);
Scalar halft_squared = 0.5 *(time_slice * time_slice);
Vector3D
accel_comp;
accel_comp.Multiply(
localAcceleration.angularMotion,
halft_squared
);
//
// velocity * delta time
//
Vector3D
scaled_velocity;
scaled_velocity.Multiply(
localVelocity.angularMotion,
time_slice
);
Vector3D
tmp_position;
tmp_position.Add(
scaled_velocity,
accel_comp
);
Vector3D
clamped_accel;
clamped_accel.Add(
old_pos,
tmp_position
);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Apply Acceleration to angular Position
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
YawPitchRoll
new_yawpitchroll(clamped_accel.y, clamped_accel.x, clamped_accel.z);
LinearMatrix
rot_matrix(LinearMatrix::Identity);
rot_matrix = new_yawpitchroll;
localOrigin.angularPosition = rot_matrix;
//
// Calc new Velocity
//
Vector3D
scaled_accel;
scaled_accel.Multiply(
localAcceleration.angularMotion,
time_slice
);
Vector3D
ang_vel;
ang_vel.Add(
localVelocity.angularMotion,
scaled_accel
);
localVelocity.angularMotion = ang_vel;
Check_Fpu();
}
//#############################################################################
// CameraInstanceManager Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::CreateCameraInstance()
{
Check(this);
Check(&cameraManager);
currentCamera = cameraManager.CreateCameraInstance(localOrigin);
DEBUG_STREAM << currentCamera->GetCameraName() << endl;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::DeleteCameraInstance()
{
Check(this);
//
//---------------------------------------------
// If this is the last camera, don't delete it!
//---------------------------------------------
//
Check(&cameraManager);
CameraInstance *next_camera = cameraManager.IncrementIterator();
if (next_camera == currentCamera)
{
return;
}
currentCamera = cameraManager.DeleteCameraInstance();
Check(currentCamera);
DEBUG_STREAM << currentCamera->GetCameraName() << endl;
localOrigin = currentCamera->GetLocalOrigin();
localToWorld = localOrigin;
Point3D local_aim(0.0f, 0.0f, -1.0f);
Point3D world_aim;
world_aim.Multiply(local_aim, localToWorld);
AimCameraAtPoint(world_aim);
localToWorld = localOrigin;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::IncrementCameraInstance()
{
Check(this);
Check(&cameraManager);
currentCamera = cameraManager.IncrementIterator();
Check(currentCamera);
DEBUG_STREAM << currentCamera->GetCameraName() << endl;
localOrigin = currentCamera->GetLocalOrigin();
localToWorld = localOrigin;
Point3D local_aim(0.0f, 0.0f, -1.0f);
Point3D world_aim;
world_aim.Multiply(local_aim, localToWorld);
AimCameraAtPoint(world_aim);
localToWorld = localOrigin;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::DecrementCameraInstance()
{
Check(this);
Check(&cameraManager);
currentCamera = cameraManager.DecrementIterator();
Check(currentCamera);
DEBUG_STREAM << currentCamera->GetCameraName() << endl;
localOrigin = currentCamera->GetLocalOrigin();
localToWorld = localOrigin;
Point3D local_aim(0.0f, 0.0f, -1.0f);
Point3D world_aim;
world_aim.Multiply(local_aim, localToWorld);
AimCameraAtPoint(world_aim);
localToWorld = localOrigin;
Check_Fpu();
}
//#############################################################################
// Motion Support Functions
//
//#############################################################################
// Construction and Destruction Support
//
CameraShip::CameraShip(
CameraShip::MakeMessage *creation_message,
CameraShip::SharedData &virtual_data
):
Mover(creation_message, virtual_data)
{
SetValidFlag();
if (GetInstance() == ReplicantInstance)
{
return;
}
//
//----------------------------
// Initialize local variables
//----------------------------
//
goalEntity = NULL;
localOrigin = Origin::Identity;
focusOffset = Vector3D::Identity;
//
//------------------------------
// Initialize attributes
//------------------------------
//
mapRange = 1000.0; // number of meters across display
mapLinearPosition = NULL; // force nav display to use object's lin. pos
mapAngularPosition = NULL; // force nav display to not turn or tilt
//
//------------------------------
// Initialize the subsystemArray
//------------------------------
//
subsystemCount = BasicSubsystemCount;
Verify(!subsystemArray);
subsystemArray = new (Subsystem (*[subsystemCount]));
Register_Pointer(subsystemArray);
subsystemArray[ControlsMapperSubsystem] = NULL;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Initialize the camera's viewpoint to the first camera
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
currentCamera = cameraManager.GetCurrent();
if (!currentCamera)
{
CreateCameraInstance();
}
Check(currentCamera);
localOrigin = currentCamera->GetLocalOrigin();
localToWorld = localOrigin;
Point3D local_aim(0.0f, 0.0f, -1.0f);
Point3D world_aim;
world_aim.Multiply(local_aim, localToWorld);
AimCameraAtPoint(world_aim);
localToWorld = localOrigin;
lastSwitch = Now();
timeOnCamera = 0.0f;
SetPerformance(&CameraShip::FollowGoal);
SetSimulationState(DefaultState);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraShip*
CameraShip::Make(MakeMessage *creation_message)
{
return new CameraShip(creation_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraShip::~CameraShip()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
CameraShip::TestInstance() const
{
return IsDerivedFrom(ClassDerivations);
}