1001 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			1001 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								Bullet Continuous Collision Detection and Physics Library
							 | 
						||
| 
								 | 
							
								Copyright (c) 2003-2008 Erwin Coumans  http://bulletphysics.com
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This software is provided 'as-is', without any express or implied warranty.
							 | 
						||
| 
								 | 
							
								In no event will the authors be held liable for any damages arising from the use of this software.
							 | 
						||
| 
								 | 
							
								Permission is granted to anyone to use this software for any purpose, 
							 | 
						||
| 
								 | 
							
								including commercial applications, and to alter it and redistribute it freely, 
							 | 
						||
| 
								 | 
							
								subject to the following restrictions:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								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.
							 | 
						||
| 
								 | 
							
								2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
							 | 
						||
| 
								 | 
							
								3. This notice may not be removed or altered from any source distribution.
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include "LinearMath/btIDebugDraw.h"
							 | 
						||
| 
								 | 
							
								#include "BulletCollision/CollisionDispatch/btGhostObject.h"
							 | 
						||
| 
								 | 
							
								#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
							 | 
						||
| 
								 | 
							
								#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
							 | 
						||
| 
								 | 
							
								#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
							 | 
						||
| 
								 | 
							
								#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
							 | 
						||
| 
								 | 
							
								#include "LinearMath/btDefaultMotionState.h"
							 | 
						||
| 
								 | 
							
								#include "btKinematicCharacterController.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// static helper method
							 | 
						||
| 
								 | 
							
								static btVector3
							 | 
						||
