void MyCollisionListener::contactPointAddedCallback( hkpContactPointAddedEvent& event ) { // // draw the contact point as a little red star // { const hkVector4& start = event.m_contactPoint->getPosition(); for ( int i = 0; i < 20; i++ ) { hkVector4 dir( hkMath::sin( i * 1.0f ), hkMath::cos( i * 1.0f ), hkMath::sin(i * 5.0f ) ); dir.setMul4(0.3f, dir); hkVector4 end; end.setAdd4(start, dir); HK_DISPLAY_LINE(start, end, hkColor::RED); } } // // collect all information in our own data structure // as the havok memory manager is really really fast, // allocating lots of small structures is acceptable // if ( event.m_contactPointProperties->getUserData() == HK_NULL ) { ContactPointInfo* info = new ContactPointInfo; info->m_uniqueId = m_uniqueIdCounter++; event.m_contactPointProperties->setUserData( reinterpret_cast<hkUlong>(info) ); // // printf some information // if (m_reportLevel >= hkDemoEnvironment::REPORT_INFO) { if ( event.isToi() ) { hkprintf("Toi userId=%i created\n", info->m_uniqueId ); } else { int cpId = event.asManifoldEvent().m_contactPointId; hkprintf("Contact Point userId=%i created: contactId=%i\n", info->m_uniqueId, cpId ); } } } // By setting the ProcessContactCallbackDelay to 0 we will receive callbacks for // any collisions processed for this body every frame (simulation step), i.e. the delay between // any such callbacks is 0 frames. // If you wish to only be notified every N frames simply set the delay to be N-1. // The default is 65536, i.e. (for practical purpose) once for the first collision only, until // the bodies separate to outside the collision tolerance. event.m_callbackFiredFrom->setProcessContactCallbackDelay(0); }
void MyExtendedUserDataListener::contactPointAddedCallback( hkpContactPointAddedEvent& event ) { // // Read the shape key hierarchy -- this is done identically for both Psi and Toi contact points. // hkpShapeKey shapeKey; { // This is the body to which the listener is attached. hkpEntity* body = event.m_callbackFiredFrom; // Extended user data only works when you use the default hkpSimpleConstraintContactMgr. // The function below will assert otherwise. // The atom caches information on how many extended user datas we store for each body. // Each body stores its data independently. const int numDatas = event.getNumExtendedUserDatas(event.m_callbackFiredFrom); // Now we can read the data. // The first user data stores the hkpShapeKey of the bottom most hkpCdBody in the shape hierarchy, // the next one stores hkpShapeKey of its parent, and so on, till we store '-1' as the hkpShapeKey // of the root collidable, or we run out of extended user data slots, in which case only a part // of the hierarchy is stored. // // In this demo we expect to have: // extendedUserDatas[0] in the [0,7] range -- this is the hkpShapeKey of one of the 8 transformed sphere shapes grouped under a hkpListShape // extendedUserDatas[1] equal -1 -- this is the root hkpListShape, with no parent, and therefore no hkpShapeKey // // Note that we only have two levels of hierarchy, while our shape is composed of hkpListShape->hkpConvexTransformShape->hkpSphereShape. // That's because hkpConvexTransform/TranslateShapes don't create a corresponding hkpCdBody during collision detection. // Note that the above is not the case for the deprecated hkpTransformShape. hkInplaceArray<hkpContactPointProperties::UserData,8> data; data.setSize(numDatas); event.getExtendedUserDatas(body, data.begin(), numDatas); // Let us store our custom contact point id. Let's store it in the last data slot to avoid overwriting the hkpShapeKey hierarchy. // We know we have enough room, as we set entity->m_numUserDatasInContactPointProperties = 3 which is more that the max hierarchy depth for our shape. data[numDatas-1] = m_uniqueIdCounter++; // And write back all datas event.setExtendedUserDatas(body, data.begin(), numDatas); // Get the hkpShapeKey shapeKey = data[0]; } // Sample demo structure holding history about callbacks triggered for this contact point. { ContactPointInfo& info = m_contactInfos.expandOne(); new (&info) ContactPointInfo(); HK_ASSERT2(0xad7853aa, m_contactInfos.getSize() == m_uniqueIdCounter, "Unique ID is not in synch with m_contactInfos array."); info.m_type = event.isToi() ? ContactPointInfo::TOI : ContactPointInfo::PSI; info.m_added = true; info.m_key = int(shapeKey); } // By setting the ProcessContactCallbackDelay to 0 we will receive callbacks for // any collisions processed for this body every frame (simulation step), i.e. the delay between // any such callbacks is 0 frames. // If you wish to only be notified every N frames simply set the delay to be N-1. // The default is 65536, i.e. (for practical purpose) once for the first collision only, until // the bodies separate to outside the collision tolerance. event.m_callbackFiredFrom->setProcessContactCallbackDelay(0); }