Esempio n. 1
0
//
// Test function to make sure that the hits from the kd-tree are identical to the ones from the broadphase.
//
static hkBool compareHitArrays(const hkAabb& aabb, const hkPrimitiveId* kdHits, int numKdHits, const hkArray<hkpBroadPhaseHandlePair>& sapHits)
{
	hkLocalArray<const hkpCollidable*> sapCollidables(sapHits.getSize());

	for (int i=0; i<sapHits.getSize(); i++)
	{
		const hkpTypedBroadPhaseHandle* tp = static_cast<const hkpTypedBroadPhaseHandle*>( sapHits[i].m_b );
		const hkpCollidable* collB = static_cast<hkpCollidable*>(tp->getOwner());

		// Make sure no spurious hits from the broadphase
		hkAabb colAabb;
		hkpRigidBody* rb = hkGetRigidBody(collB);

		if (rb)
		{
			collB->getShape()->getAabb(rb->getTransform(), 0.0f, colAabb);
			hkBool aabbOverlap = colAabb.overlaps(aabb);

			if (aabbOverlap)
				sapCollidables.pushBack(collB);
		}
	}

	// Make sure that the contents of the arrays at the same
	// It would be faster to sort and do a string compare, but this is just as easy.
	
	hkBool isOk = true;
	for (int i=0; i<numKdHits; i++)
	{
		const hkpCollidable* kdCollidable = reinterpret_cast<const hkpCollidable*> (kdHits[i]);
		int idx = sapCollidables.indexOf(kdCollidable);
		
		if(idx < 0)
		{
			// There's a hit in the kd-tree's list but not the 3AxisSweep's list
			// It's possible that 3AxisSweep skipped something. So get the AABB of the body in the kd-tree list.
			hkAabb colAabb;
			hkpRigidBody* rb = hkGetRigidBody(kdCollidable);
			kdCollidable->getShape()->getAabb(rb->getTransform(), rb->getWorld()->getCollisionInput()->getTolerance(), colAabb);
			
			hkBool aabbOverlap = colAabb.overlaps(aabb);
			if (!aabbOverlap)
			{
				// Something in the list doesn't overlap with the query's aabb
				isOk = false;
			}

			continue;
		}

		sapCollidables.removeAt(idx);
	}

	// If we made it this far, they must agree.
	return isOk && sapCollidables.isEmpty();
}
Esempio n. 2
0
void BackfacesCulledRayHitCollectorDemo::showRaycastResults(const hkpWorldRayCastOutput& output, int triangleColor)
{
		// Find the leaf shape
		hkpShapeContainer::ShapeBuffer buffer;
		const hkpShape* shape = output.m_rootCollidable->getShape();
		for(int keyIndex = 0; shape != HK_NULL; ++keyIndex )
		{
			if(shape->getType() == HK_SHAPE_MOPP)
			{
				keyIndex++;
			}

			// go to the next level
			const hkpShapeContainer* container = shape->getContainer();
			if (container)
			{
				shape = container->getChildShape(output.m_shapeKeys[keyIndex], buffer);
			}
			else
			{
				break;
			}
		}

		// Draw the leaf shape's outline if it's a triangle.
		if (shape->getType() == HK_SHAPE_TRIANGLE)
		{
			const hkpTriangleShape* triangle = static_cast<const hkpTriangleShape*>( shape );
			hkArray<hkVector4> transformedVertices(3); 
			transformedVertices[0].setTransformedPos(hkGetRigidBody(output.m_rootCollidable)->getTransform(), triangle->getVertex(0));
			transformedVertices[1].setTransformedPos(hkGetRigidBody(output.m_rootCollidable)->getTransform(), triangle->getVertex(1));
			transformedVertices[2].setTransformedPos(hkGetRigidBody(output.m_rootCollidable)->getTransform(), triangle->getVertex(2));

			HK_DISPLAY_LINE(transformedVertices[0], transformedVertices[1], triangleColor);
			HK_DISPLAY_LINE(transformedVertices[2], transformedVertices[1], triangleColor);
			HK_DISPLAY_LINE(transformedVertices[0], transformedVertices[2], triangleColor);

// 			hkVector4 triangleNormal;
// 			hkpTriangleUtil::calcNormal(triangleNormal,
// 				transformedVertices[0], transformedVertices[1], transformedVertices[2]);
// 			triangleNormal.normalize3();
// 
// 			hkVector4 trianglePos;
// 			triangle->getCentre(trianglePos);
// 			trianglePos.setTransformedPos(hkGetRigidBody(output.m_rootCollidable)->getTransform(), trianglePos);
// 
// 			HK_DISPLAY_ARROW(trianglePos, triangleNormal, hkColor::ORANGE);
		}	
}
void LaunchPadListener::contactPointAddedCallback(hkpContactPointAddedEvent& event)
{
	// Grab the body to launch
	hkpRigidBody* collidedRb = hkGetRigidBody( event.m_bodyA->getRootCollidable() );

	// If m_forceMagnitude is zero then launch toward a target
	if( m_forceMagnitude == 0.0f )
	{
		collidedRb->setMaxLinearVelocity( 300.0f );

		hkVector4 impulse;
		impulse.setSub4( m_targetPosition, collidedRb->getPosition() );
		impulse.mul4( 225.0f );

		PlanetGravityDemo::applyScaledLinearImpulse( collidedRb, impulse );
	}
	// Just apply an impulse along the contact normal
	else
	{
		hkVector4 impulse( event.m_contactPoint->getNormal() );
		impulse.mul4( m_forceMagnitude * 225.0f );
		collidedRb->setMaxLinearVelocity( 300.0f );

		PlanetGravityDemo::applyScaledLinearImpulse( collidedRb, impulse );
	}

	event.m_status = HK_CONTACT_POINT_REJECT;
}
		void contactPointRemovedCallback(const hkpRootCdPoint& point)
		{
			hkpRigidBody* body = hkGetRigidBody(point.m_rootCollidableB);

			if ( body->hasProperty(HK_OBJECT_IS_LADDER) )
			{
				m_atLadder = false;
			}
		}