| 
								 | 
							
								getNormalizedVector(const btVector3& v)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									btVector3 n(0, 0, 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (v.length() > SIMD_EPSILON) {
							 | 
						||
| 
								 | 
							
										n = v.normalized();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return n;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								///@todo Interact with dynamic objects,
							 | 
						||
| 
								 | 
							
								///Ride kinematicly animated platforms properly
							 | 
						||
| 
								 | 
							
								///More realistic (or maybe just a config option) falling
							 | 
						||
| 
								 | 
							
								/// -> Should integrate falling velocity manually and use that in stepDown()
							 | 
						||
| 
								 | 
							
								///Support jumping
							 | 
						||
| 
								 | 
							
								///Support ducking
							 | 
						||
| 
								 | 
							
								class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
									btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										m_me = me;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										if (rayResult.m_collisionObject == m_me)
							 | 
						||
| 
								 | 
							
											return 1.0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								protected:
							 | 
						||
| 
								 | 
							
									btCollisionObject* m_me;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
									btKinematicClosestNotMeConvexResultCallback (btCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
							 | 
						||
| 
								 | 
							
									: btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
							 | 
						||
| 
								 | 
							
									, m_me(me)
							 | 
						||
| 
								 | 
							
									, m_up(up)
							 | 
						||
| 
								 | 
							
									, m_minSlopeDot(minSlopeDot)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										if (convexResult.m_hitCollisionObject == m_me)
							 | 
						||
| 
								 | 
							
											return btScalar(1.0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (!convexResult.m_hitCollisionObject->hasContactResponse())
							 | 
						||
| 
								 | 
							
											return btScalar(1.0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btVector3 hitNormalWorld;
							 | 
						||
| 
								 | 
							
										if (normalInWorldSpace)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											hitNormalWorld = convexResult.m_hitNormalLocal;
							 | 
						||
| 
								 | 
							
										} else
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											///need to transform normal into worldspace
							 | 
						||
| 
								 | 
							
											hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btScalar dotUp = m_up.dot(hitNormalWorld);
							 | 
						||
| 
								 | 
							
										if (dotUp < m_minSlopeDot) {
							 | 
						||
| 
								 | 
							
											return btScalar(1.0);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								protected:
							 | 
						||
| 
								 | 
							
									btCollisionObject* m_me;
							 | 
						||
| 
								 | 
							
									const btVector3 m_up;
							 | 
						||
| 
								 | 
							
									btScalar m_minSlopeDot;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal'
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								btVector3 btKinematicCharacterController::computeReflectionDirection (const btVector3& direction, const btVector3& normal)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Returns the portion of 'direction' that is parallel to 'normal'
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								btVector3 btKinematicCharacterController::parallelComponent (const btVector3& direction, const btVector3& normal)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									btScalar magnitude = direction.dot(normal);
							 | 
						||
| 
								 | 
							
									return normal * magnitude;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Returns the portion of 'direction' that is perpindicular to 'normal'
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								btVector3 btKinematicCharacterController::perpindicularComponent (const btVector3& direction, const btVector3& normal)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return direction - parallelComponent(direction, normal);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								btKinematicCharacterController::btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, const btVector3& up)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_ghostObject = ghostObject;
							 | 
						||
| 
								 | 
							
									m_up.setValue(0.0f, 0.0f, 1.0f);
							 | 
						||
| 
								 | 
							
									m_jumpAxis.setValue(0.0f, 0.0f, 1.0f);
							 | 
						||
| 
								 | 
							
									m_addedMargin = 0.02;
							 | 
						||
| 
								 | 
							
									m_walkDirection.setValue(0.0,0.0,0.0);
							 | 
						||
| 
								 | 
							
									m_AngVel.setValue(0.0, 0.0, 0.0);
							 | 
						||
| 
								 | 
							
									m_useGhostObjectSweepTest = true;	
							 | 
						||
| 
								 | 
							
									m_turnAngle = btScalar(0.0);
							 | 
						||
| 
								 | 
							
									m_convexShape=convexShape;	
							 | 
						||
| 
								 | 
							
									m_useWalkDirection = true;	// use walk direction by default, legacy behavior
							 | 
						||
| 
								 | 
							
									m_velocityTimeInterval = 0.0;
							 | 
						||
| 
								 | 
							
									m_verticalVelocity = 0.0;
							 | 
						||
| 
								 | 
							
									m_verticalOffset = 0.0;
							 | 
						||
| 
								 | 
							
									m_gravity = 9.8 * 3.0 ; // 3G acceleration.
							 | 
						||
| 
								 | 
							
									m_fallSpeed = 55.0; // Terminal velocity of a sky diver in m/s.
							 | 
						||
| 
								 | 
							
									m_jumpSpeed = 10.0; // ?
							 | 
						||
| 
								 | 
							
									m_SetjumpSpeed = m_jumpSpeed;
							 | 
						||
| 
								 | 
							
									m_wasOnGround = false;
							 | 
						||
| 
								 | 
							
									m_wasJumping = false;
							 | 
						||
| 
								 | 
							
									m_interpolateUp = true;
							 | 
						||
| 
								 | 
							
									m_currentStepOffset = 0.0;
							 | 
						||
| 
								 | 
							
									m_maxPenetrationDepth = 0.2;
							 | 
						||
| 
								 | 
							
									full_drop = false;
							 | 
						||
| 
								 | 
							
									bounce_fix = false;
							 | 
						||
| 
								 | 
							
									m_linearDamping = btScalar(0.0);
							 | 
						||
| 
								 | 
							
									m_angularDamping = btScalar(0.0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									setUp(up);
							 | 
						||
| 
								 | 
							
									setStepHeight(stepHeight);
							 | 
						||
| 
								 | 
							
									setMaxSlope(btRadians(45.0));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								btKinematicCharacterController::~btKinematicCharacterController ()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								btPairCachingGhostObject* btKinematicCharacterController::getGhostObject()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return m_ghostObject;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld* collisionWorld)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									// Here we must refresh the overlapping paircache as the penetrating movement itself or the
							 | 
						||
| 
								 | 
							
									// previous recovery iteration might have used setWorldTransform and pushed us into an object
							 | 
						||
| 
								 | 
							
									// that is not in the previous cache contents from the last timestep, as will happen if we
							 | 
						||
| 
								 | 
							
									// are pushed into a new AABB overlap. Unhandled this means the next convex sweep gets stuck.
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									// Do this by calling the broadphase's setAabb with the moved AABB, this will update the broadphase
							 | 
						||
| 
								 | 
							
									// paircache and the ghostobject's internal paircache at the same time.    /BW
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									btVector3 minAabb, maxAabb;
							 | 
						||
| 
								 | 
							
									m_convexShape->getAabb(m_ghostObject->getWorldTransform(), minAabb,maxAabb);
							 | 
						||
| 
								 | 
							
									collisionWorld->getBroadphase()->setAabb(m_ghostObject->getBroadphaseHandle(), 
							 | 
						||
| 
								 | 
							
														 minAabb, 
							 | 
						||
| 
								 | 
							
														 maxAabb, 
							 | 
						||
| 
								 | 
							
														 collisionWorld->getDispatcher());
							 | 
						||
| 
								 | 
							
														 
							 | 
						||
| 
								 | 
							
									bool penetration = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
								//	btScalar maxPen = btScalar(0.0);
							 | 
						||
| 
								 | 
							
									for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										m_manifoldArray.resize(0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btCollisionObject* obj0 = static_cast<btCollisionObject*>(collisionPair->m_pProxy0->m_clientObject);
							 | 
						||
| 
								 | 
							
								        btCollisionObject* obj1 = static_cast<btCollisionObject*>(collisionPair->m_pProxy1->m_clientObject);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse()))
							 | 
						||
| 
								 | 
							
											continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (!needsCollision(obj0, obj1))
							 | 
						||
| 
								 | 
							
											continue;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (collisionPair->m_algorithm)
							 | 
						||
| 
								 | 
							
											collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										for (int j=0;j<m_manifoldArray.size();j++)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											btPersistentManifold* manifold = m_manifoldArray[j];
							 | 
						||
| 
								 | 
							
											btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0);
							 | 
						||
| 
								 | 
							
											for (int p=0;p<manifold->getNumContacts();p++)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												const btManifoldPoint&pt = manifold->getContactPoint(p);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												btScalar dist = pt.getDistance();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (dist < -m_maxPenetrationDepth)
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													// TODO: cause problems on slopes, not sure if it is needed
							 | 
						||
| 
								 | 
							
													//if (dist < maxPen)
							 | 
						||
| 
								 | 
							
													//{
							 | 
						||
| 
								 | 
							
													//	maxPen = dist;
							 | 
						||
| 
								 | 
							
													//	m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													//}
							 | 
						||
| 
								 | 
							
													m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2);
							 | 
						||
| 
								 | 
							
													penetration = true;
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
													//printf("touching %f\n", dist);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											//manifold->clearManifold();
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									btTransform newTrans = m_ghostObject->getWorldTransform();
							 | 
						||
| 
								 | 
							
									newTrans.setOrigin(m_currentPosition);
							 | 
						||
| 
								 | 
							
									m_ghostObject->setWorldTransform(newTrans);
							 | 
						||
| 
								 | 
							
								//	printf("m_touchingNormal = %f,%f,%f\n",m_touchingNormal[0],m_touchingNormal[1],m_touchingNormal[2]);
							 | 
						||
| 
								 | 
							
									return penetration;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::stepUp ( btCollisionWorld* world)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									btScalar stepHeight = 0.0f;
							 | 
						||
| 
								 | 
							
									if (m_verticalVelocity < 0.0)
							 | 
						||
| 
								 | 
							
										stepHeight = m_stepHeight;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// phase 1: up
							 | 
						||
| 
								 | 
							
									btTransform start, end;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									start.setIdentity ();
							 | 
						||
| 
								 | 
							
									end.setIdentity ();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* FIXME: Handle penetration properly */
							 | 
						||
| 
								 | 
							
									start.setOrigin(m_currentPosition);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									m_targetPosition = m_currentPosition + m_up * (stepHeight) + m_jumpAxis * ((m_verticalOffset > 0.f ? m_verticalOffset : 0.f));
							 | 
						||
| 
								 | 
							
									m_currentPosition = m_targetPosition;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									end.setOrigin (m_targetPosition);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									start.setRotation(m_currentOrientation);
							 | 
						||
| 
								 | 
							
									end.setRotation(m_targetOrientation);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, -m_up, m_maxSlopeCosine);
							 | 
						||
