Janky tracking on a Live Cam, and the rotation is a spring-damper on the
fixed simulation step, so it should glide. Which leaves the input rather
than the smoothing: the camera follows a REMOTE pod, whose position only
changes on this host when an update lands. If the watched point sits still
for most steps and then leaps, the camera is tracking a staircase
faithfully and nothing in the rotation can hide it.
So FollowGoal now reports, every five seconds: how many simulation steps
it ran, how many of those saw the target move at all, the largest single
jump in metres, and how many times the trackside camera was cut to a
different one. At 50 Hz that is about 250 steps per report, so:
moved near 250 the target moves every step - look elsewhere for
the jank, most likely frame pacing
moved near 50 the target changes about ten times a second and the
camera is stepping between arrivals
biggest jump large confirms leaps rather than drift
several cuts the trackside camera is flip-flopping, which snaps
rather than glides and is its own kind of jank
The cut count is worth having because timeOnCamera is 0 for a race - the
director sets it to 0 outside football - so the closest-camera choice is
re-evaluated every step and only hysteresis stops it oscillating.
Not baselined locally: FollowGoal only runs on a camera station with a
peer, so unlike the nav and copy traces this one goes out unverified
against real numbers. The counters are simple enough to trust; the
interpretation above is what to hold it to.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
797 lines
19 KiB
C++
797 lines
19 KiB
C++
#include "munga.h"
|
|
#pragma hdrstop
|
|
|
|
#include "camship.h"
|
|
#include "player.h"
|
|
#include "mission.h"
|
|
#include "cammppr.h"
|
|
#include "app.h"
|
|
#include "hostmgr.h"
|
|
|
|
//##########################################################################
|
|
//############################# CameraShip ################################
|
|
//##########################################################################
|
|
|
|
//
|
|
// Trackside camera cuts since the last RP412CAMLOG report - counted where
|
|
// the cut happens and drained where it is reported, both in FollowGoal.
|
|
//
|
|
static int gCameraCuts = 0;
|
|
|
|
//#############################################################################
|
|
// Shared Data Support
|
|
//
|
|
Derivation* CameraShip::GetClassDerivations()
|
|
{ static Derivation classDerivations(Mover::GetClassDerivations(), "CameraShip");
|
|
return &classDerivations;
|
|
}
|
|
|
|
|
|
CameraShip::SharedData
|
|
CameraShip::DefaultData(
|
|
CameraShip::GetClassDerivations(),
|
|
CameraShip::MessageHandlers,
|
|
CameraShip::GetAttributeIndex(),
|
|
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::GetAttributeIndex()
|
|
{
|
|
static CameraShip::AttributeIndexSet attributeIndex(ELEMENTS(CameraShip::AttributePointers),
|
|
CameraShip::AttributePointers,
|
|
Mover::GetAttributeIndex()
|
|
);
|
|
return attributeIndex;
|
|
}
|
|
|
|
//#############################################################################
|
|
// Messaging Support
|
|
//
|
|
const Receiver::HandlerEntry
|
|
CameraShip::MessageHandlerEntries[]=
|
|
{
|
|
MESSAGE_ENTRY(CameraShip, Direction)
|
|
};
|
|
|
|
CameraShip::MessageHandlerSet
|
|
CameraShip::MessageHandlers(
|
|
ELEMENTS(CameraShip::MessageHandlerEntries),
|
|
CameraShip::MessageHandlerEntries,
|
|
Entity::GetMessageHandlers()
|
|
);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
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);
|
|
|
|
//
|
|
// RP412CAMLOG: is the thing we are following actually MOVING every
|
|
// step, or arriving in jumps?
|
|
//
|
|
// This runs on the fixed simulation step, so it is called at a steady
|
|
// rate whatever the frame rate. The entity it follows is a REMOTE pod,
|
|
// whose position only changes when an update lands - so if the watched
|
|
// point is identical on most steps and then leaps, the camera is
|
|
// tracking a staircase and no amount of smoothing here will hide it.
|
|
// Reported as: steps counted, how many of them saw any movement at
|
|
// all, the largest single jump, and how often the trackside camera was
|
|
// cut to a different one (a cut is a snap, not a glide, and would look
|
|
// like jank of a different kind).
|
|
//
|
|
if (RPCameraLog())
|
|
{
|
|
static Scalar next_say = 0.0f;
|
|
static Point3D last_target(0.0f, 0.0f, 0.0f);
|
|
static Logical have_last = False;
|
|
static int steps = 0;
|
|
static int moved = 0;
|
|
static Scalar biggest = 0.0f;
|
|
|
|
++steps;
|
|
if (have_last)
|
|
{
|
|
Vector3D step_delta;
|
|
step_delta.Subtract(target, last_target);
|
|
Scalar distance = step_delta.Length();
|
|
if (distance > 0.0f)
|
|
{
|
|
++moved;
|
|
}
|
|
if (distance > biggest)
|
|
{
|
|
biggest = distance;
|
|
}
|
|
}
|
|
last_target = target;
|
|
have_last = True;
|
|
|
|
if ((Scalar) Now() >= next_say)
|
|
{
|
|
if (next_say > 0.0f)
|
|
{
|
|
DEBUG_STREAM << "CamLog: follow - " << steps << " steps, "
|
|
<< moved << " moved, biggest jump " << biggest
|
|
<< "m, " << gCameraCuts << " cut(s)\n" << std::flush;
|
|
}
|
|
next_say = ((Scalar) Now()) + 5.0f;
|
|
steps = 0;
|
|
moved = 0;
|
|
biggest = 0.0f;
|
|
gCameraCuts = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// 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)
|
|
{
|
|
++gCameraCuts;
|
|
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() << std::endl << std::flush;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
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() << std::endl << std::flush;
|
|
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() << std::endl << std::flush;
|
|
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() << std::endl << std::flush;
|
|
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(*GetClassDerivations());
|
|
}
|