void CPhysicsObject::SetMass(float mass) {
	btVector3 btvec = m_pObject->getInvInertiaDiagLocal();

	// Invert the inverse intertia to get inertia
	btvec.setX(SAFE_DIVIDE(1.0, btvec.x()));
	btvec.setY(SAFE_DIVIDE(1.0, btvec.y()));
	btvec.setZ(SAFE_DIVIDE(1.0, btvec.z()));

	m_pObject->setMassProps(mass, btvec);
}
void CPhysicsObject::SetInertia(const Vector &inertia) {
	btVector3 btvec;
	ConvertDirectionToBull(inertia, btvec);
	btvec = btvec.absolute();

	btvec.setX(SAFE_DIVIDE(1.0f, btvec.x()));
	btvec.setY(SAFE_DIVIDE(1.0f, btvec.y()));
	btvec.setZ(SAFE_DIVIDE(1.0f, btvec.z()));

	m_pObject->setInvInertiaDiagLocal(btvec);
	m_pObject->updateInertiaTensor();
}
void CShadowController::DetachObject() {
	btRigidBody* body = btRigidBody::upcast(m_pObject->GetObject());
	btVector3 btvec = body->getInvInertiaDiagLocal();
	btvec.setX(SAFE_DIVIDE(1.0, btvec.x()));
	btvec.setY(SAFE_DIVIDE(1.0, btvec.y()));
	btvec.setZ(SAFE_DIVIDE(1.0, btvec.z()));
	body->setMassProps(m_savedMass, btvec);
	m_pObject->SetMaterialIndex(m_savedMaterialIndex);

	body->setCollisionFlags(body->getCollisionFlags() & ~btCollisionObject::CF_KINEMATIC_OBJECT);
	body->setActivationState(ACTIVE_TAG);
}
Vector CPhysicsObject::GetInertia() const {
	btVector3 btvec = m_pObject->getInvInertiaDiagLocal();

	// Invert the inverse inertia to get inertia
	btvec.setX(SAFE_DIVIDE(1.0f, btvec.x()));
	btvec.setY(SAFE_DIVIDE(1.0f, btvec.y()));
	btvec.setZ(SAFE_DIVIDE(1.0f, btvec.z()));

	Vector hlvec;
	ConvertDirectionToHL(btvec, hlvec);
	VectorAbs(hlvec, hlvec);
	return hlvec;
}
void CPhysicsObject::SetMass(float mass) {
	if (IsStatic()) return;

	m_fMass = mass;

	btVector3 inertia = m_pObject->getInvInertiaDiagLocal();

	// Inverse the inverse to get the not inverse (unless in the case that the not inverse is inverse, therefore you must inverse the universe)
	inertia.setX(SAFE_DIVIDE(1.0f, inertia.x()));
	inertia.setY(SAFE_DIVIDE(1.0f, inertia.y()));
	inertia.setZ(SAFE_DIVIDE(1.0f, inertia.z()));

	m_pObject->setMassProps(mass, inertia);
}
void CPhysicsObject::SetMaterialIndex(int materialIndex) {
	surfacedata_t *pSurface = g_SurfaceDatabase.GetSurfaceData(materialIndex);

	if (pSurface) {
		m_materialIndex = materialIndex;
		m_pObject->setFriction(pSurface->physics.friction);
		//m_pObject->setRollingFriction(pSurface->physics.friction);
		m_pObject->setRestitution(min(pSurface->physics.elasticity, 1));

		// FIXME: Figure out how to convert damping values.

		// ratio = (mass / volume) / density
		// or (actual density) / (prop density)
		m_fBuoyancyRatio = SAFE_DIVIDE(SAFE_DIVIDE(m_fMass, m_fVolume), pSurface->physics.density);
	}
}
void CShadowController::DetachObject() {
	if (!m_pObject)
		return;

	btRigidBody *body = btRigidBody::upcast(m_pObject->GetObject());
	btVector3 btvec = body->getInvInertiaDiagLocal();
	btvec.setX(SAFE_DIVIDE(1.0f, btvec.x()));
	btvec.setY(SAFE_DIVIDE(1.0f, btvec.y()));
	btvec.setZ(SAFE_DIVIDE(1.0f, btvec.z()));
	body->setMassProps(m_savedMass, btvec);
	m_pObject->SetMaterialIndex(m_savedMaterialIndex);

	body->setActivationState(ACTIVE_TAG);

	m_pObject->DetachEventListener(this);
	m_pObject = NULL;
}
void CShadowController::AttachObject() {
	btRigidBody* body = btRigidBody::upcast(m_pObject->GetObject());
	m_savedMass = SAFE_DIVIDE(1, body->getInvMass());
	m_savedMaterialIndex = m_pObject->GetMaterialIndex();

	m_pObject->SetMaterialIndex(MATERIAL_INDEX_SHADOW);

	if ( !m_allowPhysicsMovement ) {
		m_pObject->SetMass(1e6f);
		m_pObject->EnableGravity(false);
	}

	body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
	body->setActivationState(DISABLE_DEACTIVATION);
}
void CShadowController::AttachObject() {
	if (!m_pObject)
		return;

	btRigidBody *body = btRigidBody::upcast(m_pObject->GetObject());
	m_savedMass = SAFE_DIVIDE(1, body->getInvMass());
	m_savedMaterialIndex = m_pObject->GetMaterialIndex();

	m_pObject->SetMaterialIndex(MATERIAL_INDEX_SHADOW);

	if (!AllowsTranslation()) {
		m_pObject->SetMass(0);
		m_pObject->EnableGravity(false);
	}

	body->setActivationState(DISABLE_DEACTIVATION);

	m_pObject->AttachEventListener(this);
}
void CPlayerController::CalculateVelocity(float dt) {
	btRigidBody *body = m_pObject->GetObject();

	m_secondsToArrival -= dt;
	if (m_secondsToArrival < 0) m_secondsToArrival = 0;

	float psiScale = m_pEnv->GetInvPSIScale();

	btTransform transform;
	((btMassCenterMotionState *)body->getMotionState())->getGraphicTransform(transform);
	btVector3 deltaPos = m_targetPosition - transform.getOrigin();

	ComputeController(m_linVelocity, deltaPos, m_maxSpeed, SAFE_DIVIDE(psiScale, dt), m_dampFactor);

	// Apply gravity velocity for stepping.
	/*
	if (m_onground) {
		btVector3 gravVel = body->getGravity() * dt;
		m_linVelocity += gravVel;
	}
	*/
}
float CPhysicsObject::GetInvMass() const {
	return SAFE_DIVIDE(1, m_fMass);
}
float CPhysicsObject::GetMass() const {
	btScalar invmass = m_pObject->getInvMass();
	return SAFE_DIVIDE(1.0, invmass);
}
float ComputeShadowControllerBull(btRigidBody *object, shadowcontrol_params_t &params, float secondsToArrival, float dt) {
	// Fraction of the movement we need to complete by this tick
	float fraction = 1;
	if (secondsToArrival > 0) {
		fraction = dt / secondsToArrival;
		if (fraction > 1) fraction = 1;
	}

	secondsToArrival -= dt;
	if (secondsToArrival < 0) secondsToArrival = 0;

	if (fraction <= 0) return secondsToArrival;
	float scale = SAFE_DIVIDE(fraction, dt);

	btTransform transform = object->getWorldTransform();
	transform *= ((btMassCenterMotionState *)object->getMotionState())->m_centerOfMassOffset.inverse();

	//-------------------
	// Translation
	//-------------------

	btVector3 posbull = transform.getOrigin();
	btVector3 delta_position = params.targetPosition - posbull;

	// Teleportation
	// If our distance is greater than teleport distance, teleport instead.
	if (params.teleportDistance > 0) {
		btScalar qdist;
		if (!params.lastPosition.isZero()) {
			btVector3 tmpDelta = posbull - params.lastPosition;
			qdist = tmpDelta.length2();
		} else {
			qdist = delta_position.length2();
		}

		if (qdist > params.teleportDistance * params.teleportDistance) {
			transform.setOrigin(params.targetPosition);
			transform.setRotation(params.targetRotation);
			object->setWorldTransform(transform * ((btMassCenterMotionState *)object->getMotionState())->m_centerOfMassOffset);
		}
	}

	btVector3 speed = object->getLinearVelocity();
	ComputeController(speed, delta_position, btVector3(params.maxSpeed, params.maxSpeed, params.maxSpeed), scale, params.dampFactor);
	object->setLinearVelocity(speed);

	params.lastPosition = posbull + (speed * dt);

	//-------------------
	// Rotation
	//-------------------

	btVector3 axis;
	btScalar angle;
	btTransformUtil::calculateDiffAxisAngleQuaternion(transform.getRotation(), params.targetRotation, axis, angle);

	// So we don't end up having a huge delta angle (such as instead of doing 379 deg turn, do a -1 deg turn)
	if (angle > M_PI) {
		angle -= btScalar(2 * M_PI);
	}

	btVector3 deltaAngles = axis * angle;
	btVector3 rot_speed = object->getAngularVelocity();
	ComputeController(rot_speed, deltaAngles, btVector3(params.maxAngular, params.maxAngular, params.maxAngular), scale, params.dampFactor);
	object->setAngularVelocity(rot_speed);

	object->activate();

	return secondsToArrival;
}