| 
								 | 
							
									callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
							 | 
						||
| 
								 | 
							
									callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									if (m_useGhostObjectSweepTest)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										world->convexSweepTest(m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (callback.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject))
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										// Only modify the position if the hit was a slope and not a wall or ceiling.
							 | 
						||
| 
								 | 
							
										if (callback.m_hitNormalWorld.dot(m_up) > 0.0)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											// we moved up only a fraction of the step height
							 | 
						||
| 
								 | 
							
											m_currentStepOffset = stepHeight * callback.m_closestHitFraction;
							 | 
						||
| 
								 | 
							
											if (m_interpolateUp == true)
							 | 
						||
| 
								 | 
							
												m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
												m_currentPosition = m_targetPosition;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btTransform& xform = m_ghostObject->getWorldTransform();
							 | 
						||
| 
								 | 
							
										xform.setOrigin(m_currentPosition);
							 | 
						||
| 
								 | 
							
										m_ghostObject->setWorldTransform(xform);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// fix penetration if we hit a ceiling for example
							 | 
						||
| 
								 | 
							
										int numPenetrationLoops = 0;
							 | 
						||
| 
								 | 
							
										m_touchingContact = false;
							 | 
						||
| 
								 | 
							
										while (recoverFromPenetration(world))
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											numPenetrationLoops++;
							 | 
						||
| 
								 | 
							
											m_touchingContact = true;
							 | 
						||
| 
								 | 
							
											if (numPenetrationLoops > 4)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												//printf("character could not recover from penetration = %d\n", numPenetrationLoops);
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										m_targetPosition = m_ghostObject->getWorldTransform().getOrigin();
							 | 
						||
| 
								 | 
							
										m_currentPosition = m_targetPosition;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (m_verticalOffset > 0)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_verticalOffset = 0.0;
							 | 
						||
| 
								 | 
							
											m_verticalVelocity = 0.0;
							 | 
						||
| 
								 | 
							
											m_currentStepOffset = m_stepHeight;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										m_currentStepOffset = stepHeight;
							 | 
						||
| 
								 | 
							
										m_currentPosition = m_targetPosition;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bool btKinematicCharacterController::needsCollision(const btCollisionObject* body0, const btCollisionObject* body1)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									bool collides = (body0->getBroadphaseHandle()->m_collisionFilterGroup & body1->getBroadphaseHandle()->m_collisionFilterMask) != 0;
							 | 
						||
| 
								 | 
							
									collides = collides && (body1->getBroadphaseHandle()->m_collisionFilterGroup & body0->getBroadphaseHandle()->m_collisionFilterMask);
							 | 
						||
