AabbQueryDemo::AabbQueryDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env), m_semaphore(0, 1000 ), m_rand(1337) { { m_worldSizeX = 2.0f * hkMath::sqrt(hkReal(m_env->m_cpuMhz)); m_worldSizeY = 3; m_worldSizeZ = m_worldSizeX; } // Setup the camera and graphics { // setup the camera hkVector4 from(0.0f, m_worldSizeZ*2.f, -m_worldSizeZ); hkVector4 to (0.0f, 0.0f, 0.0f); hkVector4 up (0.0f, 1.0f, 0.0f); setupDefaultCameras( env, from, to, up, 1.0f, 5000.0f ); } { hkpWorldCinfo cinfo; cinfo.m_gravity.setAll(0); cinfo.m_broadPhaseWorldAabb.m_max.set( m_worldSizeX, 10.0f*m_worldSizeY, m_worldSizeZ); cinfo.m_broadPhaseWorldAabb.m_min.setNeg4( cinfo.m_broadPhaseWorldAabb.m_max ); cinfo.m_useKdTree = true; m_world = new hkpWorld(cinfo); m_world->lock(); } { hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); } // // Create a random batch of boxes in the world // { hkAabb worldAabb; worldAabb.m_max.set( m_worldSizeX, m_worldSizeY, m_worldSizeZ ); worldAabb.m_min.setNeg4( worldAabb.m_max ); hkpMotion::MotionType motionType = hkpMotion::MOTION_SPHERE_INERTIA; hkPseudoRandomGenerator rand(100); KdTreeDemoUtils::createRandomBodies(m_world, worldAabb, 500, motionType, &rand, m_collidables); } setupGraphics(); m_world->unlock(); hkpRayCastQueryJobQueueUtils::registerWithJobQueue(m_jobQueue); m_collIdx = 0; // timer tracking m_monitorHelper = new MultithreadedMonitorHelper(this); m_monitorHelper->trackTimer("KdAabbQueryJob", MultithreadedMonitorHelper::TRACK_FRAME_MAX); m_monitorHelper->trackTimer("KdQueryRecursiveST", MultithreadedMonitorHelper::TRACK_FRAME_MAX); m_monitorHelper->trackTimer("KdQueryIterativeST", MultithreadedMonitorHelper::TRACK_FRAME_MAX); m_monitorHelper->trackTimer("BroadphaseQueryAabb", MultithreadedMonitorHelper::TRACK_FRAME_MAX); }
ConstraintKit2Demo::ConstraintKit2Demo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env, DEMO_FLAGS_NO_SERIALIZE) { // // Setup the camera // { hkVector4 from(0.0f, 5.0f, 15.0f); hkVector4 to (0.0f, 2.0f, 0.0f); hkVector4 up (0.0f, 1.0f, 0.0f); setupDefaultCameras( env, from, to, up ); } // // Create the world // { hkpWorldCinfo info; info.setupSolverInfo(hkpWorldCinfo::SOLVER_TYPE_4ITERS_MEDIUM); info.setBroadPhaseWorldSize( 100.0f ); m_world = new hkpWorld( info ); m_world->lock(); m_world->m_wantDeactivation = false; setupGraphics(); } // // Set up a collision filter so we can disable collision between the objects we constrain together // { hkpGroupFilter* groupFilter = new hkpGroupFilter; hkpGroupFilterSetup::setupGroupFilter( groupFilter ); m_world->setCollisionFilter( groupFilter ); groupFilter->removeReference(); } // // Register the box-box collision agent // { hkpAgentRegisterUtil::registerAllAgents( m_world->getCollisionDispatcher() ); } // // Create a fixed 'floor' box // const hkVector4 floorSize(10.0f, 0.5f, 10.0f); { m_world->addEntity( GameUtils::createBox( floorSize, 0.0f, hkVector4(0,-1,0) ) )->removeReference(); } // We create a 'diagonal line' of boxes; each new box after the first will have // its transform fixed in its initial position (actually expressed as a relative // offset to the previous box). const int numBoxes = 5; { hkpRigidBody* lastBox = 0; for(int boxCount = 0; boxCount < numBoxes; boxCount++) { hkVector4 pos( (hkReal)boxCount - ((hkReal)numBoxes-1) / 2.0f, (hkReal)boxCount, 0.0f); hkpRigidBody* box = GameUtils::createBox(hkVector4(1,1,1),10.0f, pos ); // Set filter info to be in group 1, so all boxes are in same group and don't collide box->setCollisionFilterInfo( hkpGroupFilter::calcFilterInfo(0,1) ); m_world->addEntity(box); box->removeReference(); if( lastBox ) { // If there is a previous box, then we create a constraint between that box, and // the box just added. Here is the code that initially constructs the hkFixedConstraint: hkFixedConstraintData* fixedConstraint = new hkFixedConstraintData(box, lastBox); // Now we set the transform of the attached box in reference box space (the product // of inv(refToWorld) * attToWorld) hkTransform attToRef; { hkTransform refToWorld = lastBox->getTransform(); hkTransform attToWorld = box->getTransform(); attToRef.setMulInverseMul(refToWorld, attToWorld); } // This modifies the internal parameters of the constraint as follows: fixedConstraint->setTransformInRef(attToRef); m_world->createAndAddConstraintInstance(box, lastBox, fixedConstraint)->removeReference(); fixedConstraint->removeReference(); } lastBox = box; } } m_world->unlock(); }
CharacterDemo::CharacterDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { // // Setup the camera // { hkVector4 from( 0.0f, 20.0f, -80.0f); hkVector4 to ( 0.0f, 0.0f, 0.0f); hkVector4 up ( 0.0f, 1.0f, 0.0f); setupDefaultCameras( env, from, to, up ); // disable back face culling setGraphicsState(HKG_ENABLED_CULLFACE, false); // don't really want shadows as makes it too dark forceShadowState(false); setupLights(m_env); // so that the extra lights are added // float lightDir[] = { 0, -0.5f, -1 }; // setSoleDirectionLight(m_env, lightDir, 0xffffffff ); } // // Create the world // { hkpWorldCinfo info; info.setBroadPhaseWorldSize( 350.0f ); info.m_gravity.set(0,0,-9.8f); info.m_collisionTolerance = 0.1f; m_world = new hkpWorld( info ); m_world->lock(); hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); setupGraphics(); } // Load the level { hkVector4 tkScaleFactor(.32f,.32f,.32f); hkString fullname("Resources/Physics/Tk/CharacterController/"); // We load our test case level. //fullname += "testcases.tk"; fullname += "level.tk"; hkpShape* moppShape = GameUtils::loadTK2MOPP(fullname.cString(),tkScaleFactor, -1.0f); HK_ASSERT2(0x64232cc0, moppShape,"TK file failed to load to MOPP in GameUtils::loadTK2MOPP."); hkpRigidBodyCinfo ci; ci.m_shape = moppShape; ci.m_motionType = hkpMotion::MOTION_FIXED; ci.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo( 0, 1 ); hkpRigidBody* entity = new hkpRigidBody(ci); moppShape->removeReference(); m_world->addEntity(entity); entity->removeReference(); } // Add a ladder hkVector4 baseSize( 1.0f, 0.5f, 3.6f); { hkpRigidBodyCinfo rci; rci.m_shape = new hkpBoxShape( baseSize ); rci.m_position.set(3.4f, 8.f, 2); rci.m_motionType = hkpMotion::MOTION_FIXED; hkpRigidBody* ladder = new hkpRigidBody(rci); rci.m_shape->removeReference(); m_world->addEntity(ladder)->removeReference(); // Add a property so we can identify this as a ladder hkpPropertyValue val(1); ladder->addProperty(HK_OBJECT_IS_LADDER, val); // Color the ladder so we can see it clearly HK_SET_OBJECT_COLOR((hkUlong)ladder->getCollidable(), 0x7f1f3f1f); } // // Create a character proxy object // { // Construct a shape hkVector4 vertexA(0,0, 0.4f); hkVector4 vertexB(0,0,-0.4f); // Create a capsule to represent the character standing m_standShape = new hkpCapsuleShape(vertexA, vertexB, .6f); // Create a capsule to represent the character crouching // Note that we create the smaller capsule with the base at the same position as the larger capsule. // This means we can simply swap the shapes without having to reposition the character proxy, // and if the character is standing on the ground, it will still be on the ground. vertexA.setZero4(); m_crouchShape = new hkpCapsuleShape(vertexA, vertexB, .6f); // Construct a Shape Phantom m_phantom = new hkpSimpleShapePhantom( m_standShape, hkTransform::getIdentity(), hkpGroupFilter::calcFilterInfo(0,2) ); // Add the phantom to the world m_world->addPhantom(m_phantom); m_phantom->removeReference(); // Construct a character proxy hkpCharacterProxyCinfo cpci; cpci.m_position.set(-9.1f, 35, .4f); cpci.m_staticFriction = 0.0f; cpci.m_dynamicFriction = 1.0f; cpci.m_up.setNeg4( m_world->getGravity() ); cpci.m_up.normalize3(); cpci.m_userPlanes = 4; cpci.m_maxSlope = HK_REAL_PI / 3.f; cpci.m_shapePhantom = m_phantom; m_characterProxy = new hkpCharacterProxy( cpci ); } // // Add in a custom friction model // { hkVector4 up( 0.f, 0.f, 1.f ); m_listener = new MyCharacterListener(); m_characterProxy->addCharacterProxyListener(m_listener); } // // Create the Character state machine and context // { hkpCharacterState* state; hkpCharacterStateManager* manager = new hkpCharacterStateManager(); state = new hkpCharacterStateOnGround(); manager->registerState( state, HK_CHARACTER_ON_GROUND); state->removeReference(); state = new hkpCharacterStateInAir(); manager->registerState( state, HK_CHARACTER_IN_AIR); state->removeReference(); state = new hkpCharacterStateJumping(); manager->registerState( state, HK_CHARACTER_JUMPING); state->removeReference(); state = new hkpCharacterStateClimbing(); manager->registerState( state, HK_CHARACTER_CLIMBING); state->removeReference(); m_characterContext = new hkpCharacterContext(manager, HK_CHARACTER_ON_GROUND); manager->removeReference(); } // Current camera angle about up m_currentAngle = HK_REAL_PI * 0.5f; m_world->unlock(); }
ChunkMoppDemo::ChunkMoppDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { //setGraphicsState(HKG_ENABLED_WIREFRAME, true); // // Setup the camera // { hkVector4 from(55.0f, 50.0f, 55.0f); hkVector4 to ( 0.0f, 0.0f, 0.0f); hkVector4 up ( 0.0f, 1.0f, 0.0f); setupDefaultCameras(env, from, to, up, 0.1f, 20000.0f); } // // Create the world // { hkpWorldCinfo worldInfo; { worldInfo.m_gravity.set(0.0f, -9.81f, 0.0f); worldInfo.setBroadPhaseWorldSize(10000.0f); worldInfo.setupSolverInfo( hkpWorldCinfo::SOLVER_TYPE_4ITERS_MEDIUM ); worldInfo.m_enableDeactivation = false; } m_world = new hkpWorld(worldInfo); m_world->lock(); // Register ALL agents (though some may not be necessary) hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); setupGraphics(); } hkpShapeCollection* meshShape = createMeshShape( VERTS_PER_SIDE, m_delayedCleanup ); m_shape = createMoppShape( meshShape, true ); m_shape->getAabb( hkTransform::getIdentity(), 0.1f, m_bounds ); // // create the ground mopp // { hkpRigidBodyCinfo terrainInfo; { hkVector4 size(100.0f, 1.0f, 100.0f); terrainInfo.m_shape = m_shape; terrainInfo.m_motionType = hkpMotion::MOTION_FIXED; terrainInfo.m_friction = 0.5f; hkpRigidBody* terrainBody = new hkpRigidBody(terrainInfo); m_world->addEntity(terrainBody); terrainBody->removeReference(); } terrainInfo.m_shape->removeReference(); } hkVector4 halfExtents; hkVector4 centre; { m_bounds.getHalfExtents( halfExtents ); m_bounds.getCenter( centre ); m_minIndex = (halfExtents(0) < halfExtents(1)) ? ((halfExtents(0) < halfExtents(2)) ? 0 : 2) : ((halfExtents(1) < halfExtents(2)) ? 1 : 2) ; } // Setup the camera { hkVector4 up; up.setZero4(); up(m_minIndex) = 1.0f; hkVector4 from; from.setAddMul4( m_bounds.m_max, up, 5.0f); setupDefaultCameras(env, from, centre, up, 0.1f, 10000.0f); } // // Create objects at random coordinates // { hkVector4 size(0.5f, 0.5f, 0.5f); hkpBoxShape* boxShape = new hkpBoxShape(size); hkpRigidBodyCinfo boxInfo; { boxInfo.m_mass = 1.0f; boxInfo.m_shape = boxShape; boxInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA; } hkPseudoRandomGenerator random(15); // // create the boxes // { hkVector4 range; range.setSub4( m_bounds.m_max, m_bounds.m_min ); range.mul4( 1.0f ); const int numObjects = 500; for (int i = 0; i < numObjects; i++) { hkVector4 pos; random.getRandomVector11(pos); pos.mul4(0.1f); pos.mul4(range); pos( m_minIndex ) += m_bounds.m_max( m_minIndex ) + i * (range(m_minIndex)) / numObjects + 4.0f; boxInfo.m_position = pos; hkpRigidBody* shape; shape = new hkpRigidBody(boxInfo); shape->setMaxLinearVelocity( 30 ); m_world->addEntity(shape); shape->removeReference(); } } boxShape->removeReference(); } m_world->unlock(); m_time = 0.0f; }
ThreeWaySqueezeDemo::ThreeWaySqueezeDemo(hkDemoEnvironment* env): hkDefaultPhysicsDemo(env) { // Disable warning hkError::getInstance().setEnabled(0xf0de4356, false); // 'Your m_contactRestingVelocity seems to be too small' // // Setup the camera // { hkVector4 from(0.0f, 10.0f, 10.0f); hkVector4 to (0.0f, 0.0f, 0.0f); hkVector4 up (0.0f, 1.0f, 0.0f); setupDefaultCameras( env, from, to, up ); } // // Create the world // { hkpWorldCinfo info; info.setupSolverInfo( hkpWorldCinfo::SOLVER_TYPE_4ITERS_MEDIUM ); info.setBroadPhaseWorldSize( 350.0f ); info.m_gravity.set(0,-40,0); info.m_collisionTolerance = 0.1f; info.m_numToisTillAllowedPenetrationToi = 1.1f; m_world = new hkpWorld( info ); m_world->lock(); hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); setupGraphics(); } { hkpCollisionFilter* cf = new My3WCollisionFilter(); m_world->setCollisionFilter(cf); cf->removeReference(); } // Build a Base hkVector4 baseSize( 50.0f, 1.0f, 50.0f); { hkpRigidBodyCinfo rci; rci.m_shape = new hkpBoxShape( baseSize ); rci.m_position.set(0.0f, -0.5f, 0.0f); rci.m_motionType = hkpMotion::MOTION_FIXED; // Create a rigid body (using the template above). hkpRigidBody* base = new hkpRigidBody(rci); // Remove reference since the body now "owns" the Shape. rci.m_shape->removeReference(); // Finally add body so we can see it, and remove reference since the world now "owns" it. m_world->addEntity( base )->removeReference(); } // Create a circle of keyframed objects // Each of the objects is given a different increasing priority // We set the priority as a property on the object and extract this i nthe callback. hkVector4 blockerSize(1,3,5); hkpShape* blocker = new hkpBoxShape( blockerSize ); { //hkPseudoRandomGenerator ran(100); for (int b = 0; b < NUM_OBJECTS; b++ ) { hkVector4 up(0,1,0); hkReal angle = hkReal(b) / NUM_OBJECTS * HK_REAL_PI * 2; hkpRigidBodyCinfo rci; rci.m_position.set(5,0,0); rci.m_rotation.setAxisAngle( up, angle ); rci.m_position.setRotatedDir( rci.m_rotation, rci.m_position ); rci.m_shape = blocker; // If we set this to true, the body is fixed, and no mass properties need to be computed. rci.m_motionType = hkpMotion::MOTION_KEYFRAMED; if (b < 1) { rci.m_qualityType = HK_COLLIDABLE_QUALITY_KEYFRAMED; } else { rci.m_qualityType = HK_COLLIDABLE_QUALITY_FIXED; } m_objects[b] = new hkpRigidBody( rci ); m_world->addEntity( m_objects[b] ); m_objects[b]->removeReference(); int color = rci.m_qualityType == HK_COLLIDABLE_QUALITY_FIXED ? hkColor::rgbFromFloats(1.0f, 0.0f, 0.0f, 1.0f) : hkColor::rgbFromFloats(0.0f, 1.0f, 0.0f, 1.0f) ; HK_SET_OBJECT_COLOR((hkUlong)m_objects[b]->getCollidable(), color ); } } blocker->removeReference(); // // Crate middle sphere // { hkpShape* shape = new hkpSphereShape(1.5f); hkpRigidBodyCinfo rbInfo; rbInfo.m_shape = shape; rbInfo.m_qualityType = HK_COLLIDABLE_QUALITY_CRITICAL; hkpRigidBody* body = new hkpRigidBody(rbInfo); m_world->addEntity(body); body->removeReference(); shape->removeReference(); } m_prevObj = 0; // Zero current time at start m_currentTime = 0.0f; m_world->unlock(); }
hkDemo::Result CharacterDemo::stepDemo() { hkVector4 up; hkQuaternion orient; { m_world->lock(); // Get user input data int m_upAxisIndex = 2; up.setZero4(); up(m_upAxisIndex) = 1; hkReal posX = 0.f; hkReal posY = 0.f; { float deltaAngle = 0.f; CharacterUtils::getUserInputForCharacter(m_env, deltaAngle, posX, posY); m_currentAngle += deltaAngle; orient.setAxisAngle(up, m_currentAngle); } hkpCharacterInput input; hkpCharacterOutput output; { input.m_inputLR = posX; input.m_inputUD = posY; input.m_wantJump = m_env->m_window->getMouse().wasButtonPressed(HKG_MOUSE_LEFT_BUTTON) || m_env->m_gamePad->wasButtonPressed(HKG_PAD_BUTTON_1); input.m_atLadder = m_listener->m_atLadder; input.m_up = up; input.m_forward.set(1,0,0); input.m_forward.setRotatedDir( orient, input.m_forward ); input.m_stepInfo.m_deltaTime = m_timestep; input.m_stepInfo.m_invDeltaTime = 1.0f / m_timestep; input.m_characterGravity.set(0,0,-16); input.m_velocity = m_characterProxy->getLinearVelocity(); input.m_position = m_characterProxy->getPosition(); if (m_listener->m_atLadder) { hkVector4 right, ladderUp; right.setCross( up, m_listener->m_ladderNorm ); ladderUp.setCross( m_listener->m_ladderNorm, right ); // Calculate the up vector for the ladder if (ladderUp.lengthSquared3() > HK_REAL_EPSILON) { ladderUp.normalize3(); } // Reorient the forward vector so it points up along the ladder input.m_forward.addMul4( -m_listener->m_ladderNorm.dot3(input.m_forward), m_listener->m_ladderNorm); input.m_forward.add4( ladderUp ); input.m_forward.normalize3(); input.m_surfaceNormal = m_listener->m_ladderNorm; input.m_surfaceVelocity = m_listener->m_ladderVelocity; } else { hkVector4 down; down.setNeg4(up); hkpSurfaceInfo ground; m_characterProxy->checkSupport(down, ground); input.m_isSupported = ground.m_supportedState == hkpSurfaceInfo::SUPPORTED; input.m_surfaceNormal = ground.m_surfaceNormal; input.m_surfaceVelocity = ground.m_surfaceVelocity; } } // 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 ); // Feed output from state machine into character proxy m_characterProxy->setLinearVelocity(output.m_velocity); hkStepInfo si; si.m_deltaTime = m_timestep; si.m_invDeltaTime = 1.0f/m_timestep; m_characterProxy->integrate( si, m_world->getGravity() ); HK_TIMER_END(); } // 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; case HK_CHARACTER_CLIMBING: stateStr = "Climbing"; break; default: stateStr = "Other"; break; } char buffer[255]; hkString::snprintf(buffer, 255, "State : %s", stateStr); m_env->m_textDisplay->outputText(buffer, 20, 270, 0xffffffff); } // // Handle crouching // { hkBool wantCrouch = ( m_env->m_window->getMouse().getButtonState() & HKG_MOUSE_RIGHT_BUTTON ) || (m_env->m_gamePad->getButtonState() & HKG_PAD_BUTTON_2); hkBool isCrouching = m_phantom->getCollidable()->getShape() == m_crouchShape; // We want to stand if (isCrouching && !wantCrouch) { swapPhantomShape(m_standShape); } // We want to crouch if (!isCrouching && wantCrouch) { swapPhantomShape(m_crouchShape); } } m_world->unlock(); } // Step the world hkDefaultPhysicsDemo::stepDemo(); // Camera Handling { m_world->lock(); { const hkReal height = .7f; hkVector4 forward; forward.set(1,0,0); forward.setRotatedDir( orient, forward ); hkVector4 from, to; to = m_characterProxy->getPosition(); to.addMul4(height, up); hkVector4 dir; dir.setMul4( height, up ); dir.addMul4( -4.f, forward); from.setAdd4(to, dir); setupDefaultCameras(m_env, from, to, up, 1.0f); } m_world->unlock(); } return hkDemo::DEMO_OK; }
BrickWallDemo::BrickWallDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { // Disable warnings: hkError::getInstance().setEnabled(0xaf55adde, false); //'No runtime block of size 637136 currently available. Allocating new block from unmanaged memory.' hkDefaultPhysicsDemo::enableDisplayingToiInformation( true ); m_frameToSimulationFrequencyRatio = 1.0f; m_timestep = 1.0f / 60.0f; const BrickWallVariant& variant = g_variants[m_variantId]; int wallHeight = variant.m_height; int wallWidth = variant.m_width; int numWalls = variant.m_numWalls; hkpWorldCinfo::SimulationType simulationType; simulationType = hkpWorldCinfo::SIMULATION_TYPE_CONTINUOUS; // // Setup the camera so that we can see the ball hit the (first) wall. // { hkVector4 from(40.0f, 20.0f, 40.0f); hkVector4 to ( 0.0f, 10.0f, 0.0f); hkVector4 up ( 0.0f, 1.0f, 0.0f); setupDefaultCameras( env, from, to, up ); } { hkpWorldCinfo info; info.setBroadPhaseWorldSize( 5000.0f ); info.setupSolverInfo(hkpWorldCinfo::SOLVER_TYPE_4ITERS_HARD); info.m_collisionTolerance = 0.01f; info.m_gravity = hkVector4( 0.0f,-9.8f,0.0f); info.m_simulationType = simulationType; info.m_broadPhaseBorderBehaviour = info.BROADPHASE_BORDER_FIX_ENTITY; //info.m_enableDeactivation = false; //info.m_enableSimulationIslands = false; info.m_enableDeactivation = false; m_world = new hkpWorld( info ); m_world->lock(); } { // Register ALL agents (though some may not be necessary) hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); setupGraphics(); // enable instancing (if present on platform) hkpShapeDisplayViewer* shapeViewer = (hkpShapeDisplayViewer*)getLocalViewerByName( hkpShapeDisplayViewer::getName() ); if (shapeViewer) { shapeViewer->setInstancingEnabled( true ); } } // // Create the ground box // { hkVector4 groundRadii( 70.0f, 2.0f, 70.0f ); hkpConvexShape* shape = new hkpBoxShape( groundRadii , 0 ); hkpRigidBodyCinfo ci; ci.m_shape = shape; ci.m_motionType = hkpMotion::MOTION_FIXED; ci.m_position = hkVector4( 0.0f, -2.0f, 0.0f ); ci.m_qualityType = HK_COLLIDABLE_QUALITY_FIXED; m_world->addEntity( new hkpRigidBody( ci ) )->removeReference(); shape->removeReference(); } hkVector4 groundPos( 0.0f, 0.0f, 0.0f ); hkVector4 posy = groundPos; // // Create the walls // if(1) { hkVector4 boxSize( 1.0f, 0.5f, 0.5f); hkpBoxShape* box = new hkpBoxShape( boxSize , 0 ); box->setRadius( 0.0f ); hkReal deltaZ = 25.0f; posy(2) = -deltaZ * numWalls * 0.5f; for ( int y = 0; y < numWalls; y ++ ) // first wall { createBrickWall( m_world, wallHeight, wallWidth, posy, 0.2f, box, boxSize ); posy(2) += deltaZ; } box->removeReference(); } // // Create the ball // if (1) { const hkReal radius = 1.5f; const hkReal sphereMass = 150.0f; hkVector4 relPos( 0.0f,radius + 0.0f, 20.0f ); hkpRigidBodyCinfo info; hkpMassProperties massProperties; hkpInertiaTensorComputer::computeSphereVolumeMassProperties(radius, sphereMass, massProperties); info.m_mass = massProperties.m_mass; info.m_centerOfMass = massProperties.m_centerOfMass; info.m_inertiaTensor = massProperties.m_inertiaTensor; info.m_shape = new hkpSphereShape( radius ); info.m_position.setAdd4(posy, relPos ); info.m_motionType = hkpMotion::MOTION_BOX_INERTIA; if ( variant.m_usePredictive) { info.m_qualityType = HK_COLLIDABLE_QUALITY_BULLET; } else { info.m_qualityType = HK_COLLIDABLE_QUALITY_DEBRIS; } hkpRigidBody* sphereRigidBody = new hkpRigidBody( info ); m_world->addEntity( sphereRigidBody ); sphereRigidBody->removeReference(); info.m_shape->removeReference(); hkVector4 vel( 0.0f,4.9f, -200.0f ); sphereRigidBody->setLinearVelocity( vel ); } m_world->unlock(); }
HingeHittingTableDemo::HingeHittingTableDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { // Disable warnings: hkError::getInstance().setEnabled(0xafe97523, false); //'This utility is intended primarily for Havok demo use. If you wish to step the world asynchronously,...' enableDisplayingToiInformation(true); // // Setup the camera // { hkVector4 from( 0, 0, 10); hkVector4 to ( 0, 0, 0); hkVector4 up ( 0, 1, 0); setupDefaultCameras(env, from, to, up); } // // Setup and create the hkpWorld // { hkpWorldCinfo info; info.setBroadPhaseWorldSize(150.0f); info.m_collisionTolerance = .03f; info.m_gravity.setZero4(); info.m_simulationType = info.SIMULATION_TYPE_CONTINUOUS; m_world = new hkpWorld( info ); m_world->lock(); hkpAgentRegisterUtil::registerAllAgents( m_world->getCollisionDispatcher() ); setupGraphics(); } const HingeHittingTableDemoVariant& variant = g_variants[this->m_variantId]; // // Collision Filter // { hkpGroupFilter* filter = new hkpGroupFilter(); hkpGroupFilterSetup::setupGroupFilter( filter ); m_world->setCollisionFilter(filter); filter->disableCollisionsBetween(30,30); filter->removeReference(); } // Create a box { hkReal mass = 0.0f; hkVector4 size( 2.0f, 0.2f, 2.0f ); hkVector4 position( 1.0f, 0.0f, 0.0f ); hkpRigidBody* body = HK_NULL; if( 1 ) { // use a hkpBoxShape body = GameUtils::createBox( size, mass, position ); } else { // use a hkpConvexVerticesShape body = GameUtils::createConvexVerticesBox( size, mass, position ); } body->setName("table0"); m_world->addEntity( body )->removeReference(); } hkVector4 pos(-2.0f, 0.0f, 0.0f); hkVector4 vel(45.0f, 0.0f, 0.0f); switch(variant.m_sceneType) { case VARIANT_HINGE: createHinge(m_world, variant.m_objectQualityType, variant.m_constraintPriorityLevel, pos, vel); break; case VARIANT_RAGDOLL: case VARIANT_RAGDOLL_INCREASED_INERTIA: createRagdoll(m_world, variant.m_objectQualityType, variant.m_constraintPriorityLevel, pos, vel, variant.m_sceneType); break; } m_world->unlock(); }
BindingDemo::BindingDemo( hkDemoEnvironment* env ) : hkDefaultAnimationDemo(env) { // // Setup the camera // { hkVector4 from( 0, -2.5f, 0.0f ); hkVector4 to ( 0,0,0 ); hkVector4 up ( 0,0,1 ); setupDefaultCameras( env, from, to, up ); } m_loader = new hkLoader(); // Get the rig { hkString assetFile = hkAssetManagementUtil::getFilePath("Resources/Animation/HavokGirl/hkRig.hkx"); hkRootLevelContainer* container = m_loader->load( assetFile.cString() ); HK_ASSERT2(0x27343437, container != HK_NULL , "Could not load asset"); hkaAnimationContainer* ac = reinterpret_cast<hkaAnimationContainer*>( container->findObjectByType( hkaAnimationContainerClass.getName() )); HK_ASSERT2(0x27343435, ac && (ac->m_numSkeletons > 0), "No skeleton loaded"); m_skeleton = ac->m_skeletons[0]; } // Get the animations and the binding { hkString assetFile = hkAssetManagementUtil::getFilePath("Resources/Animation/HavokGirl/hkIdle.hkx"); hkRootLevelContainer* container = m_loader->load( assetFile.cString() ); HK_ASSERT2(0x27343437, container != HK_NULL , "Could not load asset"); hkaAnimationContainer* ac = reinterpret_cast<hkaAnimationContainer*>( container->findObjectByType( hkaAnimationContainerClass.getName() )); HK_ASSERT2(0x27343435, ac && (ac->m_numAnimations > 0 ), "No animation loaded"); m_animation[0] = ac->m_animations[0]; HK_ASSERT2(0x27343435, ac && (ac->m_numBindings > 0), "No binding loaded"); m_binding[0] = ac->m_bindings[0]; assetFile = hkAssetManagementUtil::getFilePath("Resources/Animation/HavokGirl/hkWaveLoop.hkx"); container = m_loader->load( assetFile.cString() ); ac = reinterpret_cast<hkaAnimationContainer*>( container->findObjectByType( hkaAnimationContainerClass.getName() )); HK_ASSERT2(0x27343435, ac && (ac->m_numAnimations > 0 ), "No animation loaded"); m_animation[1] = ac->m_animations[0]; HK_ASSERT2(0x27343435, ac && (ac->m_numBindings > 0), "No binding loaded"); m_binding[1] = ac->m_bindings[0]; } // Create the skeleton m_skeletonInstance = new hkaAnimatedSkeleton( m_skeleton ); // If the weight on any bone drops below this then it is filled with the T-Pose m_skeletonInstance->setReferencePoseWeightThreshold(0.1f); // Grab the animations for (int i=0; i < NUM_ANIMS; i++) { m_control[i] = new hkaDefaultAnimationControl( m_binding[i] ); m_control[i]->setMasterWeight( 0.0f ); m_control[i]->setPlaybackSpeed( 1.0f ); m_skeletonInstance->addAnimationControl( m_control[i] ); m_control[i]->removeReference(); } // make a world so that we can auto create a display world to hold the skin setupGraphics( ); }
CollisionEventsDemo::CollisionEventsDemo( hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { // // Setup the camera // { hkVector4 from(3.0f, 4.0f, 8.0f); hkVector4 to(0.0f, 1.0f, 0.0f); hkVector4 up(0.0f, 1.0f, 0.0f); setupDefaultCameras( env, from, to, up ); } // // Create the world // { hkpWorldCinfo info; info.setupSolverInfo(hkpWorldCinfo::SOLVER_TYPE_4ITERS_MEDIUM); info.setBroadPhaseWorldSize( 100.0f ); info.m_simulationType = info.SIMULATION_TYPE_CONTINUOUS; // Turn off deactivation so we can see continuous contact point processing info.m_enableDeactivation = false; m_world = new hkpWorld( info ); m_world->lock(); setupGraphics(); } // // Register the box-box collision agent // { hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); } // // Create the floor // { hkpRigidBodyCinfo info; hkVector4 fixedBoxSize(5.0f, 0.5f , 5.0f ); hkpBoxShape* fixedBoxShape = new hkpBoxShape( fixedBoxSize , 0 ); info.m_shape = fixedBoxShape; info.m_motionType = hkpMotion::MOTION_FIXED; info.m_position.setZero4(); // Add some bounce. info.m_restitution = 0.8f; info.m_friction = 1.0f; // Create fixed box hkpRigidBody* floor = new hkpRigidBody(info); m_world->addEntity(floor); floor->removeReference(); fixedBoxShape->removeReference(); } // For this demo we simply have two box shapes which are constructed in the usual manner using a hkpRigidBodyCinfo 'blueprint'. // The dynamic box creation code in presented below. There are two key things to note in this example; // the 'm_restitution' member variable, which we have explicitly set to value of 0.9. // The restitution is over twice the default value of // 0.4 and is set to give the box (the floor has been set likewise) a more 'bouncy' nature. // // Create a moving box // { hkpRigidBodyCinfo boxInfo; hkVector4 boxSize( .5f, .5f ,.5f ); boxInfo.m_shape = new hkpBoxShape( boxSize , 0 ); // Compute the box inertia tensor hkpInertiaTensorComputer::setShapeVolumeMassProperties( boxInfo.m_shape, 1.0f, boxInfo ); boxInfo.m_qualityType = HK_COLLIDABLE_QUALITY_DEBRIS; boxInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA; // Place the box so it bounces interestingly boxInfo.m_position.set(0.0f, 5.0f, 0.0f); hkVector4 axis(1.0f, 2.0f, 3.0f); axis.normalize3(); boxInfo.m_rotation.setAxisAngle(axis, -0.7f); // Add some bounce. boxInfo.m_restitution = 0.5f; boxInfo.m_friction = 0.1f; hkpRigidBody* boxRigidBody = new hkpRigidBody( boxInfo ); // remove reference from boxShape since rigid body "owns" it boxInfo.m_shape->removeReference(); m_world->addEntity( boxRigidBody ); boxRigidBody->removeReference(); // Add the collision event listener to the rigid body MyCollisionListener* listener = new MyCollisionListener( boxRigidBody ); listener->m_reportLevel = m_env->m_reportingLevel; } m_world->unlock(); }
AdditiveBlendingDemo::AdditiveBlendingDemo( hkDemoEnvironment* env ) : hkDefaultAnimationDemo(env) { // Disable warnings: if no renderer if( hkString::strCmp( m_env->m_options->m_renderer, "n" ) == 0 ) { hkError::getInstance().setEnabled(0xf0d1e423, false); //'Could not realize an inplace texture of type PNG.' } // // Setup the camera // { hkVector4 from( 0.3f, -1, 1 ); hkVector4 to ( 0, 0, 0.5f ); hkVector4 up ( 0.0f, 0.0f, 1.0f ); setupDefaultCameras( env, from, to, up, 0.1f, 100 ); } m_loader = new hkLoader(); // Convert the scene { hkString assetFile = hkAssetManagementUtil::getFilePath("Resources/Animation/Scene/hkScene.hkx"); hkRootLevelContainer* container = m_loader->load( assetFile.cString() ); HK_ASSERT2(0x27343437, container != HK_NULL , "Could not load asset"); hkxScene* scene = reinterpret_cast<hkxScene*>( container->findObjectByType( hkxSceneClass.getName() )); HK_ASSERT2(0x27343635, scene, "No scene loaded"); removeLights(m_env); env->m_sceneConverter->convert( scene ); } // Get the rig { hkString assetFile = hkAssetManagementUtil::getFilePath("Resources/Animation/HavokGirl/hkRig.hkx"); hkRootLevelContainer* container = m_loader->load( assetFile.cString() ); HK_ASSERT2(0x27343437, container != HK_NULL , "Could not load asset"); hkaAnimationContainer* ac = reinterpret_cast<hkaAnimationContainer*>( container->findObjectByType( hkaAnimationContainerClass.getName() )); HK_ASSERT2(0x27343435, ac && (ac->m_numSkeletons > 0), "No skeleton loaded"); m_skeleton = ac->m_skeletons[0]; } // Get the animations and the binding { hkString assetFile = hkAssetManagementUtil::getFilePath("Resources/Animation/HavokGirl/hkWalkLoop.hkx"); hkRootLevelContainer* container = m_loader->load( assetFile.cString() ); HK_ASSERT2(0x27343437, container != HK_NULL , "Could not load asset"); hkaAnimationContainer* ac = reinterpret_cast<hkaAnimationContainer*>( container->findObjectByType( hkaAnimationContainerClass.getName() )); HK_ASSERT2(0x27343435, ac && (ac->m_numAnimations > 0 ), "No animation loaded"); m_animation[HK_WALK_ANIM] = ac->m_animations[0]; HK_ASSERT2(0x27343435, ac && (ac->m_numBindings > 0), "No binding loaded"); m_binding[HK_WALK_ANIM] = ac->m_bindings[0]; assetFile = hkAssetManagementUtil::getFilePath("Resources/Animation/HavokGirl/hkHeadMovement.hkx"); container = m_loader->load( assetFile.cString() ); ac = reinterpret_cast<hkaAnimationContainer*>( container->findObjectByType( hkaAnimationContainerClass.getName() )); HK_ASSERT2(0x27343435, ac && (ac->m_numAnimations > 0 ), "No animation loaded"); m_animation[HK_ADDITIVE_ANIM] = ac->m_animations[0]; HK_ASSERT2(0x27343435, ac && (ac->m_numBindings > 0), "No binding loaded"); m_binding[HK_ADDITIVE_ANIM] = ac->m_bindings[0]; } // Create an additive animation // This can also be done offline in the toolchain using the CreateAdditiveAnimation filter // See the Additive configuration of hkHeadMovement.max { hkaInterleavedUncompressedAnimation* interleavedAnim = static_cast< hkaInterleavedUncompressedAnimation* >(m_animation[ HK_ADDITIVE_ANIM ]); hkaAdditiveAnimationUtility::Input input; input.m_originalData = interleavedAnim->m_transforms; input.m_numberOfPoses = interleavedAnim->m_numTransforms / interleavedAnim->m_numberOfTransformTracks; input.m_numberOfTransformTracks = interleavedAnim->m_numberOfTransformTracks; input.m_baseData = interleavedAnim->m_transforms; // We create an additive animation by subtracting off the iniital pose for the first frame of the animation // This is done by passing the same animation for both the originalData and the baseData // Note that only the first frame of the basedata is used so this initial frame is subtracted // from each of the frames in the animation hkaAdditiveAnimationUtility::createAdditiveFromPose( input, interleavedAnim->m_transforms ); // Switch the binding to additive so this animation will be blended differently in sample and combine. m_binding[HK_ADDITIVE_ANIM]->m_blendHint = hkaAnimationBinding::ADDITIVE; } // Convert the skin { const char* skinFile = "Resources/Animation/HavokGirl/hkLowResSkinWithEyes.hkx"; hkString assetFile = hkAssetManagementUtil::getFilePath( skinFile ); hkRootLevelContainer* container = m_loader->load( assetFile.cString() ); HK_ASSERT2(0x27343437, container != HK_NULL , "Could not load asset"); hkxScene* scene = reinterpret_cast<hkxScene*>( container->findObjectByType( hkxSceneClass.getName() )); HK_ASSERT2(0x27343435, scene , "No scene loaded"); hkaAnimationContainer* ac = reinterpret_cast<hkaAnimationContainer*>( container->findObjectByType( hkaAnimationContainerClass.getName() )); HK_ASSERT2(0x27343435, ac && (ac->m_numSkins > 0), "No animation loaded"); m_numSkinBindings = ac->m_numSkins; m_skinBindings = ac->m_skins; m_numAttachments = ac->m_numAttachments; m_attachments = ac->m_attachments; // Make graphics output buffers for the skins env->m_sceneConverter->convert( scene ); for (int a=0; a < m_numAttachments; ++a) { hkaBoneAttachment* ba = m_attachments[a]; hkgDisplayObject* hkgObject = HK_NULL; //Check the attachment is a mesh if ( hkString::strCmp(ba->m_attachment.m_class->getName(), hkxMeshClass.getName()) == 0) { hkgObject = env->m_sceneConverter->findFirstDisplayObjectUsingMesh((hkxMesh*)ba->m_attachment.m_object); if (hkgObject) { hkgObject->setStatusFlags( hkgObject->getStatusFlags() | HKG_DISPLAY_OBJECT_DYNAMIC); } } m_attachmentObjects.pushBack(hkgObject); } } // Create the animated skeleton m_skeletonInstance = new hkaAnimatedSkeleton( m_skeleton ); // Set the fill threshold m_skeletonInstance->setReferencePoseWeightThreshold( 0.05f ); // Grab the animations and build controls for (int i=0; i < NUM_ANIMS; i++) { m_control[i] = new hkaDefaultAnimationControl( m_binding[i] ); m_control[i]->setMasterWeight( 1.0f ); m_control[i]->setPlaybackSpeed( 1.0f ); m_skeletonInstance->addAnimationControl( m_control[i] ); m_control[i]->removeReference(); } // We initially turn the additive animation off and allow the user to ramp it in m_control[HK_ADDITIVE_ANIM]->setMasterWeight( 0.0f ); m_control[HK_ADDITIVE_ANIM]->setPlaybackSpeed( 1.0f ); setupGraphics( ); }
SimpleShapesDemo::SimpleShapesDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { const ShapeVariant& variant = g_variants[m_variantId]; // Setup the camera. { hkVector4 from(0.0f, 5.0f, 10.0f); hkVector4 to (0.0f, 0.0f, 0.0f); hkVector4 up (0.0f, 1.0f, 0.0f); setupDefaultCameras(env, from, to, up); } // Create the world, setting gravity to zero so body floats. hkpWorldCinfo info; info.m_gravity.set(0.0f, 0.0f, 0.0f); info.setBroadPhaseWorldSize( 100.0f ); m_world = new hkpWorld(info); m_world->lock(); setupGraphics(); // Create the shape variant hkpShape* shape = 0; switch (variant.m_shapeType) { // Box case HK_SHAPE_BOX: { // Data specific to this shape. hkVector4 halfExtents(1.0f, 1.0f, 1.0f); /////////////////// SHAPE CONSTRUCTION //////////////// shape = new hkpBoxShape(halfExtents, 0 ); break; } // Sphere case HK_SHAPE_SPHERE: { // The box is of side 2, so we must bound it by a sphere of radius >= sqrt(3) hkReal radius = 1.75f; /////////////////// SHAPE CONSTRUCTION //////////////// shape = new hkpSphereShape(radius); break; } // Triangle case HK_SHAPE_TRIANGLE: { // Disable face culling setGraphicsState(HKG_ENABLED_CULLFACE, false); float vertices[] = { -0.5f, -0.5f, 0.0f, 0.0f, // v0 0.5f, -0.5f, 0.0f, 0.0f, // v1 0.0f, 0.5f, 0.0f, 0.0f, // v2 }; /////////////////// SHAPE CONSTRUCTION //////////////// shape = new hkpTriangleShape(); int index = 0; for (int i = 0; i < 3; i++) { static_cast<hkpTriangleShape*>(shape)->setVertex(i, hkVector4(vertices[index], vertices[index + 1], vertices[index + 2])); index = index + 4; } break; } // Capsule case HK_SHAPE_CAPSULE: { hkReal radius = 1.5f; hkVector4 top(0.0f, 1.5f, 0.0f); hkVector4 bottom(0.0f, -1.0f, 0.0f); /////////////////// SHAPE CONSTRUCTION //////////////// shape = new hkpCapsuleShape(top, bottom, radius); break; } // Cylinder case HK_SHAPE_CYLINDER: { hkReal radius = 1.5f; hkVector4 top(0.0f, 1.5f, 0.0f); hkVector4 bottom(0.0f, -1.0f, 0.0f); /////////////////// SHAPE CONSTRUCTION //////////////// shape = new hkpCylinderShape(top, bottom, radius); break; } // Convex vertices case HK_SHAPE_CONVEX_VERTICES: { // Data specific to this shape. int numVertices = 4; // 16 = 4 (size of "each float group", 3 for x,y,z, 1 for padding) * 4 (size of float) int stride = sizeof(float) * 4; float vertices[] = { // 4 vertices plus padding -2.0f, 2.0f, 1.0f, 0.0f, // v0 1.0f, 3.0f, 0.0f, 0.0f, // v1 0.0f, 1.0f, 3.0f, 0.0f, // v2 1.0f, 0.0f, 0.0f, 0.0f // v3 }; /////////////////// SHAPE CONSTRUCTION //////////////// hkStridedVertices stridedVerts; { stridedVerts.m_numVertices = numVertices; stridedVerts.m_striding = stride; stridedVerts.m_vertices = vertices; } shape = new hkpConvexVerticesShape(stridedVerts); break; } default: break; } // Make sure that a shape was created HK_ASSERT(0, shape); // To illustrate using the shape, first define a rigid body template. hkpRigidBodyCinfo rigidBodyInfo; rigidBodyInfo.m_position.set(0.0f, 0.0f, 0.0f); rigidBodyInfo.m_angularDamping = 0.0f; rigidBodyInfo.m_linearDamping = 0.0f; rigidBodyInfo.m_shape = shape; // Compute the rigid body inertia. rigidBodyInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA; hkpInertiaTensorComputer::setShapeVolumeMassProperties( rigidBodyInfo.m_shape, 100.0f, rigidBodyInfo ); // Create a rigid body (using the template above). hkpRigidBody* rigidBody = new hkpRigidBody(rigidBodyInfo); // Remove reference since the body now "owns" the Shape. shape->removeReference(); // Finally add body so we can see it, and remove reference since the world now "owns" it. m_world->addEntity(rigidBody); rigidBody->removeReference(); m_world->unlock(); }
BreakOffPartsAndSpuDemo::BreakOffPartsAndSpuDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { m_list0 = m_list1 = HK_NULL; m_debugViewerNames.pushBack( hkpMidphaseViewer::getName() ); m_bootstrapIterations = 150; const BreakOffPartsAndSpuVariant& variant = g_variants[m_variantId]; // // Setup the camera // { hkVector4 from(0.0f, 35.0f, -50.0f); hkVector4 to (0.0f, 0.0f, 0.0f); hkVector4 up (0.0f, 1.0f, 0.0f); setupDefaultCameras( env, from, to, up ); } // // Create the world // { hkpWorldCinfo info; info.m_gravity.set(0.0f, -9.8f, 0.0f); if ( variant.m_type == BREAK_OFF_PARTS_DEMO_COLLISION_RESPONSE) { info.m_contactRestingVelocity = 0.5f; } m_world = new hkpWorld( info ); m_world->lock(); hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); setupGraphics(); } // // Create the break off utility // { m_breakUtil = new hkpBreakOffPartsUtil( m_world, this ); } // Create ground // { hkVector4 size (100.0f, 1.0f, 100.0f); hkReal mass = 0.0f; hkVector4 position (0.0f, -0.5f, 0.0f); hkpRigidBody* ground = GameUtils::createBox(size, mass, position); m_world->addEntity(ground); ground->removeReference(); } // Create two big shapes // { hkVector4 size(0.5f, 0.5f, 0.5f); hkReal radius = 0.02f; hkReal dist = size(0)*2.0f + radius + 0.1f; hkArray<hkpConvexShape*> shapes; shapes.reserve(400); { hkpBoxShape* terminal = new hkpBoxShape(size, radius); int dim = 20; for (int i = 0; i < dim; i++) { for (int j = (i+1)%2; j < dim; j+=2) { hkTransform transform = hkTransform::getIdentity(); hkReal offset = (hkReal(dim)-1.0f)*-0.5f; transform.setTranslation(hkVector4( (offset+hkReal(i))*dist, (offset+hkReal(j))*dist, 0.0f)); hkpConvexTransformShape* cts = new hkpConvexTransformShape(terminal, transform); shapes.pushBack(cts); } } terminal->removeReference(); } // Create new list/mesh shape // hkpShapeCollection* collectionShape0; hkpShapeCollection* collectionShape1; if (!variant.m_useMeshCollection) { collectionShape0 = m_list0 = new hkpListShape(reinterpret_cast<hkpShape**>(static_cast<hkpConvexShape**>(shapes.begin())), shapes.getSize()); collectionShape1 = m_list1 = new hkpListShape(reinterpret_cast<hkpShape**>(static_cast<hkpConvexShape**>(shapes.begin())), shapes.getSize()); if (variant.m_extraListInHierarchy) { collectionShape0 = new hkpListShape((hkpShape**)&collectionShape0, 1); collectionShape1 = new hkpListShape((hkpShape**)&collectionShape1, 1); m_list0->removeReference(); m_list1->removeReference(); } } else { // This is a share shape because it's not destructible hkpExtendedMeshShape* meshShape = new hkpExtendedMeshShape(radius); collectionShape0 = meshShape; collectionShape1 = meshShape; hkpExtendedMeshShape::ShapesSubpart part(shapes.begin(), shapes.getSize()); meshShape->addShapesSubpart(part); // Add a reference to meshShape. // collectionShape0 and collectionShape1 both reference it, which means there has to be a second reference to remove later. meshShape->addReference(); } hkReferencedObject::removeReferences(shapes.begin(), shapes.getSize()); // Wrap it with a mopp // hkpShape* finalShape0 = collectionShape0; hkpShape* finalShape1 = collectionShape1; if (variant.m_useMopp) { hkpMoppCompilerInput mci; mci.m_enableChunkSubdivision = true; hkpMoppCode* code0 = hkpMoppUtility::buildCode( collectionShape0->getContainer(),mci); hkpMoppCode* code1 = hkpMoppUtility::buildCode( collectionShape1->getContainer(),mci); finalShape0 = new hkpMoppBvTreeShape( collectionShape0, code0 ); finalShape1 = new hkpMoppBvTreeShape( collectionShape1, code1 ); code0->removeReference(); code1->removeReference(); collectionShape0->removeReference(); collectionShape1->removeReference(); } // finally add create two bodies with the shape // { hkpRigidBodyCinfo info; info.m_shape = finalShape0; hkpInertiaTensorComputer::setShapeVolumeMassProperties(finalShape0, 10.0f, info); info.m_motionType = hkpMotion::MOTION_DYNAMIC; info.m_numUserDatasInContactPointProperties = 1; info.m_position.set(0.0f, 15.0f, 0.0f); m_body0 = new hkpRigidBody(info); info.m_rotation.setAxisAngle(hkVector4(0.0f,1.0f, 0.0f), 90.0f * HK_REAL_DEG_TO_RAD); info.m_position(0) += dist; info.m_shape = finalShape1; if (variant.m_fixOneBody) { info.m_motionType = hkpMotion::MOTION_FIXED; } m_body1 = new hkpRigidBody(info); finalShape0->removeReference(); finalShape1->removeReference(); m_world->addEntity(m_body0); m_world->addEntity(m_body1); } } // Mark bodies breakable // if (variant.m_useMeshCollection != 1 && variant.m_extraListInHierarchy != 1) { m_breakUtil->markEntityBreakable(m_body0, 1.0f); m_breakUtil->markEntityBreakable(m_body1, 1.0f); } m_world->unlock(); }