void GLDebugDrawer::DrawLine(const SimdVector3& from,const SimdVector3& to,const SimdVector3& color) { if (m_debugMode > 0) { glBegin(GL_LINES); glColor3f(color.getX(), color.getY(), color.getZ()); glVertex3d(from.getX(), from.getY(), from.getZ()); glVertex3d(to.getX(), to.getY(), to.getZ()); glEnd(); } }
void GLDebugDrawer::DrawContactPoint(const SimdVector3& pointOnB,const SimdVector3& normalOnB,float distance,int lifeTime,const SimdVector3& color) { if (m_debugMode & IDebugDraw::DBG_DrawContactPoints) { SimdVector3 to=pointOnB+normalOnB*distance; const SimdVector3&from = pointOnB; glBegin(GL_LINES); glColor3f(color.getX(), color.getY(), color.getZ()); glVertex3d(from.getX(), from.getY(), from.getZ()); glVertex3d(to.getX(), to.getY(), to.getZ()); glEnd(); glRasterPos3f(from.x(), from.y(), from.z()); char buf[12]; sprintf(buf," %d",lifeTime); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); } }
void AxisSweep3::Quantize(unsigned short* out, const SimdPoint3& point, int isMax) const { SimdPoint3 clampedPoint(point); /* if (isMax) clampedPoint += SimdVector3(10,10,10); else { clampedPoint -= SimdVector3(10,10,10); } */ clampedPoint.setMax(m_worldAabbMin); clampedPoint.setMin(m_worldAabbMax); SimdVector3 v = (clampedPoint - m_worldAabbMin) * m_quantize; out[0] = (unsigned short)(((int)v.getX() & 0xfffc) | isMax); out[1] = (unsigned short)(((int)v.getY() & 0xfffc) | isMax); out[2] = (unsigned short)(((int)v.getZ() & 0xfffc) | isMax); }
bool Epa::Initialize( SimplexSolverInterface& simplexSolver ) { // Run GJK on the enlarged shapes to obtain a simplex of the enlarged CSO SimdVector3 v( 1, 0, 0 ); SimdScalar squaredDistance = SIMD_INFINITY; SimdScalar delta = 0.f; simplexSolver.reset(); int nbIterations = 0; while ( true ) { EPA_DEBUG_ASSERT( ( v.length2() > 0 ) ,"Warning : v has zero magnitude!" ); SimdVector3 seperatingAxisInA = -v * m_transformA.getBasis(); SimdVector3 seperatingAxisInB = v * m_transformB.getBasis(); SimdVector3 pInA = m_pConvexShapeA->LocalGetSupportingVertex( seperatingAxisInA ); SimdVector3 qInB = m_pConvexShapeB->LocalGetSupportingVertex( seperatingAxisInB ); SimdPoint3 pWorld = m_transformA( pInA ); SimdPoint3 qWorld = m_transformB( qInB ); SimdVector3 w = pWorld - qWorld; delta = v.dot( w ); EPA_DEBUG_ASSERT( ( delta <= 0 ) ,"Shapes are disjoint, EPA should have never been called!" ); if ( delta > 0.f ) return false; EPA_DEBUG_ASSERT( !simplexSolver.inSimplex( w ) ,"Shapes are disjoint, EPA should have never been called!" ); if (simplexSolver.inSimplex( w )) return false; // Add support point to simplex simplexSolver.addVertex( w, pWorld, qWorld ); bool closestOk = simplexSolver.closest( v ); EPA_DEBUG_ASSERT( closestOk ,"Shapes are disjoint, EPA should have never been called!" ); if (!closestOk) return false; SimdScalar prevVSqrd = squaredDistance; squaredDistance = v.length2(); // Is v converging to v(A-B) ? EPA_DEBUG_ASSERT( ( ( prevVSqrd - squaredDistance ) > SIMD_EPSILON * prevVSqrd ) , "Shapes are disjoint, EPA should have never been called!" ); if (( ( prevVSqrd - squaredDistance ) <= SIMD_EPSILON * prevVSqrd )) return false; if ( simplexSolver.fullSimplex() || ( squaredDistance <= SIMD_EPSILON * simplexSolver.maxVertex() ) ) { break; } ++nbIterations; } SimdPoint3 simplexPoints[ 5 ]; SimdPoint3 wSupportPointsOnA[ 5 ]; SimdPoint3 wSupportPointsOnB[ 5 ]; int nbSimplexPoints = simplexSolver.getSimplex( wSupportPointsOnA, wSupportPointsOnB, simplexPoints ); // nbSimplexPoints can't be one because cases where the origin is on the boundary are handled // by hybrid penetration depth EPA_DEBUG_ASSERT( ( ( nbSimplexPoints > 1 ) ,( nbSimplexPoints <= 4 ) ) , "Hybrid Penetration Depth algorithm failed!" ); int nbPolyhedronPoints = nbSimplexPoints; #ifndef EPA_POLYHEDRON_USE_PLANES int initTetraIndices[ 4 ] = { 0, 1, 2, 3 }; #endif // Prepare initial polyhedron to start EPA from if ( nbSimplexPoints == 1 ) { return false; } else if ( nbSimplexPoints == 2 ) { // We have a line segment inside the CSO that contains the origin // Create an hexahedron ( two tetrahedron glued together ) by adding 3 new points SimdVector3 d = simplexPoints[ 0 ] - simplexPoints[ 1 ]; d.normalize(); SimdVector3 v1; SimdVector3 v2; SimdVector3 v3; SimdVector3 e1; SimdScalar absx = abs( d.getX() ); SimdScalar absy = abs( d.getY() ); SimdScalar absz = abs( d.getZ() ); if ( absx < absy ) { if ( absx < absz ) { e1.setX( 1 ); } else { e1.setZ( 1 ); } } else { if ( absy < absz ) { e1.setY( 1 ); } else { e1.setZ( 1 ); } } v1 = d.cross( e1 ); v1.normalize(); v2 = v1.rotate( d, 120 * SIMD_RADS_PER_DEG ); v3 = v2.rotate( d, 120 * SIMD_RADS_PER_DEG ); nbPolyhedronPoints = 5; SimdVector3 seperatingAxisInA = v1 * m_transformA.getBasis(); SimdVector3 seperatingAxisInB = -v1 * m_transformB.getBasis(); SimdVector3 p = m_pConvexShapeA->LocalGetSupportingVertex( seperatingAxisInA ); SimdVector3 q = m_pConvexShapeB->LocalGetSupportingVertex( seperatingAxisInB ); SimdPoint3 pWorld = m_transformA( p ); SimdPoint3 qWorld = m_transformB( q ); wSupportPointsOnA[ 2 ] = pWorld; wSupportPointsOnB[ 2 ] = qWorld; simplexPoints[ 2 ] = wSupportPointsOnA[ 2 ] - wSupportPointsOnB[ 2 ]; seperatingAxisInA = v2 * m_transformA.getBasis(); seperatingAxisInB = -v2 * m_transformB.getBasis(); p = m_pConvexShapeA->LocalGetSupportingVertex( seperatingAxisInA ); q = m_pConvexShapeB->LocalGetSupportingVertex( seperatingAxisInB ); pWorld = m_transformA( p ); qWorld = m_transformB( q ); wSupportPointsOnA[ 3 ] = pWorld; wSupportPointsOnB[ 3 ] = qWorld; simplexPoints[ 3 ] = wSupportPointsOnA[ 3 ] - wSupportPointsOnB[ 3 ]; seperatingAxisInA = v3 * m_transformA.getBasis(); seperatingAxisInB = -v3 * m_transformB.getBasis(); p = m_pConvexShapeA->LocalGetSupportingVertex( seperatingAxisInA ); q = m_pConvexShapeB->LocalGetSupportingVertex( seperatingAxisInB ); pWorld = m_transformA( p ); qWorld = m_transformB( q ); wSupportPointsOnA[ 4 ] = pWorld; wSupportPointsOnB[ 4 ] = qWorld; simplexPoints[ 4 ] = wSupportPointsOnA[ 4 ] - wSupportPointsOnB[ 4 ]; #ifndef EPA_POLYHEDRON_USE_PLANES if ( TetrahedronContainsOrigin( simplexPoints[ 0 ], simplexPoints[ 2 ], simplexPoints[ 3 ], simplexPoints[ 4 ] ) ) { initTetraIndices[ 1 ] = 2; initTetraIndices[ 2 ] = 3; initTetraIndices[ 3 ] = 4; } else { if ( TetrahedronContainsOrigin( simplexPoints[ 1 ], simplexPoints[ 2 ], simplexPoints[ 3 ], simplexPoints[ 4 ] ) ) { initTetraIndices[ 0 ] = 1; initTetraIndices[ 1 ] = 2; initTetraIndices[ 2 ] = 3; initTetraIndices[ 3 ] = 4; } else { // No tetrahedron contains the origin assert( false && "Unable to find an initial tetrahedron that contains the origin!" ); return false; } } #endif } else if ( nbSimplexPoints == 3 ) { // We have a triangle inside the CSO that contains the origin // Create an hexahedron ( two tetrahedron glued together ) by adding 2 new points SimdVector3 v0 = simplexPoints[ 2 ] - simplexPoints[ 0 ]; SimdVector3 v1 = simplexPoints[ 1 ] - simplexPoints[ 0 ]; SimdVector3 triangleNormal = v0.cross( v1 ); triangleNormal.normalize(); nbPolyhedronPoints = 5; SimdVector3 seperatingAxisInA = triangleNormal * m_transformA.getBasis(); SimdVector3 seperatingAxisInB = -triangleNormal * m_transformB.getBasis(); SimdVector3 p = m_pConvexShapeA->LocalGetSupportingVertex( seperatingAxisInA ); SimdVector3 q = m_pConvexShapeB->LocalGetSupportingVertex( seperatingAxisInB ); SimdPoint3 pWorld = m_transformA( p ); SimdPoint3 qWorld = m_transformB( q ); wSupportPointsOnA[ 3 ] = pWorld; wSupportPointsOnB[ 3 ] = qWorld; simplexPoints[ 3 ] = wSupportPointsOnA[ 3 ] - wSupportPointsOnB[ 3 ]; #ifndef EPA_POLYHEDRON_USE_PLANES // We place this check here because if the tetrahedron contains the origin // there is no need to sample another support point if ( !TetrahedronContainsOrigin( simplexPoints[ 0 ], simplexPoints[ 1 ], simplexPoints[ 2 ], simplexPoints[ 3 ] ) ) { #endif seperatingAxisInA = -triangleNormal * m_transformA.getBasis(); seperatingAxisInB = triangleNormal * m_transformB.getBasis(); p = m_pConvexShapeA->LocalGetSupportingVertex( seperatingAxisInA ); q = m_pConvexShapeB->LocalGetSupportingVertex( seperatingAxisInB ); pWorld = m_transformA( p ); qWorld = m_transformB( q ); wSupportPointsOnA[ 4 ] = pWorld; wSupportPointsOnB[ 4 ] = qWorld; simplexPoints[ 4 ] = wSupportPointsOnA[ 4 ] - wSupportPointsOnB[ 4 ]; #ifndef EPA_POLYHEDRON_USE_PLANES if ( TetrahedronContainsOrigin( simplexPoints[ 0 ], simplexPoints[ 1 ], simplexPoints[ 2 ], simplexPoints[ 4 ] ) ) { initTetraIndices[ 3 ] = 4; } else { // No tetrahedron contains the origin assert( false && "Unable to find an initial tetrahedron that contains the origin!" ); return false; } } #endif } #ifdef _DEBUG else if ( nbSimplexPoints == 4 ) { EPA_DEBUG_ASSERT( TetrahedronContainsOrigin( simplexPoints ) ,"Initial tetrahedron does not contain the origin!" ); } #endif #ifndef EPA_POLYHEDRON_USE_PLANES SimdPoint3 wTetraPoints[ 4 ] = { simplexPoints[ initTetraIndices[ 0 ] ], simplexPoints[ initTetraIndices[ 1 ] ], simplexPoints[ initTetraIndices[ 2 ] ], simplexPoints[ initTetraIndices[ 3 ] ] }; SimdPoint3 wTetraSupportPointsOnA[ 4 ] = { wSupportPointsOnA[ initTetraIndices[ 0 ] ], wSupportPointsOnA[ initTetraIndices[ 1 ] ], wSupportPointsOnA[ initTetraIndices[ 2 ] ], wSupportPointsOnA[ initTetraIndices[ 3 ] ] }; SimdPoint3 wTetraSupportPointsOnB[ 4 ] = { wSupportPointsOnB[ initTetraIndices[ 0 ] ], wSupportPointsOnB[ initTetraIndices[ 1 ] ], wSupportPointsOnB[ initTetraIndices[ 2 ] ], wSupportPointsOnB[ initTetraIndices[ 3 ] ] }; #endif #ifdef EPA_POLYHEDRON_USE_PLANES if ( !m_polyhedron.Create( simplexPoints, wSupportPointsOnA, wSupportPointsOnB, nbPolyhedronPoints ) ) #else if ( !m_polyhedron.Create( wTetraPoints, wTetraSupportPointsOnA, wTetraSupportPointsOnB, 4 ) ) #endif { // Failed to create initial polyhedron EPA_DEBUG_ASSERT( false ,"Failed to create initial polyhedron!" ); return false; } // Add initial faces to priority queue #ifdef _DEBUG //m_polyhedron._dbgSaveToFile( "epa_start.dbg" ); #endif std::list< EpaFace* >& faces = m_polyhedron.GetFaces(); std::list< EpaFace* >::iterator facesItr( faces.begin() ); while ( facesItr != faces.end() ) { EpaFace* pFace = *facesItr; if ( !pFace->m_deleted ) { //#ifdef EPA_POLYHEDRON_USE_PLANES // if ( pFace->m_planeDistance >= 0 ) // { // m_polyhedron._dbgSaveToFile( "epa_start.dbg" ); // assert( false && "Face's plane distance equal or greater than 0!" ); // } //#endif if ( pFace->IsAffinelyDependent() ) { EPA_DEBUG_ASSERT( false ,"One initial face is affinely dependent!" ); return false; } if ( pFace->m_vSqrd <= 0 ) { EPA_DEBUG_ASSERT( false ,"Face containing the origin!" ); return false; } if ( pFace->IsClosestPointInternal() ) { m_faceEntries.push_back( pFace ); std::push_heap( m_faceEntries.begin(), m_faceEntries.end(), CompareEpaFaceEntries ); } } ++facesItr; } #ifdef _DEBUG //m_polyhedron._dbgSaveToFile( "epa_start.dbg" ); #endif EPA_DEBUG_ASSERT( !m_faceEntries.empty() ,"No faces added to heap!" ); return true; }
void clientMouseFunc(int button, int state, int x, int y) { //printf("button %i, state %i, x=%i,y=%i\n",button,state,x,y); //button 0, state 0 means left mouse down SimdVector3 rayTo = GetRayTo(x,y); switch (button) { case 2: { if (state==0) { shootBox(rayTo); } break; }; case 1: { if (state==0) { //apply an impulse if (physicsEnvironmentPtr) { float hit[3]; float normal[3]; PHY_IPhysicsController* hitObj = physicsEnvironmentPtr->rayTest(0,eye[0],eye[1],eye[2],rayTo.getX(),rayTo.getY(),rayTo.getZ(),hit[0],hit[1],hit[2],normal[0],normal[1],normal[2]); if (hitObj) { CcdPhysicsController* physCtrl = static_cast<CcdPhysicsController*>(hitObj); RigidBody* body = physCtrl->GetRigidBody(); if (body) { body->SetActivationState(ACTIVE_TAG); SimdVector3 impulse = rayTo; impulse.normalize(); float impulseStrength = 10.f; impulse *= impulseStrength; SimdVector3 relPos( hit[0] - body->getCenterOfMassPosition().getX(), hit[1] - body->getCenterOfMassPosition().getY(), hit[2] - body->getCenterOfMassPosition().getZ()); body->applyImpulse(impulse,relPos); } } } } else { } break; } case 0: { if (state==0) { //add a point to point constraint for picking if (physicsEnvironmentPtr) { float hit[3]; float normal[3]; PHY_IPhysicsController* hitObj = physicsEnvironmentPtr->rayTest(0,eye[0],eye[1],eye[2],rayTo.getX(),rayTo.getY(),rayTo.getZ(),hit[0],hit[1],hit[2],normal[0],normal[1],normal[2]); if (hitObj) { CcdPhysicsController* physCtrl = static_cast<CcdPhysicsController*>(hitObj); RigidBody* body = physCtrl->GetRigidBody(); if (body) { pickedBody = body; pickedBody->SetActivationState(DISABLE_DEACTIVATION); SimdVector3 pickPos(hit[0],hit[1],hit[2]); SimdVector3 localPivot = body->getCenterOfMassTransform().inverse() * pickPos; gPickingConstraintId = physicsEnvironmentPtr->createConstraint(physCtrl,0,PHY_POINT2POINT_CONSTRAINT, localPivot.getX(), localPivot.getY(), localPivot.getZ(), 0,0,0); //printf("created constraint %i",gPickingConstraintId); //save mouse position for dragging gOldPickingPos = rayTo; SimdVector3 eyePos(eye[0],eye[1],eye[2]); gOldPickingDist = (pickPos-eyePos).length(); Point2PointConstraint* p2p = static_cast<Point2PointConstraint*>(physicsEnvironmentPtr->getConstraintById(gPickingConstraintId)); if (p2p) { //very weak constraint for picking p2p->m_setting.m_tau = 0.1f; } } } } } else { if (gPickingConstraintId && physicsEnvironmentPtr) { physicsEnvironmentPtr->removeConstraint(gPickingConstraintId); //printf("removed constraint %i",gPickingConstraintId); gPickingConstraintId = 0; pickedBody->ForceActivationState(ACTIVE_TAG); pickedBody->m_deactivationTime = 0.f; pickedBody = 0; } } break; } default: { } } }
//to be implemented by the demo void renderme() { debugDrawer.SetDebugMode(getDebugMode()); //render the hinge axis if (createConstraint) { SimdVector3 color(1,0,0); SimdVector3 dirLocal(0,1,0); SimdVector3 pivotInA(CUBE_HALF_EXTENTS,-CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS); SimdVector3 pivotInB(-CUBE_HALF_EXTENTS,-CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS); SimdVector3 from = physObjects[1]->GetRigidBody()->getCenterOfMassTransform()(pivotInA); SimdVector3 fromB = physObjects[2]->GetRigidBody()->getCenterOfMassTransform()(pivotInB); SimdVector3 dirWorldA = physObjects[1]->GetRigidBody()->getCenterOfMassTransform().getBasis() * dirLocal ; SimdVector3 dirWorldB = physObjects[2]->GetRigidBody()->getCenterOfMassTransform().getBasis() * dirLocal ; debugDrawer.DrawLine(from,from+dirWorldA,color); debugDrawer.DrawLine(fromB,fromB+dirWorldB,color); } float m[16]; int i; if (getDebugMode() & IDebugDraw::DBG_DisableBulletLCP) { //don't use Bullet, use quickstep physicsEnvironmentPtr->setSolverType(0); } else { //Bullet LCP solver physicsEnvironmentPtr->setSolverType(1); } if (getDebugMode() & IDebugDraw::DBG_EnableCCD) { physicsEnvironmentPtr->setCcdMode(3); } else { physicsEnvironmentPtr->setCcdMode(0); } bool isSatEnabled = (getDebugMode() & IDebugDraw::DBG_EnableSatComparison); physicsEnvironmentPtr->EnableSatCollisionDetection(isSatEnabled); #ifdef USE_HULL //some testing code for SAT if (isSatEnabled) { for (int s=0;s<numShapes;s++) { CollisionShape* shape = shapePtr[s]; if (shape->IsPolyhedral()) { PolyhedralConvexShape* polyhedron = static_cast<PolyhedralConvexShape*>(shape); if (!polyhedron->m_optionalHull) { //first convert vertices in 'Point3' format int numPoints = polyhedron->GetNumVertices(); Point3* points = new Point3[numPoints+1]; //first 4 points should not be co-planar, so add central point to satisfy MakeHull points[0] = Point3(0.f,0.f,0.f); SimdVector3 vertex; for (int p=0;p<numPoints;p++) { polyhedron->GetVertex(p,vertex); points[p+1] = Point3(vertex.getX(),vertex.getY(),vertex.getZ()); } Hull* hull = Hull::MakeHull(numPoints+1,points); polyhedron->m_optionalHull = hull; } } } } #endif //USE_HULL for (i=0;i<numObjects;i++) { SimdTransform transA; transA.setIdentity(); float pos[3]; float rot[4]; ms[i].getWorldPosition(pos[0],pos[1],pos[2]); ms[i].getWorldOrientation(rot[0],rot[1],rot[2],rot[3]); SimdQuaternion q(rot[0],rot[1],rot[2],rot[3]); transA.setRotation(q); SimdPoint3 dpos; dpos.setValue(pos[0],pos[1],pos[2]); transA.setOrigin( dpos ); transA.getOpenGLMatrix( m ); SimdVector3 wireColor(1.f,1.0f,0.5f); //wants deactivation if (i & 1) { wireColor = SimdVector3(0.f,0.0f,1.f); } ///color differently for active, sleeping, wantsdeactivation states if (physObjects[i]->GetRigidBody()->GetActivationState() == 1) //active { if (i & 1) { wireColor += SimdVector3 (1.f,0.f,0.f); } else { wireColor += SimdVector3 (.5f,0.f,0.f); } } if (physObjects[i]->GetRigidBody()->GetActivationState() == 2) //ISLAND_SLEEPING { if (i & 1) { wireColor += SimdVector3 (0.f,1.f, 0.f); } else { wireColor += SimdVector3 (0.f,0.5f,0.f); } } char extraDebug[125]; sprintf(extraDebug,"islId, Body=%i , %i",physObjects[i]->GetRigidBody()->m_islandTag1,physObjects[i]->GetRigidBody()->m_debugBodyId); physObjects[i]->GetRigidBody()->GetCollisionShape()->SetExtraDebugInfo(extraDebug); GL_ShapeDrawer::DrawOpenGL(m,physObjects[i]->GetRigidBody()->GetCollisionShape(),wireColor,getDebugMode()); ///this block is just experimental code to show some internal issues with replacing shapes on the fly. if (getDebugMode()!=0 && (i>0)) { if (physObjects[i]->GetRigidBody()->GetCollisionShape()->GetShapeType() == EMPTY_SHAPE_PROXYTYPE) { physObjects[i]->GetRigidBody()->SetCollisionShape(shapePtr[1]); //remove the persistent collision pairs that were created based on the previous shape BroadphaseProxy* bpproxy = physObjects[i]->GetRigidBody()->m_broadphaseHandle; physicsEnvironmentPtr->GetBroadphase()->CleanProxyFromPairs(bpproxy); SimdVector3 newinertia; SimdScalar newmass = 10.f; physObjects[i]->GetRigidBody()->GetCollisionShape()->CalculateLocalInertia(newmass,newinertia); physObjects[i]->GetRigidBody()->setMassProps(newmass,newinertia); physObjects[i]->GetRigidBody()->updateInertiaTensor(); } } } if (!(getDebugMode() & IDebugDraw::DBG_NoHelpText)) { float xOffset = 10.f; float yStart = 20.f; float yIncr = -2.f; char buf[124]; glColor3f(0, 0, 0); #ifdef USE_QUICKPROF if ( getDebugMode() & IDebugDraw::DBG_ProfileTimings) { static int counter = 0; counter++; std::map<std::string, hidden::ProfileBlock*>::iterator iter; for (iter = Profiler::mProfileBlocks.begin(); iter != Profiler::mProfileBlocks.end(); ++iter) { char blockTime[128]; sprintf(blockTime, "%s: %lf",&((*iter).first[0]),Profiler::getBlockTime((*iter).first, Profiler::BLOCK_CYCLE_SECONDS));//BLOCK_TOTAL_PERCENT)); glRasterPos3f(xOffset,yStart,0); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),blockTime); yStart += yIncr; } } #endif //USE_QUICKPROF //profiling << Profiler::createStatsString(Profiler::BLOCK_TOTAL_PERCENT); //<< std::endl; glRasterPos3f(xOffset,yStart,0); sprintf(buf,"mouse to interact"); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); yStart += yIncr; glRasterPos3f(xOffset,yStart,0); sprintf(buf,"space to reset"); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); yStart += yIncr; glRasterPos3f(xOffset,yStart,0); sprintf(buf,"cursor keys and z,x to navigate"); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); yStart += yIncr; glRasterPos3f(xOffset,yStart,0); sprintf(buf,"i to toggle simulation, s single step"); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); yStart += yIncr; glRasterPos3f(xOffset,yStart,0); sprintf(buf,"q to quit"); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); yStart += yIncr; glRasterPos3f(xOffset,yStart,0); sprintf(buf,"d to toggle deactivation"); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); yStart += yIncr; glRasterPos3f(xOffset,yStart,0); sprintf(buf,"a to draw temporal AABBs"); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); yStart += yIncr; glRasterPos3f(xOffset,yStart,0); sprintf(buf,"h to toggle help text"); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); yStart += yIncr; bool useBulletLCP = !(getDebugMode() & IDebugDraw::DBG_DisableBulletLCP); bool useCCD = (getDebugMode() & IDebugDraw::DBG_EnableCCD); glRasterPos3f(xOffset,yStart,0); sprintf(buf,"m Bullet GJK = %i",!isSatEnabled); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); yStart += yIncr; glRasterPos3f(xOffset,yStart,0); sprintf(buf,"n Bullet LCP = %i",useBulletLCP); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); yStart += yIncr; glRasterPos3f(xOffset,yStart,0); sprintf(buf,"1 CCD mode (adhoc) = %i",useCCD); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); yStart += yIncr; glRasterPos3f(xOffset,yStart,0); sprintf(buf,"+- shooting speed = %10.2f",bulletSpeed); BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); yStart += yIncr; } }
virtual void SetGravity(const SimdVector3& grav) { m_demoApp->GetPhysicsEnvironment()->setGravity(grav.getX(),grav.getY(),grav.getZ()); }