/* ** 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 . */ /*************************************************************************************** ** ** 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; iGet_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; iGet_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; iGet_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; iGet_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