void CPhysicsSpring::AttachListener() { if ( !(m_pObjStart->GetCallbackFlags() & CALLBACK_NEVER_DELETED) ) { m_pObjStart->GetObject()->add_listener_object( this ); } if ( !(m_pObjEnd->GetCallbackFlags() & CALLBACK_NEVER_DELETED) ) { m_pObjEnd->GetObject()->add_listener_object( this ); } }
void CShadowController::AttachObject( void ) { IVP_Real_Object *pivp = m_pObject->GetObject(); IVP_Core *pCore = pivp->get_core(); m_saveRot = pCore->rot_speed_damp_factor; m_savedRI = *pCore->get_rot_inertia(); m_savedMass = pCore->get_mass(); m_savedMaterialIndex = m_pObject->GetMaterialIndexInternal(); m_pObject->SetMaterialIndex( MATERIAL_INDEX_SHADOW ); pCore->rot_speed_damp_factor = IVP_U_Float_Point( 100, 100, 100 ); if ( !m_allowPhysicsRotation ) { IVP_U_Float_Point ri( 1e15f, 1e15f, 1e15f ); pCore->set_rotation_inertia( &ri ); } if ( !m_allowPhysicsMovement ) { m_pObject->SetMass( 1e6f ); //pCore->inv_rot_inertia.hesse_val = 0.0f; m_pObject->EnableGravity( false ); } pCore->calc_calc(); pivp->get_environment()->get_controller_manager()->add_controller_to_core( this, pCore ); m_shadow.lastPosition.set_to_zero(); }
int CPlayerController::TryTeleportObject( void ) { if ( m_handler ) { Vector hlPosition; ConvertPositionToHL( m_targetPosition, hlPosition ); if ( !m_handler->ShouldMoveTo( m_pObject, hlPosition ) ) return 0; } IVP_Real_Object *pivp = m_pObject->GetObject(); IVP_U_Quat targetOrientation; IVP_U_Point outPosition; pivp->get_quat_world_f_object_AT( &targetOrientation, &outPosition ); if ( pivp->is_collision_detection_enabled() ) { m_pObject->EnableCollisions( false ); pivp->beam_object_to_new_position( &targetOrientation, &m_targetPosition, IVP_TRUE ); m_pObject->EnableCollisions( true ); } else { pivp->beam_object_to_new_position( &targetOrientation, &m_targetPosition, IVP_TRUE ); } return 1; }
void CPhysicsSpring::DetachListener() { if ( !(m_pObjStart->GetCallbackFlags() & CALLBACK_NEVER_DELETED) ) { m_pObjStart->GetObject()->remove_listener_object( this ); } if ( !(m_pObjEnd->GetCallbackFlags() & CALLBACK_NEVER_DELETED) ) { m_pObjEnd->GetObject()->remove_listener_object( this ); } m_pObjStart = NULL; m_pObjEnd = NULL; m_pSpring = NULL; }
bool CPlayerController::IsInContact( void ) { IVP_Real_Object *pivp = m_pObject->GetObject(); if ( !pivp->flags.collision_detection_enabled ) return false; IVP_Synapse_Friction *pfriction = pivp->get_first_friction_synapse(); while ( pfriction ) { extern IVP_Real_Object *GetOppositeSynapseObject( IVP_Synapse_Friction *pfriction ); IVP_Real_Object *pobj = GetOppositeSynapseObject( pfriction ); if ( pobj->flags.collision_detection_enabled ) { // skip if this is a static object if ( !pobj->get_core()->physical_unmoveable && !pobj->get_core()->pinned ) { CPhysicsObject *pPhys = static_cast<CPhysicsObject *>(pobj->client_data); // skip if this is a shadow object // UNDONE: Is this a hack? need a better way to detect shadows? if ( !(pPhys->GetCallbackFlags() & CALLBACK_SHADOW_COLLISION) ) return true; } } pfriction = pfriction->get_next(); } return false; }
void event_object_revived( IVP_Event_Object *pEvent ) { CPhysicsObject *pObject = static_cast<CPhysicsObject *>(pEvent->real_object->client_data); if ( !pObject ) return; int sleepState = pObject->GetSleepState(); pObject->NotifyWake(); // asleep, but already in active list if ( sleepState == OBJ_STARTSLEEP ) return; // don't track static objects (like the world). That way we only track objects that will move if ( pObject->GetObject()->get_movement_state() != IVP_MT_STATIC ) { Assert(pObject->GetActiveIndex()==0xFFFF); if ( pObject->GetActiveIndex()!=0xFFFF) return; int index = m_activeObjects.AddToTail( pObject ); pObject->SetActiveIndex( index ); } if ( m_pCallback ) { m_pCallback->ObjectWake( pObject ); } }
void CPhysicsMotionController::DetachObject( IPhysicsObject *pObject ) { CPhysicsObject *pPhys = static_cast<CPhysicsObject *>(pObject); IVP_Real_Object *pIVP = pPhys->GetObject(); IVP_Core *core = pIVP->get_core(); RemoveCore(core); }
void CPhysicsSpring::GetEndpoints( Vector* worldPositionStart, Vector* worldPositionEnd ) { IVP_U_Point world_coords; if ( worldPositionStart ) { const IVP_Anchor *anchor = m_pSpring->get_actuator_anchor(0); TransformLocalToIVP( anchor->object_pos, world_coords, m_pObjStart->GetObject(), true ); ConvertPositionToHL( world_coords, *worldPositionStart ); } if ( worldPositionEnd ) { const IVP_Anchor *anchor = m_pSpring->get_actuator_anchor(1); TransformLocalToIVP( anchor->object_pos, world_coords, m_pObjEnd->GetObject(), true ); ConvertPositionToHL( world_coords, *worldPositionEnd ); } }
void CPlayerController::AttachObject( void ) { IVP_Real_Object *pivp = m_pObject->GetObject(); IVP_Core *pCore = pivp->get_core(); m_saveRot = pCore->rot_speed_damp_factor; pCore->rot_speed_damp_factor = IVP_U_Float_Point( 100, 100, 100 ); pCore->calc_calc(); pivp->get_environment()->get_controller_manager()->add_controller_to_core( this, pCore ); }
void CShadowController::DetachObject( void ) { IVP_Real_Object *pivp = m_pObject->GetObject(); IVP_Core *pCore = pivp->get_core(); pCore->rot_speed_damp_factor = m_saveRot; pCore->set_mass( m_savedMass ); pCore->set_rotation_inertia( &m_savedRI ); // this calls calc_calc() m_pObject = NULL; pivp->get_environment()->get_controller_manager()->remove_controller_from_core( this, pCore ); }
void CPlayerController::do_simulation_controller( IVP_Event_Sim *es,IVP_U_Vector<IVP_Core> *) { if ( !m_enable ) return; IVP_Real_Object *pivp = m_pObject->GetObject(); IVP_Environment *pIVPEnv = pivp->get_environment(); CPhysicsEnvironment *pVEnv = (CPhysicsEnvironment *)pIVPEnv->client_data; float psiScale = pVEnv->GetInvPSIScale(); if ( !psiScale ) return; IVP_Core *pCore = pivp->get_core(); // current situation const IVP_U_Matrix *m_world_f_core = pCore->get_m_world_f_core_PSI(); const IVP_U_Point *cur_pos_ws = m_world_f_core->get_position(); // --------------------------------------------------------- // Translation // --------------------------------------------------------- IVP_U_Float_Point delta_position; delta_position.subtract( &m_targetPosition, cur_pos_ws); if (!pivp->flags.shift_core_f_object_is_zero) { IVP_U_Float_Point shift_cs_os_ws; m_world_f_core->vmult3( pivp->get_shift_core_f_object(), &shift_cs_os_ws); delta_position.subtract( &shift_cs_os_ws ); } IVP_DOUBLE qdist = delta_position.quad_length(); // UNDONE: This is totally bogus! Measure error using last known estimate // not current position! if ( qdist > m_maxDeltaPosition * m_maxDeltaPosition ) { if ( TryTeleportObject() ) return; } // float to allow stepping if ( m_onground ) { const IVP_U_Point *pgrav = es->environment->get_gravity(); IVP_U_Float_Point gravSpeed; gravSpeed.set_multiple( pgrav, es->delta_time ); pCore->speed.subtract( &gravSpeed ); } ComputeController( pCore->speed, delta_position, m_maxSpeed, psiScale / es->delta_time, m_dampFactor ); }
void CPlayerController::DetachObject( void ) { if ( !m_pObject ) return; IVP_Real_Object *pivp = m_pObject->GetObject(); IVP_Core *pCore = pivp->get_core(); pCore->rot_speed_damp_factor = m_saveRot; pCore->calc_calc(); m_pObject = NULL; pivp->get_environment()->get_controller_manager()->remove_controller_from_core( this, pCore ); }
void CShadowController::StepUp( float height ) { Vector step( 0, 0, height ); IVP_Real_Object *pIVP = m_pObject->GetObject(); IVP_U_Quat world_f_object; IVP_U_Point positionIVP, deltaIVP; ConvertPositionToIVP( step, deltaIVP ); pIVP->get_quat_world_f_object_AT( &world_f_object, &positionIVP ); positionIVP.add( &deltaIVP ); pIVP->beam_object_to_new_position( &world_f_object, &positionIVP, IVP_TRUE ); }
void CShadowController::InitFromTemplate( const vphysics_save_cshadowcontroller_t &controllerTemplate ) { m_pObject = controllerTemplate.pObject; m_secondsToArrival = controllerTemplate.secondsToArrival; m_saveRot = controllerTemplate.saveRot; m_savedRI = controllerTemplate.savedRI; m_currentSpeed = controllerTemplate.currentSpeed; m_savedMass = controllerTemplate.savedMass; m_savedMaterialIndex = controllerTemplate.savedMaterial; m_enable = controllerTemplate.enable; m_allowPhysicsMovement = controllerTemplate.allowPhysicsMovement; m_allowPhysicsRotation = controllerTemplate.allowPhysicsRotation; ConvertShadowControllerToIVP( controllerTemplate.shadowParams, m_shadow ); m_pObject->GetObject()->get_environment()->get_controller_manager()->add_controller_to_core( this, m_pObject->GetObject()->get_core() ); }
void CPlayerController::MaxSpeed( const Vector &velocity ) { IVP_Core *pCore = m_pObject->GetObject()->get_core(); IVP_U_Float_Point ivpVel; ConvertPositionToIVP( velocity, ivpVel ); IVP_U_Float_Point available = ivpVel; // normalize and save length float length = ivpVel.real_length_plus_normize(); float dot = ivpVel.dot_product( &pCore->speed ); if ( dot > 0 ) { ivpVel.mult( dot * length ); available.subtract( &ivpVel ); } IVP_Float_PointAbs( m_maxSpeed, available ); }
void CShadowController::do_simulation_controller( IVP_Event_Sim *es,IVP_U_Vector<IVP_Core> *) { if ( m_enable ) { IVP_Real_Object *pivp = m_pObject->GetObject(); ComputeShadowControllerIVP( pivp, m_shadow, m_secondsToArrival, es->delta_time ); // if we have time left, subtract it off m_secondsToArrival -= es->delta_time; if ( m_secondsToArrival < 0 ) { m_secondsToArrival = 0; } } else { m_shadow.lastPosition.set_to_zero(); } }
void CPlayerController::Update( const Vector& position, const Vector& velocity, bool onground, IPhysicsObject *ground ) { IVP_U_Point targetPositionIVP; IVP_U_Float_Point targetSpeedIVP; ConvertPositionToIVP( position, targetPositionIVP ); ConvertPositionToIVP( velocity, targetSpeedIVP ); // if the object hasn't moved, abort if ( targetSpeedIVP.quad_distance_to( &m_currentSpeed ) < 1e-6 ) { if ( targetPositionIVP.quad_distance_to( &m_targetPosition ) < 1e-6 ) { return; } } m_targetPosition = targetPositionIVP; m_currentSpeed = targetSpeedIVP; IVP_Real_Object *pivp = m_pObject->GetObject(); IVP_Core *pCore = pivp->get_core(); IVP_Environment *pEnv = pivp->get_environment(); pEnv->get_controller_manager()->ensure_core_in_simulation(pCore); m_enable = true; // m_onground makes this object anti-grav // UNDONE: Re-evaluate this m_onground = false;//onground; if ( velocity.LengthSqr() <= 0.1f ) { // no input velocity, just go where physics takes you. m_enable = false; ground = NULL; } else { MaxSpeed( velocity ); } }
void CPhysicsMotionController::AttachObject( IPhysicsObject *pObject ) { Assert(pObject); // BUGBUG: Sometimes restore comes back with a NULL, REVISIT if ( !pObject || pObject->IsStatic() ) return; CPhysicsObject *pPhys = static_cast<CPhysicsObject *>(pObject); IVP_Real_Object *pIVP = pPhys->GetObject(); IVP_Core *pCore = pIVP->get_core(); #if DEBUG int index = m_coreList.Find(pCore); if ( m_coreList.IsValidIndex(index) ) { Msg("Attached core twice!!!\n"); return; } #endif m_coreList.AddToTail( pCore ); pCore->add_core_controller( (IVP_Controller *)this ); }
void CShadowController::MaxSpeed( const Vector &velocity, const AngularImpulse &angularVelocity ) { IVP_Core *pCore = m_pObject->GetObject()->get_core(); // limit additional velocity to that which is not amplifying the current velocity IVP_U_Float_Point ivpVel; ConvertPositionToIVP( velocity, ivpVel ); IVP_U_Float_Point available = ivpVel; m_currentSpeed = ivpVel; // normalize and save length float length = ivpVel.real_length_plus_normize(); float dot = ivpVel.dot_product( &pCore->speed ); if ( dot > 0 ) { ivpVel.mult( dot * length ); available.subtract( &ivpVel ); } IVP_Float_PointAbs( m_shadow.maxSpeed, available ); // same for angular, project on to current and remove redundant (amplifying) input IVP_U_Float_Point ivpAng; ConvertAngularImpulseToIVP( angularVelocity, ivpAng ); IVP_U_Float_Point availableAng = ivpAng; float lengthAng = ivpAng.real_length_plus_normize(); float dotAng = ivpAng.dot_product( &pCore->rot_speed ); if ( dotAng > 0 ) { ivpAng.mult( dotAng * lengthAng ); availableAng.subtract( &ivpAng ); } IVP_Float_PointAbs( m_shadow.maxAngular, availableAng ); }
//----------------------------------------------------------------------------- // Purpose: This walks the objects in the environment and generates friction events // for any scraping that is occurring. //----------------------------------------------------------------------------- void ProcessActiveObjects( IVP_Environment *pEnvironment, IPhysicsCollisionEvent *pEvent ) { // FIXME: Is this correct? Shouldn't it do next PSI - lastScrape? float nextTime = pEnvironment->get_old_time_of_last_PSI().get_time(); float delta = nextTime - m_lastScrapeTime; // only process if we have done a PSI if ( delta < pEnvironment->get_delta_PSI_time() ) return; float t = 1.0f; t /= delta; if ( t > 10.0f ) t = 10.0f; m_lastScrapeTime = nextTime; // UNDONE: This only calls friciton for one object in each pair. // UNDONE: Split energy in half and call for both objects? // UNDONE: Don't split/call if one object is static (like the world)? for ( int i = 0; i < m_activeObjects.Count(); i++ ) { CPhysicsObject *pObject = m_activeObjects[i]; IVP_Real_Object *ivpObject = pObject->GetObject(); // no friction callbacks for this object if ( ! (pObject->GetCallbackFlags() & CALLBACK_GLOBAL_FRICTION) ) continue; // UNDONE: IVP_Synapse_Friction is supposed to be opaque. Is there a better way // to implement this? Using the friction listener is much more work for the CPU // and considers sleeping objects. IVP_Synapse_Friction *pfriction = ivpObject->get_first_friction_synapse(); while ( pfriction ) { IVP_Contact_Point *contact = pfriction->get_contact_point(); IVP_Synapse_Friction *pOpposite = GetOppositeSynapse( pfriction ); IVP_Real_Object *pobj = pOpposite->get_object(); CPhysicsObject *pScrape = (CPhysicsObject *)pobj->client_data; // friction callbacks for this object? if ( pScrape->GetCallbackFlags() & CALLBACK_GLOBAL_FRICTION ) { float energy = IVP_Contact_Point_API::get_eliminated_energy( contact ); if ( energy ) { IVP_Contact_Point_API::reset_eliminated_energy( contact ); // scrape with an estimate for the energy per unit mass // This assumes that the game is interested in some measure of vibration // for sound effects. This also assumes that more massive objects require // more energy to vibrate. energy = energy * t * ivpObject->get_core()->get_inv_mass(); if ( energy > 0.05f ) { int hitSurface = physprops->RemapIVPMaterialIndex( pOpposite->get_material_index() ); CPhysicsFrictionData data(pfriction); pEvent->Friction( pObject, ConvertEnergyToHL(energy), pObject->GetMaterialIndexInternal(), hitSurface, &data ); } } } pfriction = pfriction->get_next(); } } }