/// Initialize multi-threading sharedThreadData and create threads.
vHavokCpuJobThreadPool::vHavokCpuJobThreadPool(const vHavokCpuJobThreadPoolCinfo& ci)
{
    m_isRunning = false;
    m_threadName = ci.m_threadName;
    m_stackSize = ci.m_stackSize;

    m_sharedThreadData.m_localHavokStackSize = ci.m_havokStackSize;
    m_sharedThreadData.m_timerBufferAllocation = ci.m_timerBufferPerThreadAllocation;

    int numThreads = ci.m_numThreads;
    if (numThreads >= MAX_NUM_THREADS)
    {
        HK_WARN( 0xf0defd23, "You requested 6 or more threads, this is not supported by vHavokCpuJobThreadPool" );
        numThreads = MAX_NUM_THREADS - 1;
    }

    m_sharedThreadData.m_numThreads = numThreads;

    m_sharedThreadData.m_OnWorkerThreadCreatedPtr = ci.m_OnWorkerThreadCreatedPtr;
    m_sharedThreadData.m_OnWorkerThreadFinishedPtr = ci.m_OnWorkerThreadFinishedPtr;

#if defined(HK_PLATFORM_XBOX360)
    int numCores = 3;
    int numThreadsPerCore = 2;
#elif defined(HK_PLATFORM_WIN32)
    hkHardwareInfo info;
    hkGetHardwareInfo( info );
    int numCores = info.m_numThreads; //This reports actual cores - ignoring hyperthreading
    int numThreadsPerCore = 1;
    numCores /= numThreadsPerCore;
#endif

    for (int i = 0; i < numThreads; i++ )
    {
        WorkerThreadData& data = m_workerThreads[i];
        data.m_sharedThreadData = &m_sharedThreadData;
        data.m_threadId = i + 1; // don't start with thread 0 (assume that is the calling thread)
        data.m_monitorStreamBegin = HK_NULL;
        data.m_monitorStreamEnd = HK_NULL;
        data.m_killThread = false;
        data.m_clearTimers = false;

#if defined(HK_PLATFORM_XBOX360) || defined(HK_PLATFORM_WIN32)
        if (ci.m_hardwareThreadIds.getSize() > 0)
        {
            HK_ASSERT2( 0x975fe134, ci.m_hardwareThreadIds.getSize() >= numThreads, "If you initialize hardware thread ids, you must give an ID to all threads");
            data.m_hardwareThreadId = ci.m_hardwareThreadIds[i];
        }
        else
        {
            //X360: { 2,4,1,3,5, 0, 2,4,.. }
            int procGroup = (data.m_threadId % numCores) * numThreadsPerCore;
            data.m_hardwareThreadId = procGroup + (numThreadsPerCore > 1? ((data.m_threadId / numCores) % numThreadsPerCore) : 0 );
        }
#endif

        data.m_thread.startThread( &hkWorkerThreadFunc, &data, m_threadName, m_stackSize );
    }
    hkReferencedObject::setLockMode( hkReferencedObject::LOCK_MODE_AUTO);
}
const char* HK_CALL hkAssetManagementUtil::getFilePath( hkStringBuf& filename, hkStructureLayout::LayoutRules rules )
{
#ifdef NEED_PLATFORM_SPECIFIC_EXTENSION
	if (! _fileExists( filename ) )
	{
		// Try platform extension
		int extn = filename.lastIndexOf('.');
		if (extn != -1)
		{
			hkStringBuf fe; getFileEnding(fe, rules); 
			filename.insert(extn, fe);
		}
	}
#endif
	
#ifdef HK_DEBUG
	{
		int a0 = filename.lastIndexOf('\\');
		int a1 = filename.lastIndexOf('/');
		int aLen = filename.getLength() - 1; // last index
		int mD0 = a0 >= 0? a0 : 0;
		int mD1 = a1 >= 0? a1 : 0;
		int maxSlash = mD0 > mD1? mD0 : mD1;
		if ( (aLen - maxSlash) > 42 )
		{
			hkStringBuf w;
			w.printf("Your file name [%s] is longer than 42 characters. May have issues on some consoles (like Xbox360).", filename.cString() );
			HK_WARN(0x04324, w.cString() );
		}
	}
#endif
	return filename;
}
Example #3
0
int LandscapeRepository::getLandscapeIndexByName( const char* name )
{
	for( int i = 0; i < m_landscapeEntries.getSize(); i++ )
	{
		if( hkString::strCmp(m_landscapeEntries[i].m_name, name ) == 0 )
		{
			return i;
		}
	}
	HK_WARN( 0x9420823a, "Couldn't find landscape repository " << name << ". Using landscape 0, " << m_landscapeEntries[0].m_name );
	return 0;
}
hkResult HK_CALL PhysicsLoadingUtil::loadScene( const char* filename, hkDemoEnvironment& env, hkpWorld& world, InputOptions* inputOpts, Output& output )
{
	hkResult res = LoadingUtil::loadScene( filename, env, inputOpts, output );
	if ( res == HK_FAILURE )
	{
		return HK_FAILURE;
	}

	// Grab the physics and add it if present
	hkpPhysicsData* physics = reinterpret_cast<hkpPhysicsData*>( output.m_rootLevelContainer->findObjectByType( hkpPhysicsDataClass.getName() ));

	if (!physics)
	{
		HK_WARN( 0x54e32123, "Unable to load hkpPhysicsData from file " << filename );
		return HK_FAILURE;
	}
	output.m_physicsData = physics;

	const hkArray<hkpPhysicsSystem*>& psys = physics->getPhysicsSystems();

	// Load physics systems
	for (int i=0; i < psys.getSize(); i++)
	{
		hkpPhysicsSystem* system = psys[i];

		// add the lot to the world
		world.addPhysicsSystem(system);

		for (int rb=0; rb < system->getRigidBodies().getSize(); rb++)
		{
			hkpRigidBody* body = system->getRigidBodies()[rb];

			if( inputOpts && inputOpts->m_transformScene )
			{
				hkMatrix3 rot = inputOpts->m_sceneTransformOptions.m_transformMatrix ;
				hkTransform transform; transform.setIdentity();
				transform.getRotation().setCols( rot.getColumn(0), rot.getColumn(1), rot.getColumn(2) );

				hkTransform tNew;
				tNew.setMul(transform, body->getTransform());
				body->setTransform( tNew );
			}
		}
	}

	return HK_SUCCESS;
}
hkDemo::Result AabbQueryDemo::stepDemo()
{
	if (m_jobThreadPool->getNumThreads() == 0)
	{
		 HK_WARN(0x34561f23, "This demo does not run with only one thread");
		 return DEMO_STOP;
	}

	hkDemo::Result result = hkDefaultPhysicsDemo::stepDemo();

	m_world->markForWrite();

	{
		queryAabbST();
		queryAabbMT();
	}
	
	m_world->unmarkForWrite();

	{
		m_monitorHelper->updateTree();
		hkString timers;
		hkReal recursive, iterative, spu = 0.0f, bp;

		recursive = m_monitorHelper->findTrackedTimer("KdQueryRecursiveST", MultithreadedMonitorHelper::TRACK_FRAME_MAX)->getAvgFrameValue();
		iterative = m_monitorHelper->findTrackedTimer("KdQueryIterativeST", MultithreadedMonitorHelper::TRACK_FRAME_MAX)->getAvgFrameValue();
		spu = m_monitorHelper->findTrackedTimer("KdAabbQueryJob", MultithreadedMonitorHelper::TRACK_FRAME_MAX)->getAvgFrameValue();
		
		// This gets called twice, but the helper only picks up once instance of it.
		bp = m_monitorHelper->findTrackedTimer("BroadphaseQueryAabb", MultithreadedMonitorHelper::TRACK_FRAME_MAX)->getAvgFrameValue();

		timers.printf("CPU recursive: %f\nCPU iterative: %f\nSPU query: %f\nbroadphase: %f", recursive, iterative, spu, bp);

		m_env->m_textDisplay->outputText(timers.cString(), 20, 400);
	}

	return result;

}
Example #6
0
void hkFlattenShapeHierarchyUtil::getLeafShapesFromShape(const hkpShape* shape, const hkTransform& transform, const hkBool isFixedBody, hkArray<hkpExtendedMeshShape::TrianglesSubpart>& trianglePartsOut, hkArray<hkpConvexShape*>& convexShapesOut, hkArray<hkpShape*>& otherShapesOut)
{
	const hkpShapeType type = shape->getType();

	hkTransform newTransform;

	const hkpShape* childShape = HK_NULL;
	hkUlong userData = HK_NULL;

	switch(type)
	{
	case HK_SHAPE_LIST:
	case HK_SHAPE_CONVEX_LIST:
		{
			const hkpShapeContainer* container = shape->getContainer();
			hkpShapeContainer::ShapeBuffer buffer;

			HK_ASSERT2(0xad67da22, 0 == (0xffff0000 & hkUlong(shape->getUserData())), "We're dropping a non-zero lookupIndex from user data.");
			hkUint16 materialId = hkUint16(0xffff & hkUlong(shape->getUserData()));

			for (hkpShapeKey key = container->getFirstKey(); key != HK_INVALID_SHAPE_KEY; key = container->getNextKey(key))
			{
				const hkpShape* child = container->getChildShape(key, buffer);

				if (materialId && 0 == (0xffff & hkUlong(child->getUserData())) )
				{
					// no material id for the child -- copy it
					hkUlong childData = hkUlong(child->getUserData()) | materialId;
					// Warning: modifying the const input hkpShape*
					const_cast<hkpShape*>(child)->setUserData(childData);
				}
				//HK_ASSERT2(0xad6777dd, isFixedBody || !isLeafShape(child), "A child of a list shape cannot be a terminal node. You must use a transform shape in between." );
				getLeafShapesFromShape(child, transform, isFixedBody, trianglePartsOut, convexShapesOut, otherShapesOut);
			}
		}
		break;
	case HK_SHAPE_TRANSFORM:
		{
			const hkpTransformShape* transformShape = static_cast<const hkpTransformShape*>(shape);
			newTransform.setMul(transform, transformShape->getTransform());
			childShape = transformShape->getChildShape();
			userData = hkUlong(transformShape->getUserData());
		}
		break;
	case HK_SHAPE_CONVEX_TRANSFORM:
		{
			const hkpConvexTransformShape* convexTransformShape = static_cast<const hkpConvexTransformShape*>(shape);
			newTransform.setMul(transform, convexTransformShape->getTransform());
			childShape = convexTransformShape->getChildShape();
			userData = hkUlong(convexTransformShape->getUserData());
		}
		break;
	case HK_SHAPE_CONVEX_TRANSLATE:
		{
			const hkpConvexTranslateShape* convexTranslateShape = static_cast<const hkpConvexTranslateShape*>(shape);
			hkTransform localTransform( static_cast<const hkRotation&>(hkRotation::getIdentity()), convexTranslateShape->getTranslation() );
			newTransform.setMul(transform, localTransform);
			childShape = convexTranslateShape->getChildShape();
			userData = hkUlong(convexTranslateShape->getUserData());
		}
		break;

	case HK_SHAPE_BV_TREE:
		{
			const hkpBvTreeShape* bvTreeshape = static_cast<const hkpBvTreeShape*>(shape);	
			HK_ASSERT2(0xad67da22, 0 == (0xffff0000 & hkUlong(bvTreeshape->getUserData())), "We're dropping a non-zero lookupIndex from user data.");

			const hkpShapeContainer* container = bvTreeshape->getContainer();
			for (hkpShapeKey key = container->getFirstKey(); key!= HK_INVALID_SHAPE_KEY; key = container->getNextKey(key))
			{
				hkpShapeContainer::ShapeBuffer buffer;
				const hkpShape* child = container->getChildShape(key, buffer);
				const hkpShapeType childType = child->getType();
				if ((childType == HK_SHAPE_LIST) || (childType == HK_SHAPE_CONVEX_LIST))
				{
					getLeafShapesFromShape(child, transform, isFixedBody, trianglePartsOut, convexShapesOut, otherShapesOut);
				}
			}

			break;
		}
	case HK_SHAPE_MOPP:
		{
			const hkpMoppBvTreeShape* bvTreeshape = static_cast<const hkpMoppBvTreeShape*>(shape);	
		//	HK_ASSERT2(0xad67da22, 0 == (0xffff0000 & hkUlong(bvTreeshape->getUserData())), "We're dropping a non-zero lookupIndex from user data.");
			getLeafShapesFromShape(bvTreeshape->getShapeCollection(), transform, isFixedBody, trianglePartsOut, convexShapesOut, otherShapesOut);

			break;
		}

	default:
		{
			//HK_ASSERT2(0xad67ddaa, isFixedBody, "A child of a list was attached without an intermediate transform shape. This is not handled.");
			
			// We can get simple shapes without transforms when processing fixed bodies. We do add a hkpConvexTransformShape as usual then ...
			childShape = shape;
			newTransform = transform;
			userData = hkUlong(shape->getUserData());
			//HK_ASSERT2(0XAD678D8D, 0 == (userData & 0xffff0000), "Userdata of a fixed body (other than the one fixed uber body) has a non-zero destructible info index.");
		}
		break;
	}

	if (HK_NULL != childShape)
	{
		hkBool leafDone = false;
		if (hkOneFixedMoppUtil::isTerminalConvexShape(childShape))
		{
			// Create new transform shape to wrap the child terminal shape
			hkpConvexTransformShape* newConvexTransformShape = new hkpConvexTransformShape(static_cast<const hkpConvexShape*>(childShape), newTransform);
			newConvexTransformShape->setUserData( userData );

			HK_ASSERT2(0xad67da23, 0 == (0xffff0000 & hkUlong(childShape->getUserData())) || (0xffff0000 & userData) == (0xffff0000 & hkUlong(childShape->getUserData())), "We're dropping a non-zero user data.");
			HK_ASSERT2(0xad67da24, 0 == (0xffff & hkUlong(childShape->getUserData())) || (0xffff & userData) == (0xffff & hkUlong(childShape->getUserData())), "Materials differ in the terminal shape and its wrapping hkpTransformShape.");

			// put this transform on the shapesOut list
			convexShapesOut.pushBack(newConvexTransformShape);
			leafDone = true;
		}
		else if (isLeafShape(childShape))
		{
				// It's not a terminal(leaf?) convex shape, but it might be a mesh, or indeed a simplemesh.
				// It's most likely to be a storagemesh, but we can't assume that, so check vtable:
			const hkClass* childShapeClass = hkBuiltinTypeRegistry::getInstance().getVtableClassRegistry()->getClassFromVirtualInstance(childShape);
			if( hkpMeshShapeClass.isSuperClass(*childShapeClass) )
			{
				const hkpMeshShape* mesh = static_cast<const hkpMeshShape*>(childShape);

				// Confirm vertex data not shared, see below
#if defined(HK_DEBUG)
				{
					for(int i = 0; i < mesh->getNumSubparts(); i++)
					{
						const hkpMeshShape::Subpart& meshSubPartI = mesh->getSubpartAt(i);
						for(int j = i+1; j < mesh->getNumSubparts(); j++)
						{
							const hkpMeshShape::Subpart& meshSubPartJ = mesh->getSubpartAt(j);
							HK_ASSERT2(0x0, meshSubPartI.m_vertexBase != meshSubPartJ.m_vertexBase, "This method can't (currently) collapse chared meshs data as it collpases the transform into the verts\n");
						}
						
					}
				}
#endif

				for(int i = 0; i < mesh->getNumSubparts(); i++)
				{
					const hkpMeshShape::Subpart& meshSubPart = mesh->getSubpartAt(i);
					// Now we have the subpart. We can't know if the data pointed to is 'owned' by the mesh (eg. subclass hkpStorageMeshShape)
					// or 'pointed to' (base class hkpMeshShape)
					//
					// We'll just assume here we can 'share' the data by grabbing the pointers...

					hkpExtendedMeshShape::TrianglesSubpart extendedMeshSubPart;
					
					extendedMeshSubPart.m_vertexBase = meshSubPart.m_vertexBase;
					extendedMeshSubPart.m_vertexStriding = meshSubPart.m_vertexStriding;
					extendedMeshSubPart.m_numVertices = meshSubPart.m_numVertices;
					extendedMeshSubPart.m_triangleOffset = meshSubPart.m_triangleOffset;

					// .. but we'll have to multiply in the transform! This assumes the vertex data is not shared!
					{
						for(int j = 0; j < extendedMeshSubPart.m_numVertices ; j++)
						{
							hkVector4 v;
							v(0) = extendedMeshSubPart.m_vertexBase[0 + extendedMeshSubPart.m_vertexStriding/sizeof(float) * j];
							v(1) = extendedMeshSubPart.m_vertexBase[1 + extendedMeshSubPart.m_vertexStriding/sizeof(float) * j];
							v(2) = extendedMeshSubPart.m_vertexBase[2 + extendedMeshSubPart.m_vertexStriding/sizeof(float) * j];
							v.setTransformedPos(transform, v);
							const_cast<float*>(extendedMeshSubPart.m_vertexBase)[0 + extendedMeshSubPart.m_vertexStriding/sizeof(float) * j] = v(0);
							const_cast<float*>(extendedMeshSubPart.m_vertexBase)[1 + extendedMeshSubPart.m_vertexStriding/sizeof(float) * j] = v(1);
							const_cast<float*>(extendedMeshSubPart.m_vertexBase)[2 + extendedMeshSubPart.m_vertexStriding/sizeof(float) * j] = v(2);
						}
					}

					extendedMeshSubPart.m_indexBase = meshSubPart.m_indexBase;
					extendedMeshSubPart.m_indexStriding = meshSubPart.m_indexStriding;
					extendedMeshSubPart.m_numTriangleShapes = meshSubPart.m_numTriangles;
					extendedMeshSubPart.m_stridingType = (meshSubPart.m_stridingType == hkpMeshShape::INDICES_INT16) ? hkpExtendedMeshShape::INDICES_INT16 : hkpExtendedMeshShape::INDICES_INT32;

					trianglePartsOut.pushBack(extendedMeshSubPart);

					leafDone = true;
				}
			}
		}

		if(!leafDone)
		{
			HK_WARN(0xad678dda, "An extra hkTransform shape has been inserted into the hierarchy. This might be suboptimal.");
			// Create new transform shape to wrap the child terminal shape
			hkpTransformShape* newTransformShape = new hkpTransformShape(childShape, newTransform);
			newTransformShape->setUserData( userData );

			HK_ASSERT2(0xad67da23, 0 == (0xffff0000 & hkUlong(childShape->getUserData())) || (0xffff0000 & userData) == (0xffff0000 & hkUlong(childShape->getUserData())), "We're dropping a non-zero user data.");
			HK_ASSERT2(0xad67da24, 0 == (0xffff & hkUlong(childShape->getUserData())) || (0xffff & userData) == (0xffff & hkUlong(childShape->getUserData())), "Materials differ in the terminal shape and its wrapping hkpTransformShape.");

			// put this transform on the shapesOut list
			otherShapesOut.pushBack(newTransformShape);
			leafDone = true;
		}

		if(!leafDone)
		{
			//HK_ASSERT2(0xad67da23, 0 == (0xffff0000 & shape->getUserData()), "We're dropping a non-zero user data.");
			if ( 0xffff0000 & hkUlong(shape->getUserData()) )
			{
				// copy the destruction info index downwards..
				HK_ASSERT2(0xad67da23, 0 == (0xffff0000 & hkUlong(childShape->getUserData())) || (0xffff0000 & userData) == (0xffff0000 & hkUlong(childShape->getUserData())), "We're dropping a non-zero user data.");
				HK_ASSERT2(0xad67da24, 0 == (0xffff & hkUlong(childShape->getUserData())) || (0xffff & hkUlong(shape->getUserData())) == (0xffff & hkUlong(childShape->getUserData())), "Materials differ in the terminal shape and its wrapping hkpTransformShape.");

				//HK_WORLD_ACCESS_CHECK(parentBody->getWorld(), HK_ACCESS_RW );
				// Warning: we're actually modifying the const hkpShape* passed as an input parameter
				const_cast<hkpShape*>(childShape)->setUserData( shape->getUserData() );
			}
			getLeafShapesFromShape(childShape, newTransform, isFixedBody, trianglePartsOut, convexShapesOut, otherShapesOut);
		}
	}
}
Example #7
0
void Gdc2005Demo::initAnimation()
{
	// Initialize the state machine.
	m_stateManager = new GdcStateManager();
	{
		GdcState* state = new GdcStandState();
		m_stateManager->registerState (GDC_STAND_STATE, state);
		state->removeReference();

		state = new GdcWalkState();
		m_stateManager->registerState (GDC_WALK_STATE, state);
		state->removeReference();

		state = new GdcJumpState();
		m_stateManager->registerState (GDC_JUMP_STATE, state);
		state->removeReference();

		state = new GdcInAirState();
		m_stateManager->registerState (GDC_IN_AIR_STATE, state);
		state->removeReference();

		state = new GdcLandState();
		m_stateManager->registerState (GDC_LAND_STATE, state);
		state->removeReference();

		state = new GdcDyingState();
		m_stateManager->registerState (GDC_DYING_STATE, state);
		state->removeReference();

		state = new GdcDeadState();
		m_stateManager->registerState (GDC_DEAD_STATE, state);
		state->removeReference();

		state = new GdcGettingUpState();
		m_stateManager->registerState (GDC_GETTING_UP_STATE, state);
		state->removeReference();

		state = new GdcDiveState();
		m_stateManager->registerState (GDC_DIVE_STATE, state);
		state->removeReference();
	}

	//Initialize the skeleton
	{

		// Get the rig
		{
			hkString assetFile = hkAssetManagementUtil::getFilePath("Resources/Animation/ShowCase/Gdc2005/Model/Firefighter_Rig.hkx");
			m_rigContainer = m_loader->load( assetFile.cString() );
			HK_ASSERT2(0x27343437, m_rigContainer != HK_NULL , "Could not load asset");
			hkaAnimationContainer* ac = reinterpret_cast<hkaAnimationContainer*>( m_rigContainer->findObjectByType( hkaAnimationContainerClass.getName() ));

			HK_ASSERT2(0x27343435, ac && (ac->m_numSkeletons > 0), "No skeleton loaded");

			m_animatedSkeleton = new hkaAnimatedSkeleton( ac->m_skeletons[0] );

		}

		// Get the skin (different file)
		{
			hkString assetFile;
			if (m_bUseHardwareSkinning)
				assetFile = hkAssetManagementUtil::getFilePath("Resources/Animation/ShowCase/Gdc2005/Model/Firefighter_PS2_18Bones_Skin.hkx");
			else
				assetFile = hkAssetManagementUtil::getFilePath("Resources/Animation/ShowCase/Gdc2005/Model/Firefighter_Skin.hkx");

			hkRootLevelContainer* rootContainer = m_loader->load( assetFile.cString() );
			HK_ASSERT2(0x27343437, rootContainer != HK_NULL , "Could not load asset");
			hkaAnimationContainer* ac = reinterpret_cast<hkaAnimationContainer*>( rootContainer->findObjectByType( hkaAnimationContainerClass.getName() ));

			HK_ASSERT2(0x27343435, ac && (ac->m_numSkins > 0), "No skins loaded");

			m_numSkinBindings = ac->m_numSkins;
			m_skinBindings = ac->m_skins;

			hkxScene* scene = reinterpret_cast<hkxScene*>( rootContainer->findObjectByType( hkxSceneClass.getName() ));
			HK_ASSERT2(0x27343435, scene , "No scene loaded");

			// Make graphics output buffers for the skins
			m_env->m_sceneConverter->setAllowHardwareSkinning(m_bUseHardwareSkinning);
			m_env->m_sceneConverter->convert( scene );

			if (m_bUseHardwareSkinning)
			{
				for (int ms=0; ms < m_numSkinBindings; ++ms)
				{
					hkaMeshBinding* skinBinding = m_skinBindings[ms];

					if (! m_env->m_sceneConverter->setupHardwareSkin( m_env->m_window->getContext(), skinBinding->m_mesh,
						   reinterpret_cast<hkgAssetConverter::IndexMapping*>( skinBinding->m_mappings ),
						   skinBinding->m_numMappings, (hkInt16)skinBinding->m_skeleton->m_numBones ) )
					{
						HK_WARN(0x0, "Could not setup hardware skinning from given asset!");
					}
				}
			}
		}

		// Add animations in order
		{
			// GDC_MOVE_CONTROL - A Dummy control
			hkaDefaultAnimationControl* control;

			// GDC_WALK_CONTROL
			control = new hkaDefaultAnimationControl( HK_NULL );
			control->easeOut(0.0f);
			control->setMasterWeight(0.01f);
			m_animatedSkeleton->addAnimationControl( control );
			control->removeReference();

			// GDC_IDLE_CONTROL
			control = AnimationUtils::loadControl( *m_loader, "Resources/Animation/ShowCase/Gdc2005/Animations/hkIdle1.hkx" );
			m_animatedSkeleton->addAnimationControl( control );
			control->removeReference();

			// GDC_JUMP_CONTROL
			control = AnimationUtils::loadControl( *m_loader, "Resources/Animation/ShowCase/Gdc2005/Animations/hkRunJump.hkx" );
			m_animatedSkeleton->addAnimationControl( control );
			control->removeReference();

			// GDC_IN_AIR_CONTROL
			control = AnimationUtils::loadControl( *m_loader, "Resources/Animation/ShowCase/Gdc2005/Animations/hkInAir.hkx" );
			m_animatedSkeleton->addAnimationControl( control );
			control->removeReference();

			// GDC_LAND_CONTROL
			control = AnimationUtils::loadControl( *m_loader,"Resources/Animation/ShowCase/Gdc2005/Animations/hkHardLand.hkx" );
			m_animatedSkeleton->addAnimationControl( control );
			control->removeReference();

			// GDC_DYING_CONTROL
			control = AnimationUtils::loadControl( *m_loader, "Resources/Animation/ShowCase/Gdc2005/Animations/hkDie.hkx" );
			m_animatedSkeleton->addAnimationControl( control );
			control->removeReference();

			// GDC_GET_UP_CONTROL
			control = AnimationUtils::loadControl( *m_loader, "Resources/Animation/ShowCase/Gdc2005/Animations/hkKnockdown2.hkx" );
			m_animatedSkeleton->addAnimationControl( control );
			control->setPlaybackSpeed(0.0f);
			control->removeReference();

			// GDC_WALK_CONTROL
			control = AnimationUtils::loadControl( *m_loader, "Resources/Animation/ShowCase/Gdc2005/Animations/hkWalk.hkx");
			control->setMasterWeight( 0.0f );
			control->easeIn( 0.0f );
			m_animatedSkeleton->addAnimationControl( control );
			control->removeReference();

			// GDC_RUN_CONTROL
			control = AnimationUtils::loadControl( *m_loader, "Resources/Animation/ShowCase/Gdc2005/Animations/hkRun.hkx");
			// To sync with walk
			control->setLocalTime( 17.0f / 60.0f );
			control->setMasterWeight( 0.0f );
			control->easeIn( 0.0f );
			m_animatedSkeleton->addAnimationControl( control );
			control->removeReference();

			// GDC_DIVE_CONTROL
			control = AnimationUtils::loadControl( *m_loader,"Resources/Animation/ShowCase/Gdc2005/Animations/hkDive.hkx" );
			m_animatedSkeleton->addAnimationControl( control );
			control->removeReference();

		}

		// Initialize the animation command processor
		{
			m_animationMachine = new GdcAnimationMachine(m_animatedSkeleton);
			m_animatedSkeleton->removeReference();
		}

		// Initialize the state machine
		{
			m_animationStateMachine = new GdcStateContext( m_stateManager );
			m_stateManager->removeReference();
			m_animationStateMachine->setCurrentState(GDC_STAND_STATE, m_animationMachine );
		}

		// Add constraints to skeleton
		{
			const hkaSkeleton* skeleton = m_animatedSkeleton->getSkeleton();

			// Lock translations (except root, named "position")
			hkaSkeletonUtils::lockTranslations(*skeleton);

			// and except also the children "reference" and "root"
			const hkInt16 referenceBoneIdx = hkaSkeletonUtils::findBoneWithName(*skeleton, "reference");
			const hkInt16 rootBoneIdx = hkaSkeletonUtils::findBoneWithName(*skeleton, "root");
			skeleton->m_bones[referenceBoneIdx]->m_lockTranslation = false;
			skeleton->m_bones[rootBoneIdx]->m_lockTranslation = false;

		}

	}
}
bool vHavokAiNavMeshLinker::LinkNavMeshes(const NavMeshLinkSetting& navMeshLinkSetting)
{
	const int numNavMeshes = m_navMeshes.getSize();
	hkLocalArray<hkaiNavMesh*> havokAiNavMeshes(numNavMeshes);
	hkLocalArray<hkaiNavMeshInstance*> havokAiInstances(numNavMeshes);
	hkLocalArray<hkaiNavMeshQueryMediator*> havokAiMediators(numNavMeshes);
	hkLocalArray<hkAabb> aabbs(numNavMeshes);
	hkLocalArray<hkaiSectionUid> arrayIndexToUid(numNavMeshes);
	{
		for (int idx = 0; idx < numNavMeshes; ++idx)
		{
			vHavokAiNavMeshInstance* visionInstance = m_navMeshes[idx];
			vHavokAiNavMeshResource* visionResource = m_navMeshes[idx]->GetResource();

			hkaiNavMeshInstance* havokInstance = visionInstance->GetNavMeshInstance();
			hkaiNavMeshQueryMediator* havokMediator = visionResource->GetNavMeshQueryMediator();
			hkaiNavMesh* havokNavMesh = visionResource->GetNavMesh();
#if defined(HK_DEBUG_SLOW)
			VASSERT(havokInstance->getOriginalMesh() == havokNavMesh);
			hkaiNavMeshUtils::validate(*havokInstance->getOriginalMesh());
#endif

			// this should be sufficient as we should have all the navmeshes at this point (Even the unloaded ones?)
			hkaiSectionUid uid = havokInstance->getSectionUid();
			if (arrayIndexToUid.indexOf(uid) != -1)
			{
				// duplicate key found!
				HK_WARN(0x69585a95, "Cannot stitch navmeshes together because duplicate hkaiSectionUid found for navmesh instance");
				return false;
			}
			arrayIndexToUid.pushBack(uid);

			havokAiInstances.pushBack(havokInstance);
			havokAiMediators.pushBack(havokMediator);
			havokAiNavMeshes.pushBack(havokNavMesh);

			hkAabb aabb;
			havokInstance->getAabb(aabb);
			aabbs.pushBack(aabb);
		}
	}

	// stitch together navMeshes
	if (havokAiInstances.getSize() > 1)
	{
		// Find overlaps between AABBs
		hkArray<hkKeyPair>::Temp pairs;
		hkaiStreamingUtils::findPotentialDependencies(aabbs, pairs);

#if defined(HAVOK_SDK_VERSION_MAJOR) && (HAVOK_SDK_VERSION_MAJOR < 2012)
		hkaiStreamingUtils::EdgeRemap edgeRemap;
#endif

		// Find potential connections between the nav mesh tiles
		for (int i = 0; i < pairs.getSize(); i++)
		{
			hkUint32 indexA = pairs[i].m_keyA;
			hkUint32 indexB = pairs[i].m_keyB;

			hkaiSectionUid uidA = arrayIndexToUid[indexA];
			hkaiSectionUid uidB = arrayIndexToUid[indexB];
			VASSERT(havokAiInstances[indexA]->getSectionUid() == uidA);
			VASSERT(havokAiInstances[indexA]->getOriginalMesh() == havokAiNavMeshes[indexA]);
			VASSERT(havokAiInstances[indexB]->getSectionUid() == uidB);
			VASSERT(havokAiInstances[indexB]->getOriginalMesh() == havokAiNavMeshes[indexB]);

			hkaiStreamingUtils::FindEdgeOverlapInput input;
			input.m_meshA = havokAiNavMeshes[indexA];
			input.m_uidA = uidA;
			input.m_mediatorA = havokAiMediators[indexA];
			input.m_meshB = havokAiNavMeshes[indexB];
			input.m_uidB = uidB;
			input.m_mediatorB = havokAiMediators[indexB];

      // set link settings
      input.m_edgeMatchTolerance = navMeshLinkSetting.m_edgeMatchTolerance;
      input.m_edgeMatchingParams.m_maxStepHeight = navMeshLinkSetting.m_maxStepHeight;
      input.m_edgeMatchingParams.m_maxOverhang = navMeshLinkSetting.m_maxOverhang; // slightly bigger than the default, since the meshes were built independently.
      input.m_edgeMatchingParams.m_maxSeparation = navMeshLinkSetting.m_maxSeparation;
      input.m_edgeMatchingParams.m_cosPlanarAlignmentAngle = navMeshLinkSetting.m_cosPlanarAlignmentAngle;
      input.m_edgeMatchingParams.m_cosVerticalAlignmentAngle = navMeshLinkSetting.m_cosVerticalAlignmentAngle;
      input.m_edgeMatchingParams.m_minEdgeOverlap = navMeshLinkSetting.m_minEdgeOverlap;

			// For each overlapping pair of AABBs, try to match up edges between the meshes

#if defined(HAVOK_SDK_VERSION_MAJOR) && (HAVOK_SDK_VERSION_MAJOR >= 2012)
			hkaiStreamingUtils::generateStreamingInfo(input);
#else
			hkaiStreamingUtils::findEdgeOverlaps(input, edgeRemap);
#endif
		}

#if defined(HAVOK_SDK_VERSION_MAJOR) && (HAVOK_SDK_VERSION_MAJOR < 2012)
		// Process all the edge changes that we accumulated
		hkaiStreamingUtils::remapSplitEdges(havokAiNavMeshes, edgeRemap);
#endif
	}

	for (int idx = 0; idx < havokAiInstances.getSize(); ++idx)
	{
		hkaiNavMeshUtils::validate(*havokAiInstances[idx]->getOriginalMesh());
	}
	return true;
}
hkDemo::Result WorldLinearCastMultithreadedDemo::stepDemo()
{
	if (m_jobThreadPool->getNumThreads() == 0)
	{
		 HK_WARN(0x34561f23, "This demo does not run with only one thread");
		 return DEMO_STOP;
	}

//	const WorldLinearCastMultithreadedDemoVariant& variant = g_WorldLinearCastMultithreadedDemoVariants[m_variantId];

	m_world->lock();

	//	Reset all object colors
	{
		for (int i = 0; i < m_rocksOnTheFloor.getSize(); i++)
		{
			HK_SET_OBJECT_COLOR((hkUlong)m_rocksOnTheFloor[i]->getCollidable(), hkColor::rgbFromChars(70,70,70));
		}
	}


	// For this cast we use a hkpClosestCdPointCollector to gather the results:
	hkpClosestCdPointCollector collectors[10];

	// Since we're not too concerned with perfect accuracy, we can set the early out
	// distance to give the algorithm a chance to exit more quickly:
	m_world->getCollisionInput()->m_config->m_iterativeLinearCastEarlyOutDistance = 0.1f;
	
	m_world->unlock();

	// Cast direction & length.
	hkVector4 castVector( 0.0f, -30.0f, 0.0f );

	int numQueryObjects = m_queryObjects.getSize();

	//
	// Setup the output array where the resulting collision points will be returned.
	//
	hkpRootCdPoint* collisionPoints = hkAllocateChunk<hkpRootCdPoint>(numQueryObjects, HK_MEMORY_CLASS_DEMO);

	//
	// Setup commands: one command for each query object.
	//
	hkArray<hkpWorldLinearCastCommand> commands;
	{
		for ( int i = 0; i < numQueryObjects; i++ )
		{
			QueryObject& queryObject = m_queryObjects[i];

			//
			// Let QueryObjects move in circles.
			//
			hkVector4 position;
			{
				hkReal t = m_time + HK_REAL_PI * 2 * i / m_queryObjects.getSize();
				position.set( hkMath::sin( t ) * 10.0f, 10.0f, hkMath::cos( t ) * 10.0f );
			}

			queryObject.m_transform->setTranslation(position);

			hkpWorldLinearCastCommand& command = commands.expandOne();
			{
				// Init input data.
				{
					command.m_input.m_to				  . setAdd4( position, castVector );
					command.m_input.m_maxExtraPenetration = HK_REAL_EPSILON;
					command.m_input.m_startPointTolerance = HK_REAL_EPSILON;

					command.m_collidable				  = queryObject.m_collidable;
				}

				// Init output data.
				{
					command.m_results			= &collisionPoints[i];
					command.m_resultsCapacity	= 1;
					command.m_numResultsOut		= 0;
				}
			}
		}
	}

	//
	// Create the job header.
	//
	hkpCollisionQueryJobHeader* jobHeader;
	{
		jobHeader = hkAllocateChunk<hkpCollisionQueryJobHeader>(1, HK_MEMORY_CLASS_DEMO);
	}

	//
	// Setup hkpWorldLinearCastJob.
	//
	m_world->markForRead();
	hkpWorldLinearCastJob worldLinearCastJob(m_world->getCollisionInput(), jobHeader, commands.begin(), commands.getSize(), m_world->m_broadPhase, &m_semaphore);
	m_world->unmarkForRead();

	//
	// Put the job on the queue, kick-off the PPU/SPU threads and wait for everything to finish.
	//
	{
		m_world->lockReadOnly();

		//
		// Put the raycast job on the job queue.
		//

		worldLinearCastJob.setRunsOnSpuOrPpu();
		m_jobQueue->addJob( worldLinearCastJob, hkJobQueue::JOB_LOW_PRIORITY );

		m_jobThreadPool->processAllJobs( m_jobQueue );

		m_jobThreadPool->waitForCompletion();

		//
		// Wait for the one single job we started to finish.
		//
		m_semaphore.acquire();

		m_world->unlockReadOnly();
	}

	//
	// Display results.
	//
	{
		m_world->lock();
		{
			for (int i = 0; i < commands.getSize(); i++)
			{
				QueryObject& queryObject = m_queryObjects[i];

				hkpWorldLinearCastCommand& command = commands[i];
				if ( command.m_numResultsOut > 0 )
				{
					// move our position to the hit and draw a line along the cast direction
					hkVector4& pos = queryObject.m_transform->getTranslation();
					hkVector4 to; to.setAdd4( pos, castVector );
					hkVector4 newPos; newPos.setInterpolate4( pos, to, command.m_results->m_contact.getDistance() );
					HK_DISPLAY_LINE(pos, newPos, hkColor::GREEN);

					// Update our QO
					queryObject.m_transform->setTranslation( newPos );
					hkDebugDisplay::getInstance().updateGeometry( queryObject.m_collidable->getTransform(), (hkUlong)queryObject.m_collidable, 0);

					// call a function to display the details
					displayRootCdPoint( m_world, *command.m_results );
				}
				else
				{
					// only draw a line along the cast direction
					hkVector4& pos = queryObject.m_transform->getTranslation();
					hkVector4 to; to.setAdd4( pos, castVector );
					HK_DISPLAY_LINE(pos, to, hkColor::GREEN);

					// Update our QO
					hkVector4 nirvana(10000.0f, 10000.0f, 10000.0f);
					queryObject.m_transform->setTranslation( nirvana );
					hkDebugDisplay::getInstance().updateGeometry( queryObject.m_collidable->getTransform(), (hkUlong)queryObject.m_collidable, 0);
				}
			}
		}
		m_world->unlock();
	}

	//
	// Free temporarily allocated memory.
	//
	hkDeallocateChunk( jobHeader, 1, HK_MEMORY_CLASS_DEMO );
	hkDeallocateChunk(collisionPoints, numQueryObjects, HK_MEMORY_CLASS_DEMO);

	m_time += 0.005f;

	return hkDefaultPhysicsDemo::stepDemo();
}
Example #10
0
int main(int argc, char* argv[])
{
	// initialize Havok internals
	{
		hkMemorySystem::FrameInfo frameInfo(0);

#ifdef _DEBUG
		// (Use debug mem manager to detect mem leaks in Havok code)
		hkMemoryRouter* memoryRouter = hkMemoryInitUtil::initChecking(hkMallocAllocator::m_defaultMallocAllocator, frameInfo);
#else
		hkMemoryRouter* memoryRouter = hkMemoryInitUtil::initFreeListLargeBlock(hkMallocAllocator::m_defaultMallocAllocator, frameInfo);
#endif

		hkBaseSystem::init( memoryRouter, havokErrorReport );

		hkError& errorhandler = hkError::getInstance();
		errorhandler.enableAll();
	}

	if (argc != 2)
	{
		printf("Invalid number of input arguments\n");
		printf("Usage: FBXImport <input_filename>\n");
		return -1;
	}

	// Load FBX and save as HKX
	{
		const char* filename = argv[1];

		FbxManager* fbxSdkManager = FbxManager::Create();
		if( !fbxSdkManager )
		{
			HK_ERROR(0x5213afed, "Unable to create FBX Manager!\n");
			return -1;
		}

		FbxIOSettings* fbxIoSettings = FbxIOSettings::Create(fbxSdkManager, IOSROOT);
		fbxSdkManager->SetIOSettings(fbxIoSettings);

		FbxImporter* fbxImporter = FbxImporter::Create(fbxSdkManager,"");

		if (!fbxImporter->Initialize(filename, -1, fbxSdkManager->GetIOSettings()))
		{
			HK_WARN(0x5216afed, "Failed to initialize the importer! Please ensure file " << filename << " exists\n");
			fbxSdkManager->Destroy();
			return -1;
		}

		FbxScene* fbxScene = FbxScene::Create(fbxSdkManager,"tempScene");
		if (!fbxScene)
		{
			HK_ERROR(0x5216afed, "Failed to create the scene!\n");
			fbxImporter->Destroy();
			fbxSdkManager->Destroy();
			return -1;
		}

		fbxImporter->Import(fbxScene);
		fbxImporter->Destroy();

		// Currently assume that the file is loaded from 3dsmax
		FbxAxisSystem::Max.ConvertScene(fbxScene);

		FbxToHkxConverter::Options options(fbxSdkManager);
		FbxToHkxConverter converter(options);

		if(converter.createScenes(fbxScene))
		{
			int lastSlashIndex = hkString::lastIndexOf(filename,'\\') + 1;
			int extensionIndex = hkString::lastIndexOf(filename,'.');

			hkStringBuf path;
			path.set(filename, lastSlashIndex);

			hkStringBuf name;
			name.set(filename + lastSlashIndex, extensionIndex - lastSlashIndex);

			converter.saveScenes(path, name);
		}
		else
		{
			HK_ERROR(0x0, "Failed to convert the scene!\n");
			fbxSdkManager->Destroy();
			return -1;
		}

		fbxSdkManager->Destroy();
	}

	// quit Havok
	{
		hkBaseSystem::quit();
		hkMemoryInitUtil::quit();
	}
	
	return 0;
}