This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/wwphys/rbody_obsolete.cpp

478 lines
No EOL
12 KiB
C++

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***************************************************************************************
**
** OBSOLETE CODE!!!!!
**
** THIS CODE IS JUST HERE IN CASE THERE IS SOME USEFUL IDEA IN IT THAT I MAY HAVE
** FORGOTTEN. PROBABLY NOT!
**
***************************************************************************************/
/*
** This is a timestep function for RigidBodyClass that tried to do orientation and
** position updates independently when a collision occured
*/
#if 0
void RigidBodyClass::Timestep(float dt)
{
const int MAX_BUMPS = 5;
Assert_State_Valid();
LastTimestep = dt;
/*
** Repeat until we eat all of the time
*/
float remaining_time = dt;
float timestep;
int bumps = 0;
Inc_Ignore_Counter();
while ((remaining_time > 0.0f) && (bumps < MAX_BUMPS)) {
timestep = remaining_time;
bumps++;
CastResultStruct result;
OBBoxClass obbox;
/*
** Integrate the state of the object
*/
Assert_State_Valid();
RigidBodyStateStruct oldstate = State;
Integrate(timestep);
Assert_State_Valid();
/*
** sample the start and end positions and orientations
*/
Vector3 p0 = oldstate.Position;
Vector3 p1 = State.Position;
Quaternion q0 = oldstate.Orientation;
Quaternion q1 = State.Orientation;
/*
** rotate in place
*/
Matrix3D rotate_in_place(q1,p0);
Model->Set_Transform(rotate_in_place);
obbox = Box->Get_Box();
result.Reset();
PhysOBBoxCollisionTestClass boxrotate( obbox,
Vector3(0,0,0),
&result,
Get_Collision_Group(),
COLLISION_TYPE_PHYSICAL);
PhysicsSceneClass::Get_Instance()->Cast_OBBox(boxrotate);
if (result.StartBad) {
q1 = q0;
State.Orientation = q0;
State.AMomentum /= 4.0f;
StickCount++;
} else {
StickCount = 0;
}
/*
** now translate
*/
Matrix3D initial_position(q1,p0);
Vector3 move(p1 - p0);
Model->Set_Transform(initial_position);
obbox = Box->Get_Box();
result.Reset();
result.ComputePoint = true;
PhysOBBoxCollisionTestClass boxmove( obbox,
move,
&result,
Get_Collision_Group(),
COLLISION_TYPE_PHYSICAL);
PhysicsSceneClass::Get_Instance()->Cast_OBBox(boxmove);
if (result.StartBad) {
remaining_time = 0;
State = oldstate;
//goto do_it_again;
} else {
if (result.Fraction == 1.0f) {
// accepting the entire move
remaining_time -= timestep;
State.Position = p0 + 0.99f * move;
} else {
// IMPACT!
// only take the fraction of time
remaining_time -= result.Fraction * timestep;
// only move up to the collision point, minus a padding amount
#if 0
float len = (result.Fraction * move).Length();
len -= MOVE_BUFFER;
if (len > 0.0f) {
move.Normalize();
move *= len;
State.Position = p0 + move;
} else {
State.Position = p0;
}
#else
State.Position = p0 + 0.99f * result.Fraction * move;
#endif
// interpolate the momenta to approximate their state at time of impact
Assert_State_Valid();
State.LMomentum = oldstate.LMomentum + (State.LMomentum - oldstate.LMomentum) * result.Fraction;
State.AMomentum = oldstate.AMomentum + (State.AMomentum - oldstate.AMomentum) * result.Fraction;
Assert_State_Valid();
// TODO: support multiple contact points!
ContactCount = 1;
ContactPoint[0] = result.Point;
Vector3 impulse;
Compute_Impact(result,&impulse);
Vector3 padot0,padot1;
Compute_Point_Velocity(result.Point,&padot0);
Assert_State_Valid();
Apply_Impulse(impulse,result.Point);
Assert_State_Valid();
Assert_State_Valid();
// E3Demo!!!
if (StickCount > 3) {
State.AMomentum *= 0.5f;
State.Position.Z += 0.1f;
Update_Auxiliary_State();
Apply_Impulse(result.Normal * 0.25f * Get_Weight());
}
Assert_State_Valid();
}
}
Update_Auxiliary_State();
}
Dec_Ignore_Counter();
WWASSERT(Model);
Model->Set_Transform(Matrix3D(Rotation,State.Position));
Update_Cull_Box();
Assert_State_Valid();
if (ContactBox != NULL) {
ContactBox->Compute_Forces();
}
#ifdef WWDEBUG
if(Is_Debug_Display_Enabled()) {
Add_Debug_Vector(State.Position,Velocity,LMOMENTUM_COLOR);
Add_Debug_Vector(State.Position,AngularVelocity,AMOMENTUM_COLOR);
}
#endif
}
#endif
/*
** This was a version of Timestep which used a binary search through time to try
** and find the "exact" time of collision. What a collosal waste of time!
*/
#if 0
void RigidBodyClass::Timestep(float dt)
{
if ( Is_Immovable() ) {
return;
}
WWASSERT(Model);
WWASSERT(ContactBox);
Inc_Ignore_Counter();
#ifdef RBODY_DEBUGGING
WWDEBUG_SAY(("------------------------------\r\n"));
WWDEBUG_SAY(("RigidBody Timestep Begin.\r\n"));
WWASSERT(!ContactBox->Is_Intersecting());
#endif
/*
** Repeat until we eat all of the time
*/
const int MAX_COLLISIONS = 100;
int collisions = 0;
float remaining_time = dt;
float timestep;
#ifdef RBODY_DEBUGGING
WWDEBUG_SAY(("clock counter begin:\r\n"));
#endif
while ((remaining_time > 0.0f) && (collisions < MAX_COLLISIONS)) {
timestep = remaining_time;
/*
** Integrate the state of the object
*/
#ifdef RBODY_DEBUGGING
WWDEBUG_SAY(("Computing new state, delta_t = %f:\r\n",timestep));
#endif
RigidBodyStateStruct oldstate = State;
Integrate(timestep);
#ifdef RBODY_DEBUGGING
WWDEBUG_SAY(("Done.\r\n\r\n"));
#endif
/*
** Check the final state of the object for collision.
*/
if (!ContactBox->Is_Intersecting()) {
/*
** Not intersecting so we're accepting the entire move
*/
remaining_time -= timestep;
StickCount = 0;
#ifdef RBODY_DEBUGGING
WWDEBUG_SAY(("No Collision\r\n"));
#endif
} else {
#ifdef RBODY_DEBUGGING
WWDEBUG_SAY(("Collision! Searching for TOC.\r\n"));
#endif
/*
** Sample the start and end positions and orientations.
*/
Vector3 p0 = oldstate.Position;
Vector3 p1 = State.Position;
Quaternion q0 = oldstate.Orientation;
Quaternion q1 = State.Orientation;
/*
** Assert that our start point was not intersecting.
*/
#ifdef WWDEBUG
#ifdef RBODY_DEBUGGING
WWDEBUG_SAY(("Prev Position: %f %f %f\r\n",oldstate.Position.X,oldstate.Position.Y,oldstate.Position.Z));
WWDEBUG_SAY(("New Position: %f %f %f\r\n",State.Position.X,State.Position.Y,State.Position.Z));
WWDEBUG_SAY(("Prev Orientation: %f %f %f %f\r\n",oldstate.Orientation.X,oldstate.Orientation.Y,oldstate.Orientation.Z,oldstate.Orientation.W));
WWDEBUG_SAY(("New Orientation: %f %f %f %f\r\n",State.Orientation.X,State.Orientation.Y,State.Orientation.Z,State.Orientation.W));
ContactBox->Set_Transform(q0,p0);
WWASSERT(!ContactBox->Is_Intersecting());
#endif
#endif
/*
** Binary search to find the time of collision
*/
float t = 0.0f;
float t0 = 0.0f;
float t1 = 1.0f;
const float COLLISION_EPSILON = 0.01f;//(float)WWMATH_EPSILON;
Vector3 p;
Quaternion q;
SlerpInfoStruct slerpinfo;
Slerp_Setup(q0,q1,&slerpinfo);
while (t1 - t0 > COLLISION_EPSILON) {
t = (t1 + t0) / 2.0f;
/*
** Compute interpolated orientation and position
*/
Lerp(p0,p1,t,&p);
Cached_Slerp(q0,q1,t,&slerpinfo,&q);
ContactBox->Set_Transform(q,p);
/*
** Test for collision here
*/
#ifdef RBODY_DEBUGGING
bool intersecting = ContactBox->Is_Intersecting();
WWDEBUG_SAY((" t0 = %f t1 = %f t=%f %s\r\n",t0,t1,t,(intersecting ? "colliding" : "not-colliding")));
#endif
/*
** Zero in on the TOC
*/
if (intersecting) {
t1 = t;
} else {
t0 = t;
}
}
/*
** t0 is guaranteed to be non-intersecting so use it for TOC
*/
t = t0;
remaining_time -= t * timestep;
if (t == 0.0f) {
remaining_time -= 0.001f;
}
#ifdef RBODY_DEBUGGING
WWDEBUG_SAY(("Found collision at fraction: %f\r\n",t));
#endif
/*
** Compute the state right before the collision
*/
Cached_Slerp(q0,q1,t,&slerpinfo,&State.Orientation);
Lerp(p0,p1,t,&State.Position);
Lerp(oldstate.LMomentum,State.LMomentum,t,&State.LMomentum);
Lerp(oldstate.AMomentum,State.AMomentum,t,&State.AMomentum);
Update_Auxiliary_State();
//ContactBox->Set_Transform(Matrix3D(State.Orientation,State.Position));
#ifdef RBODY_DEBUGGING
// WWDEBUG_SAY(("Position: %f %f %f\r\n",State.Position.X,State.Position.Y,State.Position.Z));
// WWDEBUG_SAY(("Orientation: %f %f %f %f\r\n",State.Orientation.X,State.Orientation.Y,State.Orientation.Z,State.Orientation.W));
WWASSERT(!ContactBox->Is_Intersecting());
#endif
/*
** Find the collision point and normal and apply an impulse to the object.
*/
ContactBox->Compute_Contacts();
#if 0 // Compute an impulse for the worst contact
Vector3 point;
Vector3 normal;
for (int i=0; i<ContactBox->Get_Contact_Count(); i++) {
if (ContactBox->Get_Contact(i).Fraction < frac) {
point = ContactBox->Get_Contact(i).Point;
normal = ContactBox->Get_Contact(i).Normal;
};
}
Vector3 impulse;
// Compute_Impact(point,normal,&impulse);
// DEBUG DEBUG apply impulse only at CM!
Compute_Impact(State.Position,normal,&impulse);
Apply_Impulse(impulse,point);
#ifdef RBODY_DEBUGGING
DEBUG_RENDER_POINT(point,Vector3(1,0,0));
WWDEBUG_SAY(("Applied Impulse: %f %f %f\r\n",impulse.X,impulse.Y,impulse.Z));
#endif
#endif
#if 1 // Simultaneously compute impulses for all contacts
if (ContactBox->Get_Contact_Count() > 0) {
int i;
Vector3 * impulses = new Vector3[ContactBox->Get_Contact_Count()];
for (i=0; i<ContactBox->Get_Contact_Count(); i++) {
Vector3 point;
Vector3 normal;
point = ContactBox->Get_Contact(i).Point;
normal = ContactBox->Get_Contact(i).Normal;
Compute_Impact(point,normal,&(impulses[i]));
}
for (i=0; i<ContactBox->Get_Contact_Count(); i++) {
Vector3 point;
point = ContactBox->Get_Contact(i).Point;
impulses[i] /= ContactBox->Get_Contact_Count();
Apply_Impulse(impulses[i],point);
Assert_State_Valid();
}
}
#endif
#if 0 // Repeatedly compute impulses until the object is happy.
int cur_contact = 0;
int impact_count = 0;
bool done = false;
while (!done && (impact_count < 100)) {
Vector3 impulse;
const Vector3 & point = ContactBox->Get_Contact(cur_contact).Point;
const Vector3 & normal = ContactBox->Get_Contact(cur_contact).Normal;
if (Is_Colliding(point,normal)) {
Compute_Impact(point,normal,&impulse);
Apply_Impulse(impulse,point);
}
done = true;
for (int i=0; i<ContactBox->Get_Contact_Count(); i++) {
if (Is_Colliding(ContactBox->Get_Contact(i).Point,ContactBox->Get_Contact(i).Normal)) {
done = false;
}
}
cur_contact = (cur_contact + 1) % ContactBox->Get_Contact_Count();
impact_count++;
}
#ifdef RBODY_DEBUGGING
WWDEBUG_SAY(("Number of impacts to resolve collision: %d\r\n",impact_count));
#endif
#endif
#ifdef RBODY_DEBUGGING
WWDEBUG_SAY(("\r\n"));
WWDEBUG_SAY(("Position: %f %f %f\r\n",State.Position.X,State.Position.Y,State.Position.Z));
WWDEBUG_SAY(("Orientation: %f %f %f %f\r\n",State.Orientation.X,State.Orientation.Y,State.Orientation.Z,State.Orientation.W));
#endif
}
collisions++;
}
#ifdef RBODY_DEBUGGING
WWASSERT(!ContactBox->Is_Intersecting());
WWDEBUG_SAY(("RigidBody Timestep End.\r\n"));
WWDEBUG_SAY(("\r\n"));
#endif
#ifdef WWDEBUG
if(Is_Debug_Display_Enabled()) {
Add_Debug_Vector(State.Position,Velocity,LMOMENTUM_COLOR);
Add_Debug_Vector(State.Position,AngularVelocity,AMOMENTUM_COLOR);
}
#endif
Dec_Ignore_Counter();
Model->Set_Transform(Matrix3D(Rotation,State.Position));
Update_Cull_Box();
}
#endif //0