/// 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; }
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; }
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); } } }
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(); }
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; }