| 
								 | 
							
									return collides;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::updateTargetPositionBasedOnCollision (const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									btVector3 movementDirection = m_targetPosition - m_currentPosition;
							 | 
						||
| 
								 | 
							
									btScalar movementLength = movementDirection.length();
							 | 
						||
| 
								 | 
							
									if (movementLength>SIMD_EPSILON)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										movementDirection.normalize();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btVector3 reflectDir = computeReflectionDirection (movementDirection, hitNormal);
							 | 
						||
| 
								 | 
							
										reflectDir.normalize();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btVector3 parallelDir, perpindicularDir;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										parallelDir = parallelComponent (reflectDir, hitNormal);
							 | 
						||
| 
								 | 
							
										perpindicularDir = perpindicularComponent (reflectDir, hitNormal);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_targetPosition = m_currentPosition;
							 | 
						||
| 
								 | 
							
										if (0)//tangentMag != 0.0)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength);
							 | 
						||
| 
								 | 
							
								//			printf("parComponent=%f,%f,%f\n",parComponent[0],parComponent[1],parComponent[2]);
							 | 
						||
| 
								 | 
							
											m_targetPosition +=  parComponent;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (normalMag != 0.0)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											btVector3 perpComponent = perpindicularDir * btScalar (normalMag*movementLength);
							 | 
						||
| 
								 | 
							
								//			printf("perpComponent=%f,%f,%f\n",perpComponent[0],perpComponent[1],perpComponent[2]);
							 | 
						||
| 
								 | 
							
											m_targetPosition += perpComponent;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									} else
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
								//		printf("movementLength don't normalize a zero vector\n");
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* collisionWorld, const btVector3& walkMove)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									// printf("m_normalizedDirection=%f,%f,%f\n",
							 | 
						||
| 
								 | 
							
									// 	m_normalizedDirection[0],m_normalizedDirection[1],m_normalizedDirection[2]);
							 | 
						||
| 
								 | 
							
									// phase 2: forward and strafe
							 | 
						||
| 
								 | 
							
									btTransform start, end;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									m_targetPosition = m_currentPosition + walkMove;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									start.setIdentity ();
							 | 
						||
| 
								 | 
							
									end.setIdentity ();
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									btScalar fraction = 1.0;
							 | 
						||
| 
								 | 
							
									btScalar distance2 = (m_currentPosition-m_targetPosition).length2();
							 | 
						||
| 
								 | 
							
								//	printf("distance2=%f\n",distance2);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									int maxIter = 10;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									while (fraction > btScalar(0.01) && maxIter-- > 0)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										start.setOrigin (m_currentPosition);
							 | 
						||
| 
								 | 
							
										end.setOrigin (m_targetPosition);
							 | 
						||
| 
								 | 
							
										btVector3 sweepDirNegative(m_currentPosition - m_targetPosition);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										start.setRotation(m_currentOrientation);
							 | 
						||
| 
								 | 
							
										end.setRotation(m_targetOrientation);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, sweepDirNegative, btScalar(0.0));
							 | 
						||
| 
								 | 
							
										callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
							 | 
						||
| 
								 | 
							
										callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btScalar margin = m_convexShape->getMargin();
							 | 
						||
| 
								 | 
							
										m_convexShape->setMargin(margin + m_addedMargin);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (!(start == end))
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											if (m_useGhostObjectSweepTest)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												collisionWorld->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										m_convexShape->setMargin(margin);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										fraction -= callback.m_closestHitFraction;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (callback.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject))
							 | 
						||
| 
								 | 
							
										{	
							 | 
						||
| 
								 | 
							
											// we moved only a fraction
							 | 
						||
| 
								 | 
							
											//btScalar hitDistance;
							 | 
						||
| 
								 | 
							
											//hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//			m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											updateTargetPositionBasedOnCollision (callback.m_hitNormalWorld);
							 | 
						||
| 
								 | 
							
											btVector3 currentDir = m_targetPosition - m_currentPosition;
							 | 
						||
| 
								 | 
							
											distance2 = currentDir.length2();
							 | 
						||
| 
								 | 
							
											if (distance2 > SIMD_EPSILON)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												currentDir.normalize();
							 | 
						||
| 
								 | 
							
												/* See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */
							 | 
						||
| 
								 | 
							
												if (currentDir.dot(m_normalizedDirection) <= btScalar(0.0))
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													break;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											} else
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
								//				printf("currentDir: don't normalize a zero vector\n");
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            m_currentPosition = m_targetPosition;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld, btScalar dt)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									btTransform start, end, end_double;
							 | 
						||
| 
								 | 
							
									bool runonce = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// phase 3: down
							 | 
						||
