Home | History | Annotate | Download | only in Character
      1 /*
      2 Bullet Continuous Collision Detection and Physics Library
      3 Copyright (c) 2003-2008 Erwin Coumans  http://bulletphysics.com
      4 
      5 This software is provided 'as-is', without any express or implied warranty.
      6 In no event will the authors be held liable for any damages arising from the use of this software.
      7 Permission is granted to anyone to use this software for any purpose,
      8 including commercial applications, and to alter it and redistribute it freely,
      9 subject to the following restrictions:
     10 
     11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
     12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
     13 3. This notice may not be removed or altered from any source distribution.
     14 */
     15 
     16 
     17 #include <stdio.h>
     18 #include "LinearMath/btIDebugDraw.h"
     19 #include "BulletCollision/CollisionDispatch/btGhostObject.h"
     20 #include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
     21 #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
     22 #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
     23 #include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
     24 #include "LinearMath/btDefaultMotionState.h"
     25 #include "btKinematicCharacterController.h"
     26 
     27 
     28 // static helper method
     29 static btVector3
     30 getNormalizedVector(const btVector3& v)
     31 {
     32 	btVector3 n(0, 0, 0);
     33 
     34 	if (v.length() > SIMD_EPSILON) {
     35 		n = v.normalized();
     36 	}
     37 	return n;
     38 }
     39 
     40 
     41 ///@todo Interact with dynamic objects,
     42 ///Ride kinematicly animated platforms properly
     43 ///More realistic (or maybe just a config option) falling
     44 /// -> Should integrate falling velocity manually and use that in stepDown()
     45 ///Support jumping
     46 ///Support ducking
     47 class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
     48 {
     49 public:
     50 	btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
     51 	{
     52 		m_me = me;
     53 	}
     54 
     55 	virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
     56 	{
     57 		if (rayResult.m_collisionObject == m_me)
     58 			return 1.0;
     59 
     60 		return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
     61 	}
     62 protected:
     63 	btCollisionObject* m_me;
     64 };
     65 
     66 class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
     67 {
     68 public:
     69 	btKinematicClosestNotMeConvexResultCallback (btCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
     70 	: btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
     71 	, m_me(me)
     72 	, m_up(up)
     73 	, m_minSlopeDot(minSlopeDot)
     74 	{
     75 	}
     76 
     77 	virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
     78 	{
     79 		if (convexResult.m_hitCollisionObject == m_me)
     80 			return btScalar(1.0);
     81 
     82 		if (!convexResult.m_hitCollisionObject->hasContactResponse())
     83 			return btScalar(1.0);
     84 
     85 		btVector3 hitNormalWorld;
     86 		if (normalInWorldSpace)
     87 		{
     88 			hitNormalWorld = convexResult.m_hitNormalLocal;
     89 		} else
     90 		{
     91 			///need to transform normal into worldspace
     92 			hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
     93 		}
     94 
     95 		btScalar dotUp = m_up.dot(hitNormalWorld);
     96 		if (dotUp < m_minSlopeDot) {
     97 			return btScalar(1.0);
     98 		}
     99 
    100 		return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace);
    101 	}
    102 protected:
    103 	btCollisionObject* m_me;
    104 	const btVector3 m_up;
    105 	btScalar m_minSlopeDot;
    106 };
    107 
    108 /*
    109  * Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal'
    110  *
    111  * from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html
    112  */
    113 btVector3 btKinematicCharacterController::computeReflectionDirection (const btVector3& direction, const btVector3& normal)
    114 {
    115 	return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
    116 }
    117 
    118 /*
    119  * Returns the portion of 'direction' that is parallel to 'normal'
    120  */
    121 btVector3 btKinematicCharacterController::parallelComponent (const btVector3& direction, const btVector3& normal)
    122 {
    123 	btScalar magnitude = direction.dot(normal);
    124 	return normal * magnitude;
    125 }
    126 
    127 /*
    128  * Returns the portion of 'direction' that is perpindicular to 'normal'
    129  */
    130 btVector3 btKinematicCharacterController::perpindicularComponent (const btVector3& direction, const btVector3& normal)
    131 {
    132 	return direction - parallelComponent(direction, normal);
    133 }
    134 
    135 btKinematicCharacterController::btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis)
    136 {
    137 	m_upAxis = upAxis;
    138 	m_addedMargin = 0.02;
    139 	m_walkDirection.setValue(0,0,0);
    140 	m_useGhostObjectSweepTest = true;
    141 	m_ghostObject = ghostObject;
    142 	m_stepHeight = stepHeight;
    143 	m_turnAngle = btScalar(0.0);
    144 	m_convexShape=convexShape;
    145 	m_useWalkDirection = true;	// use walk direction by default, legacy behavior
    146 	m_velocityTimeInterval = 0.0;
    147 	m_verticalVelocity = 0.0;
    148 	m_verticalOffset = 0.0;
    149 	m_gravity = 9.8 * 3 ; // 3G acceleration.
    150 	m_fallSpeed = 55.0; // Terminal velocity of a sky diver in m/s.
    151 	m_jumpSpeed = 10.0; // ?
    152 	m_wasOnGround = false;
    153 	m_wasJumping = false;
    154 	m_interpolateUp = true;
    155 	setMaxSlope(btRadians(45.0));
    156 	m_currentStepOffset = 0;
    157 	full_drop = false;
    158 	bounce_fix = false;
    159 }
    160 
    161 btKinematicCharacterController::~btKinematicCharacterController ()
    162 {
    163 }
    164 
    165 btPairCachingGhostObject* btKinematicCharacterController::getGhostObject()
    166 {
    167 	return m_ghostObject;
    168 }
    169 
    170 bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld* collisionWorld)
    171 {
    172 	// Here we must refresh the overlapping paircache as the penetrating movement itself or the
    173 	// previous recovery iteration might have used setWorldTransform and pushed us into an object
    174 	// that is not in the previous cache contents from the last timestep, as will happen if we
    175 	// are pushed into a new AABB overlap. Unhandled this means the next convex sweep gets stuck.
    176 	//
    177 	// Do this by calling the broadphase's setAabb with the moved AABB, this will update the broadphase
    178 	// paircache and the ghostobject's internal paircache at the same time.    /BW
    179 
    180 	btVector3 minAabb, maxAabb;
    181 	m_convexShape->getAabb(m_ghostObject->getWorldTransform(), minAabb,maxAabb);
    182 	collisionWorld->getBroadphase()->setAabb(m_ghostObject->getBroadphaseHandle(),
    183 						 minAabb,
    184 						 maxAabb,
    185 						 collisionWorld->getDispatcher());
    186 
    187 	bool penetration = false;
    188 
    189 	collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher());
    190 
    191 	m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
    192 
    193 	btScalar maxPen = btScalar(0.0);
    194 	for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++)
    195 	{
    196 		m_manifoldArray.resize(0);
    197 
    198 		btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
    199 
    200 		btCollisionObject* obj0 = static_cast<btCollisionObject*>(collisionPair->m_pProxy0->m_clientObject);
    201                 btCollisionObject* obj1 = static_cast<btCollisionObject*>(collisionPair->m_pProxy1->m_clientObject);
    202 
    203 		if ((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse()))
    204 			continue;
    205 
    206 		if (collisionPair->m_algorithm)
    207 			collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray);
    208 
    209 
    210 		for (int j=0;j<m_manifoldArray.size();j++)
    211 		{
    212 			btPersistentManifold* manifold = m_manifoldArray[j];
    213 			btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0);
    214 			for (int p=0;p<manifold->getNumContacts();p++)
    215 			{
    216 				const btManifoldPoint&pt = manifold->getContactPoint(p);
    217 
    218 				btScalar dist = pt.getDistance();
    219 
    220 				if (dist < 0.0)
    221 				{
    222 					if (dist < maxPen)
    223 					{
    224 						maxPen = dist;
    225 						m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??
    226 
    227 					}
    228 					m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2);
    229 					penetration = true;
    230 				} else {
    231 					//printf("touching %f\n", dist);
    232 				}
    233 			}
    234 
    235 			//manifold->clearManifold();
    236 		}
    237 	}
    238 	btTransform newTrans = m_ghostObject->getWorldTransform();
    239 	newTrans.setOrigin(m_currentPosition);
    240 	m_ghostObject->setWorldTransform(newTrans);
    241 //	printf("m_touchingNormal = %f,%f,%f\n",m_touchingNormal[0],m_touchingNormal[1],m_touchingNormal[2]);
    242 	return penetration;
    243 }
    244 
    245 void btKinematicCharacterController::stepUp ( btCollisionWorld* world)
    246 {
    247 	// phase 1: up
    248 	btTransform start, end;
    249 	m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_stepHeight + (m_verticalOffset > 0.f?m_verticalOffset:0.f));
    250 
    251 	start.setIdentity ();
    252 	end.setIdentity ();
    253 
    254 	/* FIXME: Handle penetration properly */
    255 	start.setOrigin (m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_convexShape->getMargin() + m_addedMargin));
    256 	end.setOrigin (m_targetPosition);
    257 
    258 	btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, -getUpAxisDirections()[m_upAxis], btScalar(0.7071));
    259 	callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
    260 	callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
    261 
    262 	if (m_useGhostObjectSweepTest)
    263 	{
    264 		m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration);
    265 	}
    266 	else
    267 	{
    268 		world->convexSweepTest (m_convexShape, start, end, callback);
    269 	}
    270 
    271 	if (callback.hasHit())
    272 	{
    273 		// Only modify the position if the hit was a slope and not a wall or ceiling.
    274 		if(callback.m_hitNormalWorld.dot(getUpAxisDirections()[m_upAxis]) > 0.0)
    275 		{
    276 			// we moved up only a fraction of the step height
    277 			m_currentStepOffset = m_stepHeight * callback.m_closestHitFraction;
    278 			if (m_interpolateUp == true)
    279 				m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
    280 			else
    281 				m_currentPosition = m_targetPosition;
    282 		}
    283 		m_verticalVelocity = 0.0;
    284 		m_verticalOffset = 0.0;
    285 	} else {
    286 		m_currentStepOffset = m_stepHeight;
    287 		m_currentPosition = m_targetPosition;
    288 	}
    289 }
    290 
    291 void btKinematicCharacterController::updateTargetPositionBasedOnCollision (const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag)
    292 {
    293 	btVector3 movementDirection = m_targetPosition - m_currentPosition;
    294 	btScalar movementLength = movementDirection.length();
    295 	if (movementLength>SIMD_EPSILON)
    296 	{
    297 		movementDirection.normalize();
    298 
    299 		btVector3 reflectDir = computeReflectionDirection (movementDirection, hitNormal);
    300 		reflectDir.normalize();
    301 
    302 		btVector3 parallelDir, perpindicularDir;
    303 
    304 		parallelDir = parallelComponent (reflectDir, hitNormal);
    305 		perpindicularDir = perpindicularComponent (reflectDir, hitNormal);
    306 
    307 		m_targetPosition = m_currentPosition;
    308 		if (0)//tangentMag != 0.0)
    309 		{
    310 			btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength);
    311 //			printf("parComponent=%f,%f,%f\n",parComponent[0],parComponent[1],parComponent[2]);
    312 			m_targetPosition +=  parComponent;
    313 		}
    314 
    315 		if (normalMag != 0.0)
    316 		{
    317 			btVector3 perpComponent = perpindicularDir * btScalar (normalMag*movementLength);
    318 //			printf("perpComponent=%f,%f,%f\n",perpComponent[0],perpComponent[1],perpComponent[2]);
    319 			m_targetPosition += perpComponent;
    320 		}
    321 	} else
    322 	{
    323 //		printf("movementLength don't normalize a zero vector\n");
    324 	}
    325 }
    326 
    327 void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* collisionWorld, const btVector3& walkMove)
    328 {
    329 	// printf("m_normalizedDirection=%f,%f,%f\n",
    330 	// 	m_normalizedDirection[0],m_normalizedDirection[1],m_normalizedDirection[2]);
    331 	// phase 2: forward and strafe
    332 	btTransform start, end;
    333 	m_targetPosition = m_currentPosition + walkMove;
    334 
    335 	start.setIdentity ();
    336 	end.setIdentity ();
    337 
    338 	btScalar fraction = 1.0;
    339 	btScalar distance2 = (m_currentPosition-m_targetPosition).length2();
    340 //	printf("distance2=%f\n",distance2);
    341 
    342 	if (m_touchingContact)
    343 	{
    344 		if (m_normalizedDirection.dot(m_touchingNormal) > btScalar(0.0))
    345 		{
    346 			//interferes with step movement
    347 			//updateTargetPositionBasedOnCollision (m_touchingNormal);
    348 		}
    349 	}
    350 
    351 	int maxIter = 10;
    352 
    353 	while (fraction > btScalar(0.01) && maxIter-- > 0)
    354 	{
    355 		start.setOrigin (m_currentPosition);
    356 		end.setOrigin (m_targetPosition);
    357 		btVector3 sweepDirNegative(m_currentPosition - m_targetPosition);
    358 
    359 		btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, sweepDirNegative, btScalar(0.0));
    360 		callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
    361 		callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
    362 
    363 
    364 		btScalar margin = m_convexShape->getMargin();
    365 		m_convexShape->setMargin(margin + m_addedMargin);
    366 
    367 
    368 		if (m_useGhostObjectSweepTest)
    369 		{
    370 			m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
    371 		} else
    372 		{
    373 			collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
    374 		}
    375 
    376 		m_convexShape->setMargin(margin);
    377 
    378 
    379 		fraction -= callback.m_closestHitFraction;
    380 
    381 		if (callback.hasHit())
    382 		{
    383 			// we moved only a fraction
    384 			//btScalar hitDistance;
    385 			//hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
    386 
    387 //			m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
    388 
    389 			updateTargetPositionBasedOnCollision (callback.m_hitNormalWorld);
    390 			btVector3 currentDir = m_targetPosition - m_currentPosition;
    391 			distance2 = currentDir.length2();
    392 			if (distance2 > SIMD_EPSILON)
    393 			{
    394 				currentDir.normalize();
    395 				/* See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */
    396 				if (currentDir.dot(m_normalizedDirection) <= btScalar(0.0))
    397 				{
    398 					break;
    399 				}
    400 			} else
    401 			{
    402 //				printf("currentDir: don't normalize a zero vector\n");
    403 				break;
    404 			}
    405 
    406 		} else {
    407 			// we moved whole way
    408 			m_currentPosition = m_targetPosition;
    409 		}
    410 
    411 	//	if (callback.m_closestHitFraction == 0.f)
    412 	//		break;
    413 
    414 	}
    415 }
    416 
    417 void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld, btScalar dt)
    418 {
    419 	btTransform start, end, end_double;
    420 	bool runonce = false;
    421 
    422 	// phase 3: down
    423 	/*btScalar additionalDownStep = (m_wasOnGround && !onGround()) ? m_stepHeight : 0.0;
    424 	btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + additionalDownStep);
    425 	btScalar downVelocity = (additionalDownStep == 0.0 && m_verticalVelocity<0.0?-m_verticalVelocity:0.0) * dt;
    426 	btVector3 gravity_drop = getUpAxisDirections()[m_upAxis] * downVelocity;
    427 	m_targetPosition -= (step_drop + gravity_drop);*/
    428 
    429 	btVector3 orig_position = m_targetPosition;
    430 
    431 	btScalar downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
    432 
    433 	if(downVelocity > 0.0 && downVelocity > m_fallSpeed
    434 		&& (m_wasOnGround || !m_wasJumping))
    435 		downVelocity = m_fallSpeed;
    436 
    437 	btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity);
    438 	m_targetPosition -= step_drop;
    439 
    440 	btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine);
    441         callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
    442         callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
    443 
    444         btKinematicClosestNotMeConvexResultCallback callback2 (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine);
    445         callback2.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
    446         callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
    447 
    448 	while (1)
    449 	{
    450 		start.setIdentity ();
    451 		end.setIdentity ();
    452 
    453 		end_double.setIdentity ();
    454 
    455 		start.setOrigin (m_currentPosition);
    456 		end.setOrigin (m_targetPosition);
    457 
    458 		//set double test for 2x the step drop, to check for a large drop vs small drop
    459 		end_double.setOrigin (m_targetPosition - step_drop);
    460 
    461 		if (m_useGhostObjectSweepTest)
    462 		{
    463 			m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
    464 
    465 			if (!callback.hasHit())
    466 			{
    467 				//test a double fall height, to see if the character should interpolate it's fall (full) or not (partial)
    468 				m_ghostObject->convexSweepTest (m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
    469 			}
    470 		} else
    471 		{
    472 			collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
    473 
    474 			if (!callback.hasHit())
    475 					{
    476 							//test a double fall height, to see if the character should interpolate it's fall (large) or not (small)
    477 							collisionWorld->convexSweepTest (m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
    478 					}
    479 		}
    480 
    481 		btScalar downVelocity2 = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
    482 		bool has_hit = false;
    483 		if (bounce_fix == true)
    484 			has_hit = callback.hasHit() || callback2.hasHit();
    485 		else
    486 			has_hit = callback2.hasHit();
    487 
    488 		if(downVelocity2 > 0.0 && downVelocity2 < m_stepHeight && has_hit == true && runonce == false
    489 					&& (m_wasOnGround || !m_wasJumping))
    490 		{
    491 			//redo the velocity calculation when falling a small amount, for fast stairs motion
    492 			//for larger falls, use the smoother/slower interpolated movement by not touching the target position
    493 
    494 			m_targetPosition = orig_position;
    495 					downVelocity = m_stepHeight;
    496 
    497 				btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity);
    498 			m_targetPosition -= step_drop;
    499 			runonce = true;
    500 			continue; //re-run previous tests
    501 		}
    502 		break;
    503 	}
    504 
    505 	if (callback.hasHit() || runonce == true)
    506 	{
    507 		// we dropped a fraction of the height -> hit floor
    508 
    509 		btScalar fraction = (m_currentPosition.getY() - callback.m_hitPointWorld.getY()) / 2;
    510 
    511 		//printf("hitpoint: %g - pos %g\n", callback.m_hitPointWorld.getY(), m_currentPosition.getY());
    512 
    513 		if (bounce_fix == true)
    514 		{
    515 			if (full_drop == true)
    516                                 m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
    517                         else
    518                                 //due to errors in the closestHitFraction variable when used with large polygons, calculate the hit fraction manually
    519                                 m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, fraction);
    520 		}
    521 		else
    522 			m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
    523 
    524 		full_drop = false;
    525 
    526 		m_verticalVelocity = 0.0;
    527 		m_verticalOffset = 0.0;
    528 		m_wasJumping = false;
    529 	} else {
    530 		// we dropped the full height
    531 
    532 		full_drop = true;
    533 
    534 		if (bounce_fix == true)
    535 		{
    536 			downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
    537 			if (downVelocity > m_fallSpeed && (m_wasOnGround || !m_wasJumping))
    538 			{
    539 				m_targetPosition += step_drop; //undo previous target change
    540 				downVelocity = m_fallSpeed;
    541 				step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity);
    542 				m_targetPosition -= step_drop;
    543 			}
    544 		}
    545 		//printf("full drop - %g, %g\n", m_currentPosition.getY(), m_targetPosition.getY());
    546 
    547 		m_currentPosition = m_targetPosition;
    548 	}
    549 }
    550 
    551 
    552 
    553 void btKinematicCharacterController::setWalkDirection
    554 (
    555 const btVector3& walkDirection
    556 )
    557 {
    558 	m_useWalkDirection = true;
    559 	m_walkDirection = walkDirection;
    560 	m_normalizedDirection = getNormalizedVector(m_walkDirection);
    561 }
    562 
    563 
    564 
    565 void btKinematicCharacterController::setVelocityForTimeInterval
    566 (
    567 const btVector3& velocity,
    568 btScalar timeInterval
    569 )
    570 {
    571 //	printf("setVelocity!\n");
    572 //	printf("  interval: %f\n", timeInterval);
    573 //	printf("  velocity: (%f, %f, %f)\n",
    574 //		 velocity.x(), velocity.y(), velocity.z());
    575 
    576 	m_useWalkDirection = false;
    577 	m_walkDirection = velocity;
    578 	m_normalizedDirection = getNormalizedVector(m_walkDirection);
    579 	m_velocityTimeInterval += timeInterval;
    580 }
    581 
    582 void btKinematicCharacterController::reset ( btCollisionWorld* collisionWorld )
    583 {
    584         m_verticalVelocity = 0.0;
    585         m_verticalOffset = 0.0;
    586         m_wasOnGround = false;
    587         m_wasJumping = false;
    588         m_walkDirection.setValue(0,0,0);
    589         m_velocityTimeInterval = 0.0;
    590 
    591         //clear pair cache
    592         btHashedOverlappingPairCache *cache = m_ghostObject->getOverlappingPairCache();
    593         while (cache->getOverlappingPairArray().size() > 0)
    594         {
    595                 cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, cache->getOverlappingPairArray()[0].m_pProxy1, collisionWorld->getDispatcher());
    596         }
    597 }
    598 
    599 void btKinematicCharacterController::warp (const btVector3& origin)
    600 {
    601 	btTransform xform;
    602 	xform.setIdentity();
    603 	xform.setOrigin (origin);
    604 	m_ghostObject->setWorldTransform (xform);
    605 }
    606 
    607 
    608 void btKinematicCharacterController::preStep (  btCollisionWorld* collisionWorld)
    609 {
    610 
    611 	int numPenetrationLoops = 0;
    612 	m_touchingContact = false;
    613 	while (recoverFromPenetration (collisionWorld))
    614 	{
    615 		numPenetrationLoops++;
    616 		m_touchingContact = true;
    617 		if (numPenetrationLoops > 4)
    618 		{
    619 			//printf("character could not recover from penetration = %d\n", numPenetrationLoops);
    620 			break;
    621 		}
    622 	}
    623 
    624 	m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
    625 	m_targetPosition = m_currentPosition;
    626 //	printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]);
    627 
    628 
    629 }
    630 
    631 #include <stdio.h>
    632 
    633 void btKinematicCharacterController::playerStep (  btCollisionWorld* collisionWorld, btScalar dt)
    634 {
    635 //	printf("playerStep(): ");
    636 //	printf("  dt = %f", dt);
    637 
    638 	// quick check...
    639 	if (!m_useWalkDirection && (m_velocityTimeInterval <= 0.0 || m_walkDirection.fuzzyZero())) {
    640 //		printf("\n");
    641 		return;		// no motion
    642 	}
    643 
    644 	m_wasOnGround = onGround();
    645 
    646 	// Update fall velocity.
    647 	m_verticalVelocity -= m_gravity * dt;
    648 	if(m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed)
    649 	{
    650 		m_verticalVelocity = m_jumpSpeed;
    651 	}
    652 	if(m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed))
    653 	{
    654 		m_verticalVelocity = -btFabs(m_fallSpeed);
    655 	}
    656 	m_verticalOffset = m_verticalVelocity * dt;
    657 
    658 
    659 	btTransform xform;
    660 	xform = m_ghostObject->getWorldTransform ();
    661 
    662 //	printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]);
    663 //	printf("walkSpeed=%f\n",walkSpeed);
    664 
    665 	stepUp (collisionWorld);
    666 	if (m_useWalkDirection) {
    667 		stepForwardAndStrafe (collisionWorld, m_walkDirection);
    668 	} else {
    669 		//printf("  time: %f", m_velocityTimeInterval);
    670 		// still have some time left for moving!
    671 		btScalar dtMoving =
    672 			(dt < m_velocityTimeInterval) ? dt : m_velocityTimeInterval;
    673 		m_velocityTimeInterval -= dt;
    674 
    675 		// how far will we move while we are moving?
    676 		btVector3 move = m_walkDirection * dtMoving;
    677 
    678 		//printf("  dtMoving: %f", dtMoving);
    679 
    680 		// okay, step
    681 		stepForwardAndStrafe(collisionWorld, move);
    682 	}
    683 	stepDown (collisionWorld, dt);
    684 
    685 	// printf("\n");
    686 
    687 	xform.setOrigin (m_currentPosition);
    688 	m_ghostObject->setWorldTransform (xform);
    689 }
    690 
    691 void btKinematicCharacterController::setFallSpeed (btScalar fallSpeed)
    692 {
    693 	m_fallSpeed = fallSpeed;
    694 }
    695 
    696 void btKinematicCharacterController::setJumpSpeed (btScalar jumpSpeed)
    697 {
    698 	m_jumpSpeed = jumpSpeed;
    699 }
    700 
    701 void btKinematicCharacterController::setMaxJumpHeight (btScalar maxJumpHeight)
    702 {
    703 	m_maxJumpHeight = maxJumpHeight;
    704 }
    705 
    706 bool btKinematicCharacterController::canJump () const
    707 {
    708 	return onGround();
    709 }
    710 
    711 void btKinematicCharacterController::jump ()
    712 {
    713 	if (!canJump())
    714 		return;
    715 
    716 	m_verticalVelocity = m_jumpSpeed;
    717 	m_wasJumping = true;
    718 
    719 #if 0
    720 	currently no jumping.
    721 	btTransform xform;
    722 	m_rigidBody->getMotionState()->getWorldTransform (xform);
    723 	btVector3 up = xform.getBasis()[1];
    724 	up.normalize ();
    725 	btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0);
    726 	m_rigidBody->applyCentralImpulse (up * magnitude);
    727 #endif
    728 }
    729 
    730 void btKinematicCharacterController::setGravity(btScalar gravity)
    731 {
    732 	m_gravity = gravity;
    733 }
    734 
    735 btScalar btKinematicCharacterController::getGravity() const
    736 {
    737 	return m_gravity;
    738 }
    739 
    740 void btKinematicCharacterController::setMaxSlope(btScalar slopeRadians)
    741 {
    742 	m_maxSlopeRadians = slopeRadians;
    743 	m_maxSlopeCosine = btCos(slopeRadians);
    744 }
    745 
    746 btScalar btKinematicCharacterController::getMaxSlope() const
    747 {
    748 	return m_maxSlopeRadians;
    749 }
    750 
    751 bool btKinematicCharacterController::onGround () const
    752 {
    753 	return m_verticalVelocity == 0.0 && m_verticalOffset == 0.0;
    754 }
    755 
    756 
    757 btVector3* btKinematicCharacterController::getUpAxisDirections()
    758 {
    759 	static btVector3 sUpAxisDirection[3] = { btVector3(1.0f, 0.0f, 0.0f), btVector3(0.0f, 1.0f, 0.0f), btVector3(0.0f, 0.0f, 1.0f) };
    760 
    761 	return sUpAxisDirection;
    762 }
    763 
    764 void btKinematicCharacterController::debugDraw(btIDebugDraw* debugDrawer)
    765 {
    766 }
    767 
    768 void btKinematicCharacterController::setUpInterpolate(bool value)
    769 {
    770 	m_interpolateUp = value;
    771 }
    772