bool CPlayerController::IsInContact() {
	CPhysicsEnvironment *pEnv = m_pObject->GetVPhysicsEnvironment();

	int numManifolds = pEnv->GetBulletEnvironment()->getDispatcher()->getNumManifolds();
	for (int i = 0; i < numManifolds; i++) {
		btPersistentManifold *contactManifold = pEnv->GetBulletEnvironment()->getDispatcher()->getManifoldByIndexInternal(i);
		const btCollisionObject *obA = contactManifold->getBody0();
		const btCollisionObject *obB = contactManifold->getBody1();
		CPhysicsObject *pPhysUs = NULL;
		CPhysicsObject *pPhysOther = NULL;

		if (contactManifold->getNumContacts() > 0 && (obA == m_pObject->GetObject() || obB == m_pObject->GetObject())) {
			if (obA == m_pObject->GetObject()) {
				pPhysUs = (CPhysicsObject *)obA->getUserPointer();
				pPhysOther = (CPhysicsObject *)obB->getUserPointer();
			} else if (obB == m_pObject->GetObject()) {
				pPhysUs = (CPhysicsObject *)obB->getUserPointer();
				pPhysOther = (CPhysicsObject *)obA->getUserPointer();
			}

			if (pPhysOther->IsStatic() || !pPhysOther->IsMotionEnabled() || (pPhysOther->GetCallbackFlags() & CALLBACK_SHADOW_COLLISION))
				continue;

			return true;
		}
	}

	return false;
}
void SerializeWorld_f(const CCommand &args) {
	if (args.ArgC() != 3) {
		Msg("Usage: vphysics_serialize <index> <name>\n");
		return;
	}

	CPhysicsEnvironment *pEnv = (CPhysicsEnvironment *)g_Physics.GetActiveEnvironmentByIndex(atoi(args.Arg(2)));
	if (pEnv) {
		btDiscreteDynamicsWorld *pWorld = (btDiscreteDynamicsWorld *)pEnv->GetBulletEnvironment();
		Assert(pWorld);

		btSerializer *pSerializer = new btDefaultSerializer;
		pWorld->serialize(pSerializer);

		// FIXME: We shouldn't be using this. Find the appropiate method from valve interfaces.
		const char *pName = args.Arg(3);
		FILE *pFile = fopen(pName, "wb");
		if (pFile) {
			fwrite(pSerializer->getBufferPointer(), pSerializer->getCurrentBufferSize(), 1, pFile);
			fclose(pFile);
		} else {
			Warning("Couldn't open \"%s\" for writing!\n", pName);
		}
	} else {
		Warning("Invalid environment index supplied!\n");
	}
}
// UNEXPOSED
void CPhysicsEnvironment::TickCallback(btDynamicsWorld *world, btScalar timeStep) {
	if (!world) return;

	CPhysicsEnvironment *pEnv = (CPhysicsEnvironment *)world->getWorldUserInfo();
	if (pEnv)
		pEnv->BulletTick(timeStep);
}
void CPhysicsObject::SetShadow( const Vector &maxVelocity, const AngularImpulse &maxAngularVelocity, bool allowPhysicsMovement, bool allowPhysicsRotation )
{
	if ( m_pShadow )
	{
		m_pShadow->MaxSpeed( maxVelocity, maxAngularVelocity );
	}
	else
	{
	//	m_pObject->get_core()->rot_speed_damp_factor = IVP_U_Float_Point( 1e5f, 1e5f, 1e5f );
		m_shadowTempGravityDisable = false;

		unsigned int flags = GetCallbackFlags() | CALLBACK_SHADOW_COLLISION;
		flags &= ~CALLBACK_GLOBAL_FRICTION;
		flags &= ~CALLBACK_GLOBAL_COLLIDE_STATIC;
		SetCallbackFlags( flags );

		IVP_Environment *pEnv = m_pObject->get_environment();
		CPhysicsEnvironment *pVEnv = (CPhysicsEnvironment *)pEnv->client_data;
		m_pShadow = pVEnv->CreateShadowController( this, allowPhysicsMovement, allowPhysicsRotation );
		m_pShadow->MaxSpeed( maxVelocity, maxAngularVelocity );
		SetRollingDrag( 0 );
		EnableDrag( false );
		if ( !allowPhysicsMovement )
		{
			EnableGravity( false );
		}
	}
}
void CPhysicsObject::RemoveShadowController()
{
	if ( m_pShadow )
	{
		IVP_Environment *pEnv = m_pObject->get_environment();
		CPhysicsEnvironment *pVEnv = (CPhysicsEnvironment *)pEnv->client_data;
		pVEnv->DestroyShadowController( m_pShadow );
		m_pShadow = NULL;
	}
}
bool RestorePhysicsSpring( const physrestoreparams_t &params, CPhysicsSpring **ppSpring )
{
	vphysics_save_cphysicsspring_t springTemplate;
	memset( &springTemplate, 0, sizeof(springTemplate) );
	params.pRestore->ReadAll( &springTemplate );
	CPhysicsEnvironment *pEnvironment = (CPhysicsEnvironment *)params.pEnvironment;
	*ppSpring = (CPhysicsSpring *)pEnvironment->CreateSpring( springTemplate.pObjStart, springTemplate.pObjEnd, &springTemplate );

	return true;
}
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 );
}
CPhysicsObject::~CPhysicsObject( void )
{
	RemoveShadowController();

	if ( m_pObject )
	{
		// prevents callbacks to the game code / unlink from this object
		m_callbacks = 0;
		m_pGameData = 0;
		m_pObject->client_data = 0;

		IVP_Core *pCore = m_pObject->get_core();
		if ( pCore->physical_unmoveable == IVP_TRUE && pCore->controllers_of_core.n_elems )
		{
			// go ahead and notify them if this happens in the real world
			for(int i = pCore->controllers_of_core.len()-1; i >=0 ;i-- ) 
			{
				IVP_Controller *my_controller = pCore->controllers_of_core.element_at(i);
				my_controller->core_is_going_to_be_deleted_event(pCore);
				Assert(my_controller==pCore->environment->get_gravity_controller());
			}
		}

		// UNDONE: Don't free the surface manager here
		// UNDONE: Remove reference to it by calling something in physics_collide
		IVP_SurfaceManager *pSurman = GetSurfaceManager();

		IVP_Environment *pEnv = m_pObject->get_environment();
		CPhysicsEnvironment *pVEnv = (CPhysicsEnvironment *)pEnv->client_data;

		// BUGBUG: Sometimes IVP will call a "revive" on the object we're deleting!
		if ( pVEnv && pVEnv->ShouldQuickDelete() )
		{
			m_pObject->delete_silently();
		}
		else
		{
			m_pObject->delete_and_check_vicinity();
		}
		delete pSurman;
	}
}
int CPhysicsObject::GetShadowPosition( Vector *position, QAngle *angles )
{
	IVP_U_Matrix matrix;
	
	IVP_Environment *pEnv = m_pObject->get_environment();
	CPhysicsEnvironment *pVEnv = (CPhysicsEnvironment *)pEnv->client_data;

	double psi = pEnv->get_next_PSI_time().get_seconds();
	m_pObject->calc_at_matrix( psi, &matrix );
	if ( angles )
	{
		ConvertRotationToHL( matrix, *angles );
	}
	if ( position )
	{
		ConvertPositionToHL( matrix.vv, *position );
	}

	return pVEnv->GetSimulatedPSIs();
}
void CPhysicsObject::BecomeTrigger()
{
	if ( IsTrigger() )
		return;

	EnableDrag( false );
	EnableGravity( false );

	// UNDONE: Use defaults here?  Do we want object sets by default?
	IVP_Template_Phantom trigger;
    trigger.manage_intruding_cores = IVP_TRUE; // manage a list of intruded objects
	trigger.dont_check_for_unmoveables = IVP_TRUE;
    trigger.exit_policy_extra_radius = 0.1f; // relatively strict exit check [m]

	m_pObject->convert_to_phantom( &trigger );

	// hook up events
	IVP_Environment *pEnv = m_pObject->get_environment();
	CPhysicsEnvironment *pVEnv = (CPhysicsEnvironment *)pEnv->client_data;
	pVEnv->PhantomAdd( this );
}
CPhysicsFrictionSnapshot::CPhysicsFrictionSnapshot(CPhysicsObject *pObject) {
	m_pObject = pObject;
	m_iCurContactPoint = 0;
	m_iCurManifold = 0;

	CPhysicsEnvironment *pEnv = pObject->GetVPhysicsEnvironment();
	btRigidBody *pBody = pObject->GetObject();
	int numManifolds = pEnv->GetBulletEnvironment()->getDispatcher()->getNumManifolds();
	for (int i = 0; i < numManifolds; i++) {
		btPersistentManifold *pManifold = pEnv->GetBulletEnvironment()->getDispatcher()->getManifoldByIndexInternal(i);
		const btCollisionObject *pObjA = pManifold->getBody0();
		const btCollisionObject *pObjB = pManifold->getBody1();

		if (pManifold->getNumContacts() <= 0)
			continue;

		if (pObjA == pBody || pObjB == pBody) {
			m_manifolds.AddToTail(pManifold);
		}
	}
}
    virtual void event_PSI( IVP_Event_PSI *pEvent )
	{
		CPhysicsEnvironment *pVEnv = (CPhysicsEnvironment *)pEvent->environment->client_data;
		pVEnv->EventPSI();
	}