| 
								 | 
							
									/*btScalar additionalDownStep = (m_wasOnGround && !onGround()) ? m_stepHeight : 0.0;
							 | 
						||
| 
								 | 
							
									btVector3 step_drop = m_up * (m_currentStepOffset + additionalDownStep);
							 | 
						||
| 
								 | 
							
									btScalar downVelocity = (additionalDownStep == 0.0 && m_verticalVelocity<0.0?-m_verticalVelocity:0.0) * dt;
							 | 
						||
| 
								 | 
							
									btVector3 gravity_drop = m_up * downVelocity; 
							 | 
						||
| 
								 | 
							
									m_targetPosition -= (step_drop + gravity_drop);*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									btVector3 orig_position = m_targetPosition;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									btScalar downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (m_verticalVelocity > 0.0)
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if(downVelocity > 0.0 && downVelocity > m_fallSpeed
							 | 
						||
| 
								 | 
							
										&& (m_wasOnGround || !m_wasJumping))
							 | 
						||
| 
								 | 
							
										downVelocity = m_fallSpeed;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									btVector3 step_drop = m_up * (m_currentStepOffset + downVelocity);
							 | 
						||
| 
								 | 
							
									m_targetPosition -= step_drop;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, m_up, m_maxSlopeCosine);
							 | 
						||
| 
								 | 
							
								        callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
							 | 
						||
| 
								 | 
							
								        callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									btKinematicClosestNotMeConvexResultCallback callback2(m_ghostObject, m_up, m_maxSlopeCosine);
							 | 
						||
| 
								 | 
							
								        callback2.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
							 | 
						||
| 
								 | 
							
								        callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									while (1)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										start.setIdentity ();
							 | 
						||
| 
								 | 
							
										end.setIdentity ();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										end_double.setIdentity ();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										start.setOrigin (m_currentPosition);
							 | 
						||
| 
								 | 
							
										end.setOrigin (m_targetPosition);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										start.setRotation(m_currentOrientation);
							 | 
						||
| 
								 | 
							
										end.setRotation(m_targetOrientation);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										//set double test for 2x the step drop, to check for a large drop vs small drop
							 | 
						||
| 
								 | 
							
										end_double.setOrigin (m_targetPosition - step_drop);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (m_useGhostObjectSweepTest)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (!callback.hasHit() && m_ghostObject->hasContactResponse())
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												//test a double fall height, to see if the character should interpolate it's fall (full) or not (partial)
							 | 
						||
| 
								 | 
							
												m_ghostObject->convexSweepTest (m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										} else
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (!callback.hasHit() && m_ghostObject->hasContactResponse())
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												//test a double fall height, to see if the character should interpolate it's fall (large) or not (small)
							 | 
						||
| 
								 | 
							
												collisionWorld->convexSweepTest (m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
										btScalar downVelocity2 = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
							 | 
						||
| 
								 | 
							
										bool has_hit;
							 | 
						||
| 
								 | 
							
										if (bounce_fix == true)
							 | 
						||
| 
								 | 
							
											has_hit = (callback.hasHit() || callback2.hasHit()) && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject);
							 | 
						||
| 
								 | 
							
										else
							 | 
						||
| 
								 | 
							
											has_hit = callback2.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback2.m_hitCollisionObject);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btScalar stepHeight = 0.0f;
							 | 
						||
| 
								 | 
							
										if (m_verticalVelocity < 0.0)
							 | 
						||
| 
								 | 
							
											stepHeight = m_stepHeight;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (downVelocity2 > 0.0 && downVelocity2 < stepHeight && has_hit == true && runonce == false
							 | 
						||
| 
								 | 
							
													&& (m_wasOnGround || !m_wasJumping))
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											//redo the velocity calculation when falling a small amount, for fast stairs motion
							 | 
						||
| 
								 | 
							
											//for larger falls, use the smoother/slower interpolated movement by not touching the target position
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											m_targetPosition = orig_position;
							 | 
						||
| 
								 | 
							
											downVelocity = stepHeight;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											step_drop = m_up * (m_currentStepOffset + downVelocity);
							 | 
						||
| 
								 | 
							
											m_targetPosition -= step_drop;
							 | 
						||
| 
								 | 
							
											runonce = true;
							 | 
						||
| 
								 | 
							
											continue; //re-run previous tests
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										break;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if ((m_ghostObject->hasContactResponse() && (callback.hasHit() && needsCollision(m_ghostObject, callback.m_hitCollisionObject))) || runonce == true)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										// we dropped a fraction of the height -> hit floor
							 | 
						||
| 
								 | 
							
										btScalar fraction = (m_currentPosition.getY() - callback.m_hitPointWorld.getY()) / 2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										//printf("hitpoint: %g - pos %g\n", callback.m_hitPointWorld.getY(), m_currentPosition.getY());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (bounce_fix == true)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											if (full_drop == true)
							 | 
						||
| 
								 | 
							
												m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
												//due to errors in the closestHitFraction variable when used with large polygons, calculate the hit fraction manually
							 | 
						||
| 
								 | 
							
												m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, fraction);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else
							 | 
						||
| 
								 | 
							
											m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										full_drop = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_verticalVelocity = 0.0;
							 | 
						||
| 
								 | 
							
										m_verticalOffset = 0.0;
							 | 
						||
| 
								 | 
							
										m_wasJumping = false;
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										// we dropped the full height
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										full_drop = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (bounce_fix == true)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
							 | 
						||
| 
								 | 
							
											if (downVelocity > m_fallSpeed && (m_wasOnGround || !m_wasJumping))
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												m_targetPosition += step_drop; //undo previous target change
							 | 
						||
| 
								 | 
							
												downVelocity = m_fallSpeed;
							 | 
						||
| 
								 | 
							
												step_drop = m_up * (m_currentStepOffset + downVelocity);
							 | 
						||
| 
								 | 
							
												m_targetPosition -= step_drop;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										//printf("full drop - %g, %g\n", m_currentPosition.getY(), m_targetPosition.getY());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_currentPosition = m_targetPosition;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setWalkDirection
							 | 
						||
| 
								 | 
							
								(
							 | 
						||
| 
								 | 
							
								const btVector3& walkDirection
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_useWalkDirection = true;
							 | 
						||
| 
								 | 
							
									m_walkDirection = walkDirection;
							 | 
						||
| 
								 | 
							
									m_normalizedDirection = getNormalizedVector(m_walkDirection);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setVelocityForTimeInterval
							 | 
						||
| 
								 | 
							
								(
							 | 
						||
| 
								 | 
							
								const btVector3& velocity,
							 | 
						||
| 
								 | 
							
								btScalar timeInterval
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								//	printf("setVelocity!\n");
							 | 
						||
| 
								 | 
							
								//	printf("  interval: %f\n", timeInterval);
							 | 
						||
| 
								 | 
							
								//	printf("  velocity: (%f, %f, %f)\n",
							 | 
						||
| 
								 | 
							
								//		 velocity.x(), velocity.y(), velocity.z());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									m_useWalkDirection = false;
							 | 
						||
| 
								 | 
							
									m_walkDirection = velocity;
							 | 
						||
| 
								 | 
							
									m_normalizedDirection = getNormalizedVector(m_walkDirection);
							 | 
						||
| 
								 | 
							
									m_velocityTimeInterval += timeInterval;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setAngularVelocity(const btVector3& velocity)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_AngVel = velocity;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const btVector3& btKinematicCharacterController::getAngularVelocity() const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return m_AngVel;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setLinearVelocity(const btVector3& velocity)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_walkDirection = velocity;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// HACK: if we are moving in the direction of the up, treat it as a jump :(
							 | 
						||
| 
								 | 
							
									if (m_walkDirection.length2() > 0)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										btVector3 w = velocity.normalized();
							 | 
						||
| 
								 | 
							
										btScalar c = w.dot(m_up);
							 | 
						||
| 
								 | 
							
										if (c != 0)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											//there is a component in walkdirection for vertical velocity
							 | 
						||
| 
								 | 
							
											btVector3 upComponent = m_up * (btSin(SIMD_HALF_PI - btAcos(c)) * m_walkDirection.length());
							 | 
						||
| 
								 | 
							
											m_walkDirection -= upComponent;
							 | 
						||
| 
								 | 
							
											m_verticalVelocity = (c < 0.0f ? -1 : 1) * upComponent.length();
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											if (c > 0.0f)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												m_wasJumping = true;
							 | 
						||
| 
								 | 
							
												m_jumpPosition = m_ghostObject->getWorldTransform().getOrigin();
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										m_verticalVelocity = 0.0f;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								btVector3 btKinematicCharacterController::getLinearVelocity() const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return m_walkDirection + (m_verticalVelocity * m_up);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::reset ( btCollisionWorld* collisionWorld )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    m_verticalVelocity = 0.0;
							 | 
						||
| 
								 | 
							
								    m_verticalOffset = 0.0;
							 | 
						||
| 
								 | 
							
								    m_wasOnGround = false;
							 | 
						||
| 
								 | 
							
								    m_wasJumping = false;
							 | 
						||
| 
								 | 
							
								    m_walkDirection.setValue(0,0,0);
							 | 
						||
| 
								 | 
							
								    m_velocityTimeInterval = 0.0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //clear pair cache
							 | 
						||
| 
								 | 
							
								    btHashedOverlappingPairCache *cache = m_ghostObject->getOverlappingPairCache();
							 | 
						||
| 
								 | 
							
								    while (cache->getOverlappingPairArray().size() > 0)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								            cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, cache->getOverlappingPairArray()[0].m_pProxy1, collisionWorld->getDispatcher());
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::warp (const btVector3& origin)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									btTransform xform;
							 | 
						||
| 
								 | 
							
									xform.setIdentity();
							 | 
						||
| 
								 | 
							
									xform.setOrigin (origin);
							 | 
						||
| 
								 | 
							
									m_ghostObject->setWorldTransform (xform);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::preStep (  btCollisionWorld* collisionWorld)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
							 | 
						||
| 
								 | 
							
									m_targetPosition = m_currentPosition;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									m_currentOrientation = m_ghostObject->getWorldTransform().getRotation();
							 | 
						||
| 
								 | 
							
									m_targetOrientation = m_currentOrientation;
							 | 
						||
| 
								 | 
							
								//	printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::playerStep (  btCollisionWorld* collisionWorld, btScalar dt)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								//	printf("playerStep(): ");
							 | 
						||
| 
								 | 
							
								//	printf("  dt = %f", dt);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (m_AngVel.length2() > 0.0f)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										m_AngVel *= btPow(btScalar(1) - m_angularDamping, dt);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// integrate for angular velocity
							 | 
						||
| 
								 | 
							
									if (m_AngVel.length2() > 0.0f)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										btTransform xform;
							 | 
						||
| 
								 | 
							
										xform = m_ghostObject->getWorldTransform();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btQuaternion rot(m_AngVel.normalized(), m_AngVel.length() * dt);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										btQuaternion orn = rot * xform.getRotation();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										xform.setRotation(orn);
							 | 
						||
| 
								 | 
							
										m_ghostObject->setWorldTransform(xform);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
							 | 
						||
| 
								 | 
							
										m_targetPosition = m_currentPosition;
							 | 
						||
| 
								 | 
							
										m_currentOrientation = m_ghostObject->getWorldTransform().getRotation();
							 | 
						||
| 
								 | 
							
										m_targetOrientation = m_currentOrientation;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// quick check...
							 | 
						||
| 
								 | 
							
									if (!m_useWalkDirection && (m_velocityTimeInterval <= 0.0)) {
							 | 
						||
| 
								 | 
							
								//		printf("\n");
							 | 
						||
| 
								 | 
							
										return;		// no motion
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									m_wasOnGround = onGround();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									//btVector3 lvel = m_walkDirection;
							 | 
						||
| 
								 | 
							
									//btScalar c = 0.0f;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									if (m_walkDirection.length2() > 0)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										// apply damping
							 | 
						||
| 
								 | 
							
										m_walkDirection *= btPow(btScalar(1) - m_linearDamping, dt);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									m_verticalVelocity *= btPow(btScalar(1) - m_linearDamping, dt);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// Update fall velocity.
							 | 
						||
| 
								 | 
							
									m_verticalVelocity -= m_gravity * dt;
							 | 
						||
| 
								 | 
							
									if (m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										m_verticalVelocity = m_jumpSpeed;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if (m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed))
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										m_verticalVelocity = -btFabs(m_fallSpeed);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									m_verticalOffset = m_verticalVelocity * dt;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									btTransform xform;
							 | 
						||
| 
								 | 
							
									xform = m_ghostObject->getWorldTransform();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//	printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]);
							 | 
						||
| 
								 | 
							
								//	printf("walkSpeed=%f\n",walkSpeed);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									stepUp(collisionWorld);
							 | 
						||
| 
								 | 
							
									//todo: Experimenting with behavior of controller when it hits a ceiling..
							 | 
						||
| 
								 | 
							
									//bool hitUp = stepUp (collisionWorld);	
							 | 
						||
| 
								 | 
							
									//if (hitUp)
							 | 
						||
| 
								 | 
							
									//{
							 | 
						||
| 
								 | 
							
									//	m_verticalVelocity -= m_gravity * dt;
							 | 
						||
| 
								 | 
							
									//	if (m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed)
							 | 
						||
| 
								 | 
							
									//	{
							 | 
						||
| 
								 | 
							
									//		m_verticalVelocity = m_jumpSpeed;
							 | 
						||
| 
								 | 
							
									//	}
							 | 
						||
| 
								 | 
							
									//	if (m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed))
							 | 
						||
| 
								 | 
							
									//	{
							 | 
						||
| 
								 | 
							
									//		m_verticalVelocity = -btFabs(m_fallSpeed);
							 | 
						||
| 
								 | 
							
									//	}
							 | 
						||
| 
								 | 
							
									//	m_verticalOffset = m_verticalVelocity * dt;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									//	xform = m_ghostObject->getWorldTransform();
							 | 
						||
| 
								 | 
							
									//}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (m_useWalkDirection) {
							 | 
						||
| 
								 | 
							
										stepForwardAndStrafe (collisionWorld, m_walkDirection);
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										//printf("  time: %f", m_velocityTimeInterval);
							 | 
						||
| 
								 | 
							
										// still have some time left for moving!
							 | 
						||
| 
								 | 
							
										btScalar dtMoving =
							 | 
						||
| 
								 | 
							
											(dt < m_velocityTimeInterval) ? dt : m_velocityTimeInterval;
							 | 
						||
| 
								 | 
							
										m_velocityTimeInterval -= dt;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// how far will we move while we are moving?
							 | 
						||
| 
								 | 
							
										btVector3 move = m_walkDirection * dtMoving;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										//printf("  dtMoving: %f", dtMoving);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// okay, step
							 | 
						||
| 
								 | 
							
										stepForwardAndStrafe(collisionWorld, move);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									stepDown (collisionWorld, dt);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									//todo: Experimenting with max jump height
							 | 
						||
| 
								 | 
							
									//if (m_wasJumping)
							 | 
						||
| 
								 | 
							
									//{
							 | 
						||
| 
								 | 
							
									//	btScalar ds = m_currentPosition[m_upAxis] - m_jumpPosition[m_upAxis];
							 | 
						||
| 
								 | 
							
									//	if (ds > m_maxJumpHeight)
							 | 
						||
| 
								 | 
							
									//	{
							 | 
						||
| 
								 | 
							
									//		// substract the overshoot
							 | 
						||
| 
								 | 
							
									//		m_currentPosition[m_upAxis] -= ds - m_maxJumpHeight;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									//		// max height was reached, so potential energy is at max 
							 | 
						||
| 
								 | 
							
									//		// and kinematic energy is 0, thus velocity is 0.
							 | 
						||
| 
								 | 
							
									//		if (m_verticalVelocity > 0.0)
							 | 
						||
| 
								 | 
							
									//			m_verticalVelocity = 0.0;
							 | 
						||
| 
								 | 
							
									//	}
							 | 
						||
| 
								 | 
							
									//}
							 | 
						||
| 
								 | 
							
									// printf("\n");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									xform.setOrigin (m_currentPosition);
							 | 
						||
| 
								 | 
							
									m_ghostObject->setWorldTransform (xform);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									int numPenetrationLoops = 0;
							 | 
						||
| 
								 | 
							
									m_touchingContact = false;
							 | 
						||
| 
								 | 
							
									while (recoverFromPenetration(collisionWorld))
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										numPenetrationLoops++;
							 | 
						||
| 
								 | 
							
										m_touchingContact = true;
							 | 
						||
| 
								 | 
							
										if (numPenetrationLoops > 4)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											//printf("character could not recover from penetration = %d\n", numPenetrationLoops);
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setFallSpeed (btScalar fallSpeed)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_fallSpeed = fallSpeed;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setJumpSpeed (btScalar jumpSpeed)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_jumpSpeed = jumpSpeed;
							 | 
						||
| 
								 | 
							
									m_SetjumpSpeed = m_jumpSpeed;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setMaxJumpHeight (btScalar maxJumpHeight)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_maxJumpHeight = maxJumpHeight;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bool btKinematicCharacterController::canJump () const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return onGround();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::jump(const btVector3& v)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_jumpSpeed = v.length2() == 0 ? m_SetjumpSpeed : v.length();
							 | 
						||
| 
								 | 
							
									m_verticalVelocity = m_jumpSpeed;
							 | 
						||
| 
								 | 
							
									m_wasJumping = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									m_jumpAxis = v.length2() == 0 ? m_up : v.normalized();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									m_jumpPosition = m_ghostObject->getWorldTransform().getOrigin();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if 0
							 | 
						||
| 
								 | 
							
									currently no jumping.
							 | 
						||
| 
								 | 
							
									btTransform xform;
							 | 
						||
| 
								 | 
							
									m_rigidBody->getMotionState()->getWorldTransform (xform);
							 | 
						||
| 
								 | 
							
									btVector3 up = xform.getBasis()[1];
							 | 
						||
| 
								 | 
							
									up.normalize ();
							 | 
						||
| 
								 | 
							
									btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0);
							 | 
						||
| 
								 | 
							
									m_rigidBody->applyCentralImpulse (up * magnitude);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setGravity(const btVector3& gravity)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (gravity.length2() > 0) setUpVector(-gravity);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									m_gravity = gravity.length();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								btVector3 btKinematicCharacterController::getGravity() const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return -m_gravity * m_up;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setMaxSlope(btScalar slopeRadians)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_maxSlopeRadians = slopeRadians;
							 | 
						||
| 
								 | 
							
									m_maxSlopeCosine = btCos(slopeRadians);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								btScalar btKinematicCharacterController::getMaxSlope() const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return m_maxSlopeRadians;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setMaxPenetrationDepth(btScalar d)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_maxPenetrationDepth = d;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								btScalar btKinematicCharacterController::getMaxPenetrationDepth() const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return m_maxPenetrationDepth;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bool btKinematicCharacterController::onGround () const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return (fabs(m_verticalVelocity) < SIMD_EPSILON) && (fabs(m_verticalOffset) < SIMD_EPSILON);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setStepHeight(btScalar h) 
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_stepHeight = h;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								btVector3* btKinematicCharacterController::getUpAxisDirections()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									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) };
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									return sUpAxisDirection;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::debugDraw(btIDebugDraw* debugDrawer)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setUpInterpolate(bool value)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									m_interpolateUp = value;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setUp(const btVector3& up)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (up.length2() > 0 && m_gravity > 0.0f)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										setGravity(-m_gravity * up.normalized());
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									setUpVector(up);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void btKinematicCharacterController::setUpVector(const btVector3& up)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (m_up == up)
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									btVector3 u = m_up;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (up.length2() > 0)
							 | 
						||
| 
								 | 
							
										m_up = up.normalized();
							 | 
						||
| 
								 | 
							
									else
							 | 
						||
| 
								 | 
							
										m_up = btVector3(0.0, 0.0, 0.0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (!m_ghostObject) return;
							 | 
						||
| 
								 | 
							
									btQuaternion rot = getRotation(m_up, u);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									//set orientation with new up
							 | 
						||
| 
								 | 
							
									btTransform xform;
							 | 
						||
| 
								 | 
							
									xform = m_ghostObject->getWorldTransform();
							 | 
						||
| 
								 | 
							
									btQuaternion orn = rot.inverse() * xform.getRotation();
							 | 
						||
| 
								 | 
							
									xform.setRotation(orn);
							 | 
						||
| 
								 | 
							
									m_ghostObject->setWorldTransform(xform);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								btQuaternion btKinematicCharacterController::getRotation(btVector3& v0, btVector3& v1) const
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (v0.length2() == 0.0f || v1.length2() == 0.0f)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										btQuaternion q;
							 | 
						||
| 
								 | 
							
										return q;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return shortestArcQuatNormalize2(v0, v1);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 |