public void performRaycast(
      TriangleRaycastCallback callback, Vector3f raySource, Vector3f rayTarget) {
    MyNodeOverlapCallback myNodeCallback = myNodeCallbacks.get();
    myNodeCallback.init(callback, meshInterface);

    bvh.reportRayOverlappingNodex(myNodeCallback, raySource, rayTarget);

    myNodeCallbacks.release(myNodeCallback);
  }
  public void performConvexcast(
      TriangleConvexcastCallback callback,
      Vector3f raySource,
      Vector3f rayTarget,
      Vector3f aabbMin,
      Vector3f aabbMax) {
    MyNodeOverlapCallback myNodeCallback = myNodeCallbacks.get();
    myNodeCallback.init(callback, meshInterface);

    bvh.reportBoxCastOverlappingNodex(myNodeCallback, raySource, rayTarget, aabbMin, aabbMax);

    myNodeCallbacks.release(myNodeCallback);
  }
  /** Perform bvh tree traversal and report overlapping triangles to 'callback'. */
  @Override
  public void processAllTriangles(TriangleCallback callback, Vector3f aabbMin, Vector3f aabbMax) {
    // #ifdef DISABLE_BVH
    // // brute force traverse all triangles
    // btTriangleMeshShape::processAllTriangles(callback,aabbMin,aabbMax);
    // #else

    // first get all the nodes
    MyNodeOverlapCallback myNodeCallback = myNodeCallbacks.get();
    myNodeCallback.init(callback, meshInterface);

    bvh.reportAabbOverlappingNodex(myNodeCallback, aabbMin, aabbMax);

    myNodeCallbacks.release(myNodeCallback);
    // #endif//DISABLE_BVH
  }
  public void addContactPoint(Vector3f normalOnBInWorld, Vector3f pointInWorld, float depth) {
    assert (manifoldPtr != null);
    // order in manifold needs to match

    if (depth > manifoldPtr.getContactBreakingThreshold()) {
      return;
    }

    stack.vectors.push();
    try {
      boolean isSwapped = manifoldPtr.getBody0() != body0;

      Vector3f pointA = stack.vectors.get();
      pointA.scaleAdd(depth, normalOnBInWorld, pointInWorld);

      Vector3f localA = stack.vectors.get();
      Vector3f localB = stack.vectors.get();

      if (isSwapped) {
        rootTransB.invXform(pointA, localA);
        rootTransA.invXform(pointInWorld, localB);
      } else {
        rootTransA.invXform(pointA, localA);
        rootTransB.invXform(pointInWorld, localB);
      }

      ManifoldPoint newPt = pointsPool.get();
      newPt.init(localA, localB, normalOnBInWorld, depth);

      newPt.positionWorldOnA.set(pointA);
      newPt.positionWorldOnB.set(pointInWorld);

      int insertIndex = manifoldPtr.getCacheEntry(newPt);

      newPt.combinedFriction = calculateCombinedFriction(body0, body1);
      newPt.combinedRestitution = calculateCombinedRestitution(body0, body1);

      /// todo, check this for any side effects
      if (insertIndex >= 0) {
        // const btManifoldPoint& oldPoint = m_manifoldPtr->getContactPoint(insertIndex);
        manifoldPtr.replaceContactPoint(newPt, insertIndex);
      } else {
        manifoldPtr.addManifoldPoint(newPt);
      }

      // User can override friction and/or restitution
      if (BulletGlobals.gContactAddedCallback != null
          &&
          // and if either of the two bodies requires custom material
          ((body0.getCollisionFlags() & CollisionFlags.CUSTOM_MATERIAL_CALLBACK) != 0
              || (body1.getCollisionFlags() & CollisionFlags.CUSTOM_MATERIAL_CALLBACK) != 0)) {
        // experimental feature info, for per-triangle material etc.
        CollisionObject obj0 = isSwapped ? body1 : body0;
        CollisionObject obj1 = isSwapped ? body0 : body1;
        BulletGlobals.gContactAddedCallback.invoke(
            newPt, obj0, partId0, index0, obj1, partId1, index1);
      }

      pointsPool.release(newPt);
    } finally {
      stack.vectors.pop();
    }
  }