Esempio n. 5
0
		// hkpPhantom interface implementation
		virtual void phantomEnterEvent( const hkpCollidable* collidableA, const hkpCollidable* collidableB, const hkpCollisionInput& env )
		{
			// the color can only be changed once the entity has been added to the world
			hkpRigidBody* owner = hkGetRigidBody(collidableB);

			// the "Collidables" here are "faked" so it's necessary to get the owner first in order
			// to get the "real" collidable!
			HK_SET_OBJECT_COLOR((hkUlong)owner->getCollidable(), hkColor::rgbFromChars(255, 0, 0));
			//HK_SET_OBJECT_COLOR((int)&collidableB, hkColor::rgbFromChars(255, 0, 0));
		}
		// Ladder handling code goes here
		void contactPointAddedCallback(const hkpRootCdPoint& point)
		{
			hkpRigidBody* body = hkGetRigidBody(point.m_rootCollidableB);

			if ( body->hasProperty(HK_OBJECT_IS_LADDER) )
			{
				m_atLadder = true;
				m_ladderNorm = point.m_contact.getNormal();
				body->getPointVelocity(point.m_contact.getPosition(), m_ladderVelocity);
			}
		}
hkpRigidBody* CollisionFilterViewerUtil::getBodyUnderMousePointer(const hkDemoEnvironment* env, const hkpWorld* world)
{
	hkpWorldRayCastInput input;
	hkpWorldRayCastOutput output;
	hkVector4 intersectionPointWorld;
	castRayIntoWorldAtMousePointer(env, world, input, output);

	if(output.hasHit())
	{
		hkpRigidBody* rb = hkGetRigidBody(output.m_rootCollidable);
		return rb;
	}

	return HK_NULL;
}
void PortalPhantom::removeOverlappingCollidable( hkpCollidable* handle )
{
	hkpRigidBody* rb = hkGetRigidBody(handle);

	//if hovercraft send envent to checkpoint
	if ( (rb != HK_NULL) && HavokEntityType::isEntityType(rb,HavokEntityType::CHARACTER ) ) {
		HavokEntity * ch = reinterpret_cast<HavokEntity*>(rb->getUserData());
		Entity * e = ch->getEntity();
		if ( e->getCategory() == Hovercraft::CATEGORY ){
			mPortal->onLeave(dynamic_cast<Hovercraft*>(e));
		}
	}

	hkpAabbPhantom::removeOverlappingCollidable( handle );
}
Esempio n. 9
0
		// hkpPhantom interface implementation
		virtual void phantomLeaveEvent( const hkpCollidable* collidableA, const hkpCollidable* collidableB )
		{
			// the color can only be changed once the entity has been added to the world
			hkpRigidBody* owner = hkGetRigidBody(collidableB);

			// the "Collidables" here are "faked" so it's necessary to get the owner first in order
			// to get the "real" collidable!
			HK_SET_OBJECT_COLOR((hkUlong)owner->getCollidable(), hkColor::rgbFromChars(0, 255, 0));

			// If moving out AND falling down, apply impulse to fire it towards "wall"
			if(owner->getLinearVelocity()(1) < 0.0f)
			{
				hkVector4 impulse(-50.0f, 220.0f, 0.0f);
				owner->applyLinearImpulseAsCriticalOperation(impulse);
			}
		}
Esempio n. 10
0
void SlidingWorldDemo::removeBodiesLeavingBroadphaseFromSimulation(const hkArray<hkpBroadPhaseHandle*>& objectsEnteringBroadphaseBorder)
{
	for (int i = 0; i < objectsEnteringBroadphaseBorder.getSize(); i++)
	{
		hkpBroadPhaseHandle* handle = objectsEnteringBroadphaseBorder[i];
		hkpCollidable* collidable = static_cast<hkpCollidable*>(static_cast<hkpTypedBroadPhaseHandle*>(handle)->getOwner());

		// It might be a rigid body, or a phantom, so check both possibilities
		hkpRigidBody* rigidBody = hkGetRigidBody(collidable);
		if(rigidBody)
		{
			m_world->removeEntity( rigidBody );
		}

		hkpPhantom* phantom = hkGetPhantom(collidable);
		if(phantom)
		{
			m_world->removePhantom( phantom );
		}

	}

}
hkDemo::Result PlanetGravityDemo::stepDemo()
{
	// Update lighting
	{
		// Update the light source to be at the camera
		float position[3];
		m_cameraPosition.store3( position );
		m_flashLight->setPosition( position );

		// Update the light direction to be pointing toward the character controller rigid body
		hkVector4 directionVector;
		directionVector.setSub4( m_cameraPosition, m_characterRigidBody->getPosition() );
		directionVector.mul4( -1.0f );
		directionVector.normalize3();

		float direction[3];
		directionVector.store3( direction );
		m_flashLight->setDirection( direction );
	}

	// Detach the camera from the character when P is pressed.
	if( m_env->m_window->getKeyboard().wasKeyPressed('P') )
	{
		m_detachedCamera = !m_detachedCamera;
	}

	// Update turrets
	for( int i = 0; i < m_turrets.getSize(); i++ )
	{
		Turret& turret = m_turrets[i];
		turret.cooldown -= m_timestep;
		
		// Make the turret spin
		turret.hinge->setMotorTargetAngle( turret.hinge->getMotorTargetAngle() + ( m_timestep / 5.f ) );

		// Bail out if the turret is "hot"
		if( turret.cooldown > 0.0f )
		{
			continue;
		}

		// Generate a curved raycast and shoot the ray
		// This has to be done every time-step as it's in world-space
		{
			const hkReal radius = 14.8f;
			hkRotation rot;
			hkVector4 offset;
			hkVector4 turretDown;
			
			rot.set( turret.turretRigidBody->getRotation() );
			offset = turret.turretRigidBody->getPosition();
			turretDown.setMul4( -1.0f, rot.getColumn(2) );

			hkpLinearParametricCurve myCurve;
			// Move the ray's source a little up so it's coming from the center of the barrel
			hkTransform localTransform( hkQuaternion::getIdentity(), hkVector4( 0.0f, 0.0f, 0.7f ) );

			// Create a curve of 20 points
			for( int j = 0; j < 20; j++ )
			{
				hkReal angle = HK_REAL_PI * static_cast<hkReal>(j) / 15.0f;

				hkVector4 newPoint( radius * 2.0f * sin( angle ),
									0.0f,
									radius * 2.0f * cos( angle ) );

				newPoint.setTransformedPos( localTransform, newPoint );
				newPoint.setTransformedPos( turret.turretRigidBody->getTransform(), newPoint );
				newPoint.addMul4( radius * 2.0f, turretDown );

				myCurve.addPoint( newPoint );
			}

			// We only need the closest hit (as our lasers can't pass through objects)
			//  so hkpClosestRayHitCollector is used.
			hkpClosestRayHitCollector raycastOutput;
			hkReal t = castCurvedRay( raycastOutput, myCurve, 20 );

			// Apply a large force to the closest rb we hit, along the tangent at the colliding point
			if( raycastOutput.hasHit() )
			{
				hkpRigidBody* hitRb = hkGetRigidBody( raycastOutput.getHit().m_rootCollidable );

				if( hitRb->getMotionType() != hkpMotion::MOTION_FIXED )
				{
					hkVector4 tangent;
					myCurve.getTangent( t, tangent );
					tangent.mul4( 15000.0f );

					applyScaledLinearImpulse( hitRb, tangent );
					turret.cooldown = 3.0f;
				}
			}
		}
	}

	m_world->markForWrite();

	// Update the character context
	m_characterRigidBody->m_up = m_worldUp;
	hkReal posX = 0.0f;
	hkReal posY = 0.0f;
	if( !m_detachedCamera )
	{
		float deltaAngle;
		CharacterUtils::getUserInputForCharacter( m_env, deltaAngle, posX, posY );

		if( ( ( hkMath::fabs( posX ) < HK_REAL_MAX ) && ( hkMath::fabs( posY ) < HK_REAL_MAX ) ) && ( posX || posY ) )
		{
			// find new orientation in local space
			hkVector4 newForward( -posY, 0.0f, -posX );
			hkVector4 absoluteForward( 1.0f, 0.0f, 0.0f );
			hkReal characterAngle = hkMath::acos( absoluteForward.dot3( newForward ) );

			// Calculate cross product to get sign of rotation.
			hkVector4 crossProduct;
			crossProduct.setCross( absoluteForward, newForward );

			if( crossProduct(1) < 0.0f )
			{
				characterAngle *= -1.0f;
			}

			// Rotate the character's rigid body to face in the direction it's moving
			hkRotation newRotation;
			newRotation.setAxisAngle( m_worldUp, characterAngle );
 			m_characterForward.setRotatedDir( newRotation, m_cameraForward );
 			m_characterForward.normalize3();
		}

		// Rotate the camera's forward vector based on world up vector and mouse movement
		if( deltaAngle != 0.0f && m_characterRigidBody->getRigidBody()->getRotation().hasValidAxis() )
		{
			hkRotation newRotation;
			newRotation.setAxisAngle( m_worldUp, deltaAngle );
 			m_cameraForward.setRotatedDir( newRotation, m_cameraForward );
 			m_cameraForward.normalize3();
		}
	}

	HK_TIMER_BEGIN( "set character state", HK_NULL );
	hkpCharacterInput input;
	hkpCharacterOutput output;
	{
		input.m_atLadder = false;
		input.m_inputLR = posX;
		input.m_inputUD = posY;

		if( m_detachedCamera )
		{
			input.m_wantJump = false;
		}
		else
		{
			input.m_wantJump = m_env->m_window->getMouse().wasButtonPressed( HKG_MOUSE_LEFT_BUTTON )
							|| m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_1 );
		}

		// Check that we have a valid rotation. Probably won't for the first couple of frames.
		if( !( m_characterRigidBody->getRigidBody()->getRotation().hasValidAxis() ) )
		{
			input.m_up = hkVector4( 0.0f, 0.0f, 1.0f );
			input.m_forward = m_cameraForward;
		}
		else
		{
			input.m_up = m_worldUp;

			// Recalculate m_forward so it's perpendicular to m_worldUp
			hkVector4 newRot;
			newRot.setCross( m_cameraForward, m_worldUp );
			m_cameraForward.setCross( m_worldUp, newRot );

			// Display character's current heading
			hkRotation characterRotation;
			characterRotation.set( m_characterRigidBody->getRigidBody()->getRotation() );
			HK_DISPLAY_ARROW( m_characterRigidBody->getPosition(), characterRotation.getColumn(0), hkColor::LIMEGREEN );

			input.m_forward = m_cameraForward;
		}

		hkStepInfo stepInfo;
		stepInfo.m_deltaTime = m_timestep;
		stepInfo.m_invDeltaTime = 1.0f / m_timestep;

		input.m_stepInfo = stepInfo;
		input.m_characterGravity.setMul4( -20.0f, m_worldUp );

		input.m_velocity = m_characterRigidBody->getRigidBody()->getLinearVelocity();
		input.m_position = m_characterRigidBody->getRigidBody()->getPosition();
		{
			hkpSurfaceInfo ground;
			m_characterRigidBody->checkSupport( stepInfo, ground );

			// Avoid accidental state changes (Smooth movement on stairs)
			// During transition supported->unsupported continue to return N-frames hkpSurfaceInfo data from previous supported state
			{
				// Number of frames to skip (continue with previous hkpSurfaceInfo data)
				const int skipFramesInAir = 6;

				if( input.m_wantJump )
				{
					m_framesInAir = skipFramesInAir;
				}

				hkpSurfaceInfo* currInfo;
				if( ground.m_supportedState != hkpSurfaceInfo::SUPPORTED )
				{
					if( m_framesInAir < skipFramesInAir )
					{
						input.m_isSupported = true;
						currInfo = m_previousGround;
					}
					else
					{
						input.m_isSupported = false;
						currInfo = &ground;
					}

					m_framesInAir++;
				}
				else
				{
					input.m_isSupported = true;
					currInfo = &ground;

					m_previousGround->set( ground );

					// reset old number of frames
					if( m_framesInAir > skipFramesInAir )
					{
						m_framesInAir = 0;
					}			
				}

				input.m_surfaceNormal = currInfo->m_surfaceNormal;
				input.m_surfaceVelocity = currInfo->m_surfaceVelocity;
				input.m_surfaceMotionType = currInfo->m_surfaceMotionType;
			}
		}

		HK_TIMER_END();
	}

	// Apply the character state machine
	{
		HK_TIMER_BEGIN( "update character state", HK_NULL );

		m_characterContext->update( input, output );

		HK_TIMER_END();
	}

	//Apply the player character controller
	{
		HK_TIMER_BEGIN( "simulate character", HK_NULL );

		// Set output velocity from state machine into character rigid body
		m_characterRigidBody->setLinearVelocity( output.m_velocity, m_timestep );

		HK_TIMER_END();

		m_world->unmarkForWrite();
	}

	// Rotate the character
	{
		hkRotation newOrientation;
		newOrientation.getColumn(0) = m_characterForward;
		newOrientation.getColumn(1) = m_worldUp;
		newOrientation.getColumn(2).setCross( newOrientation.getColumn(0), newOrientation.getColumn(1) );
		newOrientation.renormalize();
		
		reorientCharacter( newOrientation );
	}

	// Step the world
	hkDefaultPhysicsDemo::stepDemo();

	// Display state
	{
		hkpCharacterStateType state = m_characterContext->getState();
		char* stateStr;

		switch( state )
		{
			case HK_CHARACTER_ON_GROUND:
			{
				stateStr = "On Ground";
				break;
			}
			case HK_CHARACTER_JUMPING:
			{
				stateStr = "Jumping";
				break;
			}
			case HK_CHARACTER_IN_AIR:
			{
				stateStr = "In Air";
				break;
			}
			default:
			{
				stateStr = "Other";
				break;
			}
		}

		char buffer[255];
		hkString::snprintf( buffer, 255, "State : %s", stateStr );
		m_env->m_textDisplay->outputText( buffer, 20.f, 270.f, 0xffffffff );
	}

	//
	// Handle crouching (only for capsule)
	//
	if( !m_detachedCamera )
	{
		m_world->markForWrite();
		hkBool wantCrouch = ( m_env->m_window->getMouse().getButtonState() & HKG_MOUSE_RIGHT_BUTTON )
						 || ( m_env->m_gamePad->getButtonState() & HKG_PAD_BUTTON_2 );

		hkBool isCrouching = ( m_characterRigidBody->getRigidBody()->getCollidable()->getShape() == m_crouchShape );


		// We want to stand
		if( isCrouching && !wantCrouch )
		{
			m_characterRigidBody->getRigidBody()->setShape( m_standShape );
		}

		// We want to crouch
		else if( !isCrouching && wantCrouch )
		{
			m_characterRigidBody->getRigidBody()->setShape( m_crouchShape );
		}

		m_world->unmarkForWrite();
	}

	// Transparent camera handling
	if( !m_detachedCamera )
	{
		m_world->markForWrite();
		handleCamera();
		m_world->unmarkForWrite();
	}

	return hkDemo::DEMO_OK;
}
void KdTreeVsBroadphaseDemo::doLinearCasts()
{
	const int numCasts = 100;

	hkObjectArray<hkpClosestCdPointCollector> worldCollectors(numCasts);
	hkObjectArray<hkpClosestCdPointCollector> treeCollectors(numCasts);
	hkArray<hkpLinearCastInput> lcInput (numCasts);

	hkArray<const hkpCollidable*> castCollidables(numCasts);

	for (int i=0; i < numCasts; i++)
	{
		//hkprintf("random seed = %d\n", m_rand.getCurrent());
		castCollidables[i] = m_collidables[ m_rand.getRand32() % m_collidables.getSize() ];

		hkVector4 start, end;
		start = hkGetRigidBody(castCollidables[i])->getPosition();

		hkVector4 worldSize(m_worldSizeX, m_worldSizeY, m_worldSizeZ);
		m_rand.getRandomVector11(end);
		end.mul4(worldSize);

		// Flatten out the rays in one component - this triggers a special case in the raycasting code
		{
			end(i%3) = start(i%3);
		}

		lcInput[i].m_to = end;
		lcInput[i].m_maxExtraPenetration = HK_REAL_EPSILON;
		lcInput[i].m_startPointTolerance = HK_REAL_EPSILON;
		worldCollectors[i].reset();
		treeCollectors[i].reset();

	}

	{
		HK_ASSERT(0x3fe8daf1, m_world->m_kdTreeManager->isUpToDate());
		HK_TIME_CODE_BLOCK("kdtreeLinearCast", HK_NULL);
		for (int i=0; i < numCasts; i++)
		{
			m_world->linearCast(castCollidables[i], lcInput[i], treeCollectors[i] );
		}

	}

	{ 
		HK_TIME_CODE_BLOCK("worldLinearCast", HK_NULL);
		//
		// Mark the world's kd-tree as dirty, forcing raycasting to go through the old (slow) hkp3AxisSweep algorithm
		// You should NOT usually be doing this.
		//
		m_world->markKdTreeDirty();
		for (int i=0; i < numCasts; i++)
		{
			m_world->linearCast(castCollidables[i], lcInput[i], worldCollectors[i] );
		}
	}
	
	
	// Check that the results agree, and draw the results
	{ 
		for (int i=0; i<numCasts; i++)
		{

  			HK_ASSERT(0x0, worldCollectors[i].hasHit() == treeCollectors[i].hasHit() );
  			
  			if (worldCollectors[i].hasHit())
  			{
  				hkReal tolerance = m_world->getCollisionInput()->m_config->m_iterativeLinearCastEarlyOutDistance;
  				
  				hkBool hitFractionsEqual = hkMath::equal(worldCollectors[i].getEarlyOutDistance(), treeCollectors[i].getEarlyOutDistance(), 2.0f*tolerance);
  				hkBool hitCollidablesEqual =  worldCollectors[i].getHit().m_rootCollidableB == treeCollectors[i].getHit().m_rootCollidableB ;
  				HK_ASSERT(0x0, hitFractionsEqual || hitCollidablesEqual );
  			}

			hkVector4 start = hkGetRigidBody(castCollidables[i])->getPosition();

			if (treeCollectors[i].hasHit())
			{
				hkVector4 hitpoint;
				hitpoint.setInterpolate4(start, lcInput[i].m_to, treeCollectors[i].getEarlyOutDistance() );

				HK_DISPLAY_STAR(hitpoint, .1f, hkColor::RED);
				HK_DISPLAY_ARROW(hitpoint, treeCollectors[i].getHit().m_contact.getNormal(),  hkColor::CYAN);
				HK_DISPLAY_LINE(start, hitpoint, hkColor::BLUE);
			}
			else
			{
				HK_DISPLAY_LINE(start, lcInput[i].m_to, hkColor::WHITE);
			}
		}
	}
}
hkBool hkDefaultPhysicsDemo::objectPicked( const hkgDisplayObject* displayObject, const hkVector4& worldPosition, int geomIndex )
{
	HK_ASSERT(0x65b2643b, m_env->m_displayHandler);
	hkgDisplayHandler* dhandler = m_env->m_displayHandler;

	if( displayObject && m_world )
	{
		hkUlong id = 0;
		void* userPtr = HK_NULL;
		if (displayObject->getStatusFlags() & HKG_DISPLAY_OBJECT_INSTANCED)
		{
			id = ((hkgInstancedDisplayObject*)displayObject)->getUserDataFromIndex( geomIndex );
		}
		else
		{
			id = dhandler->getDisplayObjectId( displayObject );
			userPtr = displayObject->getUserPointer();
		}

		// HACK!  We know the id is actually the address of the Collidable
		if ( (id > 0) || (userPtr != HK_NULL) )
		{
			hkpRigidBody* rb = HK_NULL;
			// Check if doLink->m_id is a valid address.
			if (id > 0)
			{
				if ( (id & 0x03) == 0x03) // 0x1 == swept transform from, 0x2 = swept transform to, 0x3 = convex radius (ok to pick)
				{
					id &= ~0x03;
				}

				if (id % 4 != 0 || id < 64)
				{
					return false;
				}

				hkpCollidable* col = reinterpret_cast<hkpCollidable*>( id );
				if( col->getOwner() )
				{
					rb = hkGetRigidBody(col);
				}
			}
			else
			{
				rb = reinterpret_cast<hkpRigidBody*>( userPtr ); // true in our demos that use assets
			}

			if( rb && !rb->isFixed() )
			{
				hkpWorld* mouseWorld = rb->getWorld();
				if (mouseWorld)
				{
					hkVector4 positionAinA;
					positionAinA.setTransformedInversePos( rb->getTransform(), worldPosition );

					const hkReal springDamping = 0.5f;
					const hkReal springElasticity = 0.3f;
					const hkReal objectDamping = 0.95f;

					mouseWorld->lock();
						m_mouseSpring = new hkpMouseSpringAction( positionAinA, worldPosition, springDamping, springElasticity, objectDamping, rb, &m_mouseSpringAppliedCallbacks );
						m_mouseSpring->setMaxRelativeForce(m_mouseSpringMaxRelativeForce);

 						mouseWorld->addAction( m_mouseSpring );
					mouseWorld->unlock();
				}

				return true;
			}
		}
	}
	return false;
}
Esempio n. 14
0
void AabbQueryDemo::queryAabbMT()
{
	HK_TIMER_BEGIN_LIST("queryAabbMT", "setup");

	hkAabb aabb;
	// Grab a body from the world, and compute it's AABB + some padding
	const hkpCollidable* queryCollidable;
	{
		queryCollidable = m_collidables[m_collIdx];
		hkpRigidBody* rb = hkGetRigidBody(queryCollidable);
		queryCollidable->getShape()->getAabb(rb->getTransform(), 20.0f, aabb);
	}

	hkArray<hkpKdTreeAabbCommand> commands;
	commands.setSize(numQueries);
	
	//
	// For performance timings, we query the same AABB multiple times and overwrite the results.
	// When using this, make sure to use different output arrays!
	//
	hkArray<hkPrimitiveId> output;
	output.setSize(50);

	//
	// Set up the commands for the job
	//
	for (int i=0; i<commands.getSize(); i++)
	{
		hkpKdTreeAabbCommand& command = commands[i];
		command.m_aabb = aabb;
		command.m_results = output.begin();
		command.m_resultsCapacity = output.getSize();
		command.m_numResultsOut = 0;
	}


	// 
	// Setup the job
	//
	hkArray<hkpRayCastQueryJobHeader> header(1);
	hkpKdTreeAabbJob aabbJob(header.begin(), commands.begin(), commands.getSize(), &m_semaphore);
	aabbJob.m_numTrees = 1;
	aabbJob.m_trees[0] = m_world->m_kdTreeManager->getTree();

	m_jobQueue->addJob( *reinterpret_cast<hkJobQueue::JobQueueEntry*>(&aabbJob), hkJobQueue::JOB_HIGH_PRIORITY );

	HK_TIMER_SPLIT_LIST("process");
	m_jobThreadPool->processAllJobs( m_jobQueue );
	m_jobThreadPool->waitForCompletion();
	m_semaphore.acquire();

	HK_TIMER_END_LIST();

	//
	// Run the same query on the broadphase for comparison purposes
	//
	hkArray<hkpBroadPhaseHandlePair> sapHits;
	{
		HK_TIME_CODE_BLOCK("BroadphaseQueryAabb", HK_NULL);
		for (int i=0; i<numQueries; i++)
		{
			sapHits.clear();
			m_world->getBroadPhase()->querySingleAabb( aabb, sapHits );
		}

	}

	//
	// Check results and draw 
	//
	for (int i=0; i<commands.getSize(); i++)
	{
		hkpKdTreeAabbCommand& command = commands[i];
		hkBool jobOk = compareHitArrays(command.m_aabb, command.m_results, command.m_numResultsOut, sapHits); 

		for (int j=0; j<command.m_numResultsOut; j++)
		{
			HK_SET_OBJECT_COLOR(command.m_results[j], hkColor::YELLOW);
		}
		HK_SET_OBJECT_COLOR((hkUlong)queryCollidable, hkColor::LIME);

		if( !jobOk )
		{
			m_env->m_textDisplay->outputText("MT Hit lits differed!", 20, 250, (hkUint32) hkColor::RED);
		}
	}


}
Esempio n. 15
0
void AabbQueryDemo::queryAabbST()
{
	HK_TIME_CODE_BLOCK("queryAabbST", HK_NULL);
	hkAabb aabb;
	// Grab a body from the world, and compute it's AABB + some padding
	const hkpCollidable* queryCollidable;
	{
		queryCollidable = m_collidables[m_collIdx];
		hkpRigidBody* rb = hkGetRigidBody(queryCollidable);
		queryCollidable->getShape()->getAabb(rb->getTransform(), 20.0f, aabb);
	}

	//
	// For performance timings, we query the same AABB multiple times and overwrite the results.
	// When using this, make sure to use different output arrays!
	//
	hkArray<hkPrimitiveId> kdhitsRecurs, kdhitsIter;		
	hkArray<hkpBroadPhaseHandlePair> sapHits;

	{
		HK_TIME_CODE_BLOCK("KdQueryRecursiveST", HK_NULL);
		for (int i=0; i<numQueries; i++)
		{
			kdhitsRecurs.clear();
			hkKdTreeAabbQueryUtils::queryAabbRecursive(m_world->m_kdTreeManager->getTree(), aabb, kdhitsRecurs);
		}
	}

	{
		HK_TIME_CODE_BLOCK("KdQueryIterativeST", HK_NULL);
		for (int i=0; i<numQueries; i++)
		{
			kdhitsIter.clear();
			hkKdTreeAabbQueryUtils::queryAabbIterative(m_world->m_kdTreeManager->getTree(), aabb, kdhitsIter);
		}
	}

	// Visualize the results
	HK_DISPLAY_BOUNDING_BOX(aabb, hkColor::YELLOW);

	for (int i=0; i<kdhitsIter.getSize(); i++)
	{
		HK_SET_OBJECT_COLOR(kdhitsIter[i], hkColor::YELLOW);		
	}

	HK_SET_OBJECT_COLOR((hkUlong)queryCollidable, hkColor::RED);


	// Call the corresponding hkp3AxisSweep method for comparison
	{
		HK_TIME_CODE_BLOCK("BroadphaseQueryAabb", HK_NULL);
		for (int i=0; i<numQueries; i++)
		{
			sapHits.clear();
			m_world->getBroadPhase()->querySingleAabb( aabb, sapHits );
		}

	}

	{
		hkBool iterOk = compareHitArrays(aabb, kdhitsIter.begin(), kdhitsIter.getSize(), sapHits); 
		hkBool recursOk = compareHitArrays(aabb, kdhitsRecurs.begin(), kdhitsRecurs.getSize(), sapHits);

		if( !(iterOk && recursOk) )
		{
			m_env->m_textDisplay->outputText("ST Hit lits differed!", 20, 150, (hkUint32) hkColor::RED);
		}
	}
}