Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

1270 lines
36 KiB
C++

//===========================================================================//
// File: mover.cc //
// Project: MUNGA Brick: Model Manager //
// Contents: Implementation details of moving entity class //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 01/21/95 JMA Initial coding. //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include "AdeptHeaders.hpp"
#include "Mover.hpp"
#include "EntityManager.hpp"
//#############################################################################
//################## Mover::ExecutionStateEngine #####################
//#############################################################################
const StateEngine::StateEntry
Mover::ExecutionStateEngine::StateEntries[]=
{
STATE_ENTRY(Mover__ExecutionStateEngine, StraightLineMotion),
STATE_ENTRY(Mover__ExecutionStateEngine, LinearDragMotion)
};
Mover::ExecutionStateEngine::ClassData*
Mover::ExecutionStateEngine::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::ExecutionStateEngine::InitializeClass()
{
Check_Object(StateEngine::DefaultData);
Verify(!DefaultData);
DefaultData =
new ClassData(
Mover__ExecutionStateEngineClassID,
"Adept::Mover::ExecutionStateEngine",
BaseClass::DefaultData,
ELEMENTS(StateEntries), StateEntries,
(Entity::ExecutionStateEngine::Factory)Make,
(Entity::ExecutionStateEngine::FactoryRequest::Factory)
&FactoryRequest::ConstructFactoryRequest
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::ExecutionStateEngine::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Mover::ExecutionStateEngine*
Mover::ExecutionStateEngine::Make(
Mover *mover,
FactoryRequest *request
)
{
Check_Object(mover);
Check_Object(request);
Mover::ExecutionStateEngine *engine =
new Mover::ExecutionStateEngine(DefaultData, mover, request);
return engine;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::ExecutionStateEngine::TestInstance()
{
Verify(IsDerivedFrom(DefaultData));
}
//#############################################################################
//############################### Mover #################################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Mover::ClassData*
Mover::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::InitializeClass()
{
Check_Object(ExecutionStateEngine::DefaultData);
Verify(!DefaultData);
DefaultData =
new ClassData(
MoverClassID,
"Adept::Mover",
BaseClass::DefaultData,
0, NULL,
(Entity::Factory)Make,
(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
ExecutionStateEngine::DefaultData,
(Entity::GameModel::Factory)GameModel::ConstructGameModel,
NULL,
(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
(Entity::GameModel::ModelWrite)GameModel::WriteToText,
(Entity::GameModel::ModelSave)GameModel::SaveGameModel
);
Register_Object(DefaultData);
DIRECT_ATTRIBUTE(
Mover,
LocalSpaceVelocity,
localSpaceVelocity,
Motion3D
);
DIRECT_ATTRIBUTE(
Mover,
LocalSpaceAcceleration,
localSpaceAcceleration,
Motion3D
);
DIRECT_ATTRIBUTE(
Mover,
WorldSpaceVelocity,
worldSpaceVelocity,
Motion3D
);
DIRECT_ATTRIBUTE(
Mover,
WorldSpaceAcceleration,
worldSpaceAcceleration,
Motion3D
);
INDIRECT_STATE_ATTRIBUTE(
Mover,
ExecutionState,
executionState,
Mover__ExecutionStateEngine
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Mover__GameModel,
MoverMass,
moverMass,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Mover__GameModel,
MomentOfInertia,
momentOfInertia,
Vector3D
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Mover__GameModel,
LinearDragCoefficients,
linearDragCoefficients,
Vector3D
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Mover__GameModel,
AngularDragCoefficients,
angularDragCoefficients,
Vector3D
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Mover__GameModel,
FrictionCoefficient,
frictionCoefficient,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Mover__GameModel,
ElasticityCoefficient,
elasticityCoefficient,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Mover__GameModel,
MinimumBounceSpeed,
minimumBounceSpeed,
Scalar
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Mover*
Mover::Make(
const CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(message);
gos_PushCurrentHeap(g_LibraryHeap);
Mover *new_entity = new Mover(DefaultData, message, base_id, NULL);
Check_Object(new_entity);
gos_PopCurrentHeap();
return new_entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Mover::Mover(
ClassData *class_data,
const CreateMessage *message,
ReplicatorID *base_id,
ElementRenderer::Element *element
):
Entity(class_data, message, base_id, element)
{
Check_Pointer(this);
Check_Object(message);
//
//------------------------------------------------------------------------
// Initialize the motion vectors. Note that this assignment only works
// because at the time of construction, there is no parent so parent space
// is equivalant to world space
//------------------------------------------------------------------------
//
initialWorldSpaceVelocity = message->worldSpaceVelocity;
initialWorldSpaceAcceleration = message->worldSpaceAcceleration;
//
//----------------------------------------------------------------------
// Look at our initial state and see how to compute the current position
//----------------------------------------------------------------------
//
if (message->initialAge > 0.0f)
{
Check_Object(executionState);
int execution_state = executionState->GetState();
switch (execution_state)
{
case ExecutionStateEngine::StraightLineMotionState:
StraightLineMotionSimulation(gos_GetElapsedTime());
break;
case ExecutionStateEngine::LinearDragMotionState:
{
//
//--------------------------------------------
// figure out the drag numbers in parent space
//--------------------------------------------
//
const GameModel *model = GetGameModel();
Check_Object(model);
localSpaceDrag.linearMotion = model->linearDragCoefficients;
localSpaceDrag.angularMotion = model->angularDragCoefficients;
LinearMatrix4D world_to_local;
world_to_local.Invert(GetLocalToWorld());
localSpaceAcceleration.linearMotion.Multiply(
worldSpaceAcceleration.linearMotion,
world_to_local
);
localSpaceAcceleration.angularMotion.Multiply(
worldSpaceAcceleration.angularMotion,
world_to_local
);
LinearDragMotionSimulation(gos_GetElapsedTime());
}
break;
default:
goto T_is_T0;
}
}
//
//----------------------------------------------------------------
// If we are at the beginning of the time, just copy the variables
//----------------------------------------------------------------
//
else
{
T_is_T0:
worldSpaceVelocity = message->worldSpaceVelocity;
worldSpaceAcceleration = message->worldSpaceAcceleration;
}
//
//-------------------------------------
// Initialize the local velocity vector
//-------------------------------------
//
LinearMatrix4D world_to_local;
world_to_local.Invert(initialLocalToParent);
localSpaceVelocity.linearMotion.Multiply(
worldSpaceVelocity.linearMotion,
world_to_local
);
localSpaceVelocity.angularMotion.Multiply(
worldSpaceVelocity.angularMotion,
world_to_local
);
localSpaceAcceleration.linearMotion.Multiply(
worldSpaceAcceleration.linearMotion,
world_to_local
);
localSpaceAcceleration.angularMotion.Multiply(
worldSpaceAcceleration.angularMotion,
world_to_local
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Mover::Respawn(Entity::CreateMessage *message)
{
Check_Object(this);
Check_Object(message);
BaseClass::Respawn(message);
CreateMessage *mover_message = Cast_Pointer(CreateMessage *, message);
//
//------------------------------------------------------------------------
// Initialize the motion vectors. Note that this assignment only works
// because at the time of construction, there is no parent so parent space
// is equivalant to world space
//------------------------------------------------------------------------
//
initialWorldSpaceVelocity = mover_message->worldSpaceVelocity;
initialWorldSpaceAcceleration = mover_message->worldSpaceAcceleration;
//
//----------------------------------------------------------------------
// Look at our initial state and see how to compute the current position
//----------------------------------------------------------------------
//
if (mover_message->initialAge > 0.0f)
{
Check_Object(executionState);
int execution_state = executionState->GetState();
switch (execution_state)
{
case ExecutionStateEngine::StraightLineMotionState:
StraightLineMotionSimulation(gos_GetElapsedTime());
break;
case ExecutionStateEngine::LinearDragMotionState:
{
//
//--------------------------------------------
// figure out the drag numbers in parent space
//--------------------------------------------
//
const GameModel *model = GetGameModel();
Check_Object(model);
localSpaceDrag.linearMotion = model->linearDragCoefficients;
localSpaceDrag.angularMotion = model->angularDragCoefficients;
LinearMatrix4D world_to_local;
world_to_local.Invert(GetLocalToWorld());
localSpaceAcceleration.linearMotion.Multiply(
worldSpaceAcceleration.linearMotion,
world_to_local
);
localSpaceAcceleration.angularMotion.Multiply(
worldSpaceAcceleration.angularMotion,
world_to_local
);
LinearDragMotionSimulation(gos_GetElapsedTime());
}
break;
default:
goto T_is_T0;
}
}
//
//----------------------------------------------------------------
// If we are at the beginning of the time, just copy the variables
//----------------------------------------------------------------
//
else
{
T_is_T0:
worldSpaceVelocity = mover_message->worldSpaceVelocity;
worldSpaceAcceleration = mover_message->worldSpaceAcceleration;
}
//
//-------------------------------------
// Initialize the local velocity vector
//-------------------------------------
//
LinearMatrix4D world_to_local;
world_to_local.Invert(initialLocalToParent);
localSpaceVelocity.linearMotion.Multiply(
worldSpaceVelocity.linearMotion,
world_to_local
);
localSpaceVelocity.angularMotion.Multiply(
worldSpaceVelocity.angularMotion,
world_to_local
);
localSpaceAcceleration.linearMotion.Multiply(
worldSpaceAcceleration.linearMotion,
world_to_local
);
localSpaceAcceleration.angularMotion.Multiply(
worldSpaceAcceleration.angularMotion,
world_to_local
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::Reuse(
const CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Pointer(this);
Check_Object(message);
BaseClass::Reuse(message, base_id);
//
//------------------------------------------------------------------------
// Initialize the motion vectors. Note that this assignment only works
// because at the time of construction, there is no parent so parent space
// is equivalant to world space
//------------------------------------------------------------------------
//
initialWorldSpaceVelocity = message->worldSpaceVelocity;
initialWorldSpaceAcceleration = message->worldSpaceAcceleration;
//
//----------------------------------------------------------------------
// Look at our initial state and see how to compute the current position
//----------------------------------------------------------------------
//
if (message->initialAge > 0.0f)
{
Check_Object(executionState);
int execution_state = executionState->GetState();
switch (execution_state)
{
case ExecutionStateEngine::StraightLineMotionState:
StraightLineMotionSimulation(gos_GetElapsedTime());
break;
case ExecutionStateEngine::LinearDragMotionState:
{
//
//--------------------------------------------
// figure out the drag numbers in parent space
//--------------------------------------------
//
const GameModel *model = GetGameModel();
Check_Object(model);
localSpaceDrag.linearMotion = model->linearDragCoefficients;
localSpaceDrag.angularMotion = model->angularDragCoefficients;
LinearMatrix4D world_to_local;
world_to_local.Invert(GetLocalToWorld());
localSpaceAcceleration.linearMotion.Multiply(
worldSpaceAcceleration.linearMotion,
world_to_local
);
localSpaceAcceleration.angularMotion.Multiply(
worldSpaceAcceleration.angularMotion,
world_to_local
);
LinearDragMotionSimulation(gos_GetElapsedTime());
}
break;
default:
goto T_is_T0;
}
}
//
//----------------------------------------------------------------
// If we are at the beginning of the time, just copy the variables
//----------------------------------------------------------------
//
else
{
T_is_T0:
worldSpaceVelocity = message->worldSpaceVelocity;
worldSpaceAcceleration = message->worldSpaceAcceleration;
}
//
//-------------------------------------
// Initialize the local velocity vector
//-------------------------------------
//
LinearMatrix4D world_to_local;
world_to_local.Invert(initialLocalToParent);
localSpaceVelocity.linearMotion.Multiply(
worldSpaceVelocity.linearMotion,
world_to_local
);
localSpaceVelocity.angularMotion.Multiply(
worldSpaceVelocity.angularMotion,
world_to_local
);
localSpaceAcceleration.linearMotion.Multiply(
worldSpaceAcceleration.linearMotion,
world_to_local
);
localSpaceAcceleration.angularMotion.Multiply(
worldSpaceAcceleration.angularMotion,
world_to_local
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Replicator::CreateMessage*
Mover::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
{
Check_Object(this);
Check_Object(stream);
//
//---------------------------------------------------------------------
// Make sure there is enough room for the factory request on the stream
//---------------------------------------------------------------------
//
stream->AllocateBytes(sizeof(CreateMessage));
BaseClass::SaveMakeMessage(stream, res_file);
CreateMessage *message =
Cast_Pointer(CreateMessage*, stream->GetPointer());
message->messageLength = sizeof(*message);
//
//-------------------------------------------------------------------------
// Set up the motion. This will absolutely not work if the age is anything
// other than zero
//-------------------------------------------------------------------------
//
if(parentEntity)
{
Check_Object(parentEntity);
LinearMatrix4D parent_to_world = parentEntity->GetLocalToWorld();
message->worldSpaceVelocity.linearMotion.Multiply(
initialWorldSpaceVelocity.linearMotion,
parent_to_world
);
message->worldSpaceVelocity.angularMotion.Multiply(
initialWorldSpaceVelocity.angularMotion,
parent_to_world
);
message->worldSpaceAcceleration.linearMotion.Multiply(
initialWorldSpaceAcceleration.linearMotion,
parent_to_world
);
message->worldSpaceAcceleration.angularMotion.Multiply(
initialWorldSpaceAcceleration.angularMotion,
parent_to_world
);
}
else
{
message->worldSpaceVelocity = Motion3D::Identity;
message->worldSpaceAcceleration = Motion3D::Identity;
}
return message;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::PreCollisionExecute(Time till)
{
Check_Object(this);
PRECOLLISION_LOGIC("Mover");
//
//---------------------------------
// If we aren't executing, stop now
//---------------------------------
//
Check_Object(executionState);
int execution_state = executionState->GetState();
Verify(execution_state != ExecutionStateEngine::NeverExecuteState);
//
//---------------------------------------------
// Make sure that the local velocity is current
//---------------------------------------------
//
#if defined(_ARMOR)
{
const LinearMatrix4D &local_to_world = GetLocalToWorld();
Check_Object(&local_to_world);
LinearMatrix4D world_to_local;
world_to_local.Invert(local_to_world);
Vector3D velocity;
velocity.Multiply(worldSpaceVelocity.linearMotion, world_to_local);
Verify(velocity == localSpaceVelocity.linearMotion);
velocity.Multiply(worldSpaceVelocity.angularMotion, world_to_local);
Verify(velocity == localSpaceVelocity.angularMotion);
}
#endif
//
//---------------------------
// Set up the mover variables
//---------------------------
//
Verify(Close_Enough(GetLocalToParent(), GetLocalToWorld()));
Verify(IsUsingPostCollision());
const GameModel *model = GetGameModel();
Check_Object(model);
//
//--------------------------
// Now do something for real
//--------------------------
//
switch (execution_state)
{
case ExecutionStateEngine::StraightLineMotionState:
StraightLineMotionSimulation(till);
break;
//
//------------------------------------------------------------------------
// Linear drag model requires us to rotate the initial world accelerations
// into local space each frame
//------------------------------------------------------------------------
//
case ExecutionStateEngine::LinearDragMotionState:
{
localSpaceDrag.linearMotion = model->linearDragCoefficients;
localSpaceDrag.angularMotion = model->angularDragCoefficients;
LinearMatrix4D world_to_local;
world_to_local.Invert(GetLocalToWorld());
localSpaceAcceleration.linearMotion.Multiply(
worldSpaceAcceleration.linearMotion,
world_to_local
);
localSpaceAcceleration.angularMotion.Multiply(
worldSpaceAcceleration.angularMotion,
world_to_local
);
LinearDragMotionSimulation(till);
}
break;
default:
localSpaceAcceleration = Motion3D::Identity;
localSpaceDrag.linearMotion = model->linearDragCoefficients;
localSpaceDrag.angularMotion = model->angularDragCoefficients;
break;
}
//
//--------------------------------------------------
// For pre-collision execution, call our parent last
//--------------------------------------------------
//
BaseClass::PreCollisionExecute(till);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::PostCollisionExecute(Time till)
{
Check_Object(this);
Verify(Close_Enough(GetLocalToParent(), GetLocalToWorld()));
POSTCOLLISION_LOGIC("Mover");
//
//----------------------------
// Update the local velocities
//----------------------------
//
LinearMatrix4D world_to_local;
world_to_local.Invert(GetLocalToWorld());
localSpaceVelocity.linearMotion.Multiply(
worldSpaceVelocity.linearMotion,
world_to_local
);
localSpaceVelocity.angularMotion.Multiply(
worldSpaceVelocity.angularMotion,
world_to_local
);
//
//--------------------------------------------------
// Reparameterize if we are in the linear drag state
//--------------------------------------------------
//
Check_Object(executionState);
int execution_state = executionState->GetState();
//this is an invalid check...
// it is possible that we were just set to this and are post executing...
// Verify(execution_state != ExecutionStateEngine::NeverExecuteState);
if (execution_state == ExecutionStateEngine::LinearDragMotionState)
{
lastParameterization = till;
initialLocalToParent = GetLocalToParent();
initialWorldSpaceVelocity = worldSpaceVelocity,
initialWorldSpaceAcceleration = worldSpaceAcceleration;
}
BaseClass::PostCollisionExecute(till);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::StraightLineMotionSimulation(Time till)
{
Check_Object(this);
Verify(Close_Enough(GetLocalToParent(), GetLocalToWorld()));
//
//-------------------------
// See how long to move for
//-------------------------
//
Scalar t = GetTimeParameter(till);
//
//----------------------------------------------------
// Add the world linear velocity to the world position
//----------------------------------------------------
//
Point3D old_translation(initialLocalToParent);
Point3D new_translation;
new_translation.AddScaled(
old_translation,
worldSpaceVelocity.linearMotion,
t
);
//
//---------------------------------------------------
// Make a matrix representing the rotation this frame
//---------------------------------------------------
//
Vector3D spin_axis;
spin_axis.Multiply(worldSpaceVelocity.angularMotion, t);
UnitQuaternion spin;
spin = spin_axis;
//
//-------------------------------------------------------------------------
// Convert the EulerAngles into a matrix and create the new rotation matrix
// through concatenation
//-------------------------------------------------------------------------
//
UnitQuaternion rotation;
rotation = initialLocalToParent;
UnitQuaternion desire;
desire.Multiply(rotation, spin);
LinearMatrix4D new_position;
new_position.BuildTranslation(new_translation);
new_position.BuildRotation(desire);
SetNewLocalToParent(new_position);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::LinearDragMotionSimulation(Time till)
{
Check_Object(this);
Verify(Close_Enough(GetLocalToParent(), GetLocalToWorld()));
Verify(IsUsingPostCollision());
//
//-------------------------
// See how long to move for
//-------------------------
//
Scalar t = GetTimeParameter(till);
//
//---------------------------------
// Call the linear drag computation
//---------------------------------
//
LinearMatrix4D origin_to_local;
Motion3D new_v;
CalculateMotionWithLinearDrag(
t,
&origin_to_local,
&new_v,
LinearMatrix4D::Identity,
localSpaceVelocity,
localSpaceAcceleration,
localSpaceDrag
);
//
//--------------------------------------------------
// Now rotate the motions and delta into world space
//--------------------------------------------------
//
const LinearMatrix4D &local_to_world = GetLocalToWorld();
worldSpaceVelocity.linearMotion.Multiply(new_v.linearMotion, local_to_world);
worldSpaceVelocity.angularMotion.Multiply(new_v.angularMotion, local_to_world);
LinearMatrix4D new_local_to_parent;
new_local_to_parent.Multiply(origin_to_local, local_to_world);
new_local_to_parent.Normalize();
//
//--------------------------------
// Set the position of the locator
//--------------------------------
//
SetNewLocalToParent(new_local_to_parent);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::PlaceOnEntity(
LinearMatrix4D *position,
Motion3D *velocity,
const LinearMatrix4D& initial_offset,
const Motion3D& initial_velocity
)
{
Check_Object(this);
Check_Object(position);
Check_Object(velocity);
BaseClass::PlaceOnEntity(
position,
velocity,
initial_offset,
initial_velocity
);
STOP(("Not implemented"));
velocity->linearMotion += worldSpaceVelocity.linearMotion;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::CalculateMotionWithLinearDrag(
Scalar time_slice,
LinearMatrix4D *new_local_to_parent,
Motion3D *new_velocity,
const LinearMatrix4D &old_local_to_parent,
const Motion3D &old_velocity,
const Motion3D &acceleration,
const Motion3D &drag
)
{
Check_Pointer(new_local_to_parent);
Check_Pointer(new_velocity);
Check_Object(&old_local_to_parent);
Check_Object(&old_velocity);
Check_Object(&acceleration);
Check_Object(&drag);
Verify(&old_local_to_parent != new_local_to_parent);
//
//-------------------------
// Extract the translations
//-------------------------
//
Point3D old_translation;
old_translation = old_local_to_parent;
Point3D new_translation;
//
//-----------------------------------------------------
// Spin through each axis and compute the linear motion
//-----------------------------------------------------
//
for (int axis=X_Axis; axis <= Z_Axis; ++axis)
{
//
//-----------------------------------------------------------------
// If there is no drag, use the x += v*t + 0.5*a*t*t, v += a*t form
//-----------------------------------------------------------------
//
Scalar c = drag.linearMotion[axis];
if (Small_Enough(c))
{
Scalar delta_v = acceleration.linearMotion[axis]*time_slice;
new_translation[axis] =
old_translation[axis]
+ old_velocity.linearMotion[axis]*time_slice
+ 0.5f*delta_v*time_slice;
new_velocity->linearMotion[axis] =
old_velocity.linearMotion[axis] + delta_v;
}
//
//-----------------------------------
// Otherwise, use the continuous form
//-----------------------------------
//
else
{
Verify(c > 0.0f);
Scalar terminal_v = acceleration.linearMotion[axis] / c;
Scalar v_range = old_velocity.linearMotion[axis] - terminal_v;
Scalar delta_v = v_range * Exp(-time_slice*c);
new_velocity->linearMotion[axis] = terminal_v + delta_v;
new_translation[axis] =
old_translation[axis]
+ terminal_v*time_slice
+ (v_range - delta_v) / c;
}
}
//
//------------------------------------------------------
// Spin through each axis and compute the angular motion
//------------------------------------------------------
//
Verify(time_slice > 0.0f);
Vector3D delta_q;
for (axis=X_Axis; axis <= Z_Axis; ++axis)
{
//
//-----------------------------------------------------------------
// If there is no drag, use the x += v*t + 0.5*a*t*t, v += a*t form
//-----------------------------------------------------------------
//
Scalar c = drag.angularMotion[axis];
if (Small_Enough(c))
{
Scalar delta_v = acceleration.angularMotion[axis]*time_slice;
delta_q[axis] =
old_velocity.angularMotion[axis]*time_slice
+ 0.5f*delta_v*time_slice;
new_velocity->angularMotion[axis] =
old_velocity.angularMotion[axis] + delta_v;
}
//
//-----------------------------------
// Otherwise, use the continuous form
//-----------------------------------
//
else
{
Verify(c > 0.0f);
Scalar terminal_v = acceleration.angularMotion[axis] / c;
Scalar v_range = old_velocity.angularMotion[axis] - terminal_v;
Scalar delta_v = v_range * Exp(-time_slice*c);
new_velocity->angularMotion[axis] = terminal_v + delta_v;
delta_q[axis] = terminal_v*time_slice + (v_range - delta_v) / c;
}
}
//
//------------------------------------------------------------------------
// Now add this motion to the origin. For the angular motion, convert the
// delta into a quaternion first
//------------------------------------------------------------------------
//
LinearMatrix4D d;
d.BuildRotation(delta_q);
d.BuildTranslation(Point3D::Identity);
new_local_to_parent->Multiply(old_local_to_parent, d);
new_local_to_parent->BuildTranslation(new_translation);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::ApplyLocalAccelerationToTorque(
const Vector3D &acceleration,
const Vector3D &moment
)
{
Check_Object(this);
Check_Object(&acceleration);
Check_Object(&moment);
Vector3D torque;
torque.Cross(moment, acceleration);
const GameModel *model = GetGameModel();
Check_Pointer(model);
torque *= model->momentOfInertia;
localSpaceAcceleration.angularMotion += torque;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::ApplyLocalForceToTorque(
const Vector3D &force,
const Vector3D &moment
)
{
Check_Object(this);
Check_Object(&force);
Check_Object(&moment);
const GameModel *model = GetGameModel();
Check_Pointer(model);
Verify(!Small_Enough(model->moverMass));
Vector3D acceleration;
acceleration.Divide(force, model->moverMass);
ApplyLocalAccelerationToTorque(acceleration, moment);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::ApplyLocalAcceleration(
const Vector3D &acceleration,
const Vector3D &moment
)
{
Check_Object(this);
Check_Object(&acceleration);
Check_Object(&moment);
localSpaceAcceleration.linearMotion += acceleration;
ApplyLocalAccelerationToTorque(acceleration, moment);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::ApplyLocalForce(
const Vector3D &force,
const Vector3D &moment
)
{
Check_Object(this);
Check_Object(&force);
Check_Object(&moment);
const GameModel *model = GetGameModel();
Check_Pointer(model);
Verify(!Small_Enough(model->moverMass));
Vector3D acceleration;
acceleration.Divide(force, model->moverMass);
ApplyLocalAcceleration(acceleration, moment);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
Mover::StaticBounce(
const Point3D &, //old_position,
Scalar delta_t,
Scalar penetration,
const Normal3D &normal,
Scalar *elasticity,
Scalar bounce_min,
Scalar *friction
)
{
Check_Object(this);
Check_Object(&normal);
Check_Pointer(elasticity);
Check_Pointer(friction);
Verify(penetration >= 0.0f && penetration <= 1.0f);
Verify(*elasticity >= 0.0f && *elasticity <= 1.0f);
Verify(*friction >= 0.0f);
Verify(delta_t > SMALL);
// penetration = 1.0f; // HACK - should keep stuff from going through the floor
//
//-----------------------------------------------------------------------
// Calculate the impact speed and vectors. If we didn't hit fast enough,
// don't do any bounce
//-----------------------------------------------------------------------
//
Scalar impact = worldSpaceVelocity.linearMotion * normal;
Vector3D vn,vp;
vn.Multiply(normal, impact);
vp.Subtract(worldSpaceVelocity.linearMotion, vn);
if (impact > 0.0f)
{
return 0.0f;
}
if (-impact <= bounce_min * delta_t)
{
*elasticity = 0.0f;
}
//
//--------------------------------------
// Calculate the energy lost to friction
//--------------------------------------
//
Scalar resistance = vp.GetLength();
if (Small_Enough(resistance))
{
*friction = resistance = 0.0f;
}
else
{
resistance =
1.0f + *friction * (1.0f + *elasticity) * impact / resistance;
if (resistance < 0.0f)
{
*friction = resistance = 0.0f;
}
}
//
//----------------------------------------------------
// Compute the velocity delta created by the collision
//----------------------------------------------------
//
Scalar temp = resistance - 1.0f;
Vector3D delta_v;
delta_v.Multiply(worldSpaceVelocity.linearMotion, temp);
temp = resistance + *elasticity;
delta_v.AddScaled(delta_v, vn, -temp);
//
//------------------------------------
// Figure out the kinetic energy stuff
//------------------------------------
//
temp = -1.0f - *elasticity;
vn *= temp;
vp.AddScaled(vn, worldSpaceVelocity.linearMotion, 2.0f);
//
// Reflect the velocity vector
//
worldSpaceVelocity.linearMotion += delta_v;
temp = penetration * delta_t;
delta_v *= temp;
STOP(("Not implemented"));
// localOrigin.linearPosition += delta_v;
//
// Compute the kinetic energy loss
//
const GameModel *model = GetGameModel();
Check_Pointer(model);
return -0.0005f * (vn * vp) * model->moverMass;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
Mover::DynamicBounce(
Mover *other,
Scalar delta_t,
Scalar penetration,
const Normal3D &normal,
Scalar *elasticity
)
{
Check_Object(this);
Check_Object(other);
Check_Object(&normal);
Check_Pointer(elasticity);
Verify(penetration >= 0.0f && penetration <= 1.0f);
Verify(*elasticity >= 0.0f && *elasticity <= 1.0f);
Verify(delta_t > SMALL);
//
//------------------------------------------------------------------------
// Get the relative velocity of the other guy, and figure out the velocity
// delta along the normal
//------------------------------------------------------------------------
//
Scalar k1 = worldSpaceVelocity.linearMotion.GetLengthSquared();
Scalar k2 = other->worldSpaceVelocity.linearMotion.GetLengthSquared();
const GameModel *model = GetGameModel();
Check_Pointer(model);
const GameModel *other_model = other->GetGameModel();
Check_Pointer(model);
Scalar mass_ratio =
other_model->moverMass / (model->moverMass + other_model->moverMass);
Vector3D v;
v.Subtract(other->worldSpaceVelocity.linearMotion, worldSpaceVelocity.linearMotion);
Scalar temp = (1.0f + *elasticity) * (v*normal);
Vector3D delta_v;
delta_v.Multiply(normal, temp);
//
//-------------------------------------------------------------------------
// Figure out the kinetic energy loss in kilojoules, and bounce the primary
// mover
//
// There was an additional multiplication by mass ratio in system 3 code...
// we should make sure it is really needed...
//-------------------------------------------------------------------------
//
v.AddScaled(delta_v, v, -2.0f);
worldSpaceVelocity.linearMotion.AddScaled(
worldSpaceVelocity.linearMotion,
delta_v,
mass_ratio
);
STOP(("Not implemented"));
#if 0
localOrigin.linearPosition.AddScaled(
localOrigin.linearPosition,
delta_v,
delta_t * penetration
);
#endif
//
//----------------------------------------------------------
// Bounce the second object, and reset it's update values...
//----------------------------------------------------------
//
other->worldSpaceVelocity.linearMotion.AddScaled(
other->worldSpaceVelocity.linearMotion,
delta_v,
mass_ratio - 1.0f
);
#if 0
other->localOrigin.linearPosition.AddScaled(
other->localOrigin.linearPosition,
delta_v,
delta_t
);
#endif
//
//--------------------------------
// Return the result in kilojoules
//--------------------------------
//
k1 -= worldSpaceVelocity.linearMotion.GetLengthSquared();
k2 -= other->worldSpaceVelocity.linearMotion.GetLengthSquared();
return
0.0005f * mass_ratio
* (model->moverMass * k1 + other_model->moverMass * k2);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Mover::TestInstance()
{
Verify(IsDerivedFrom(DefaultData));
}