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

    bvh.reportRayOverlappingNodex(myNodeCallback, raySource, rayTarget);

    myNodeCallbacks.release(myNodeCallback);
  }
  public void performConvexcast(
      TriangleCallback 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
  }
/**
 * BvhTriangleMeshShape is a static-triangle mesh shape with several optimizations, such as bounding
 * volume hierarchy. It is recommended to enable useQuantizedAabbCompression for better memory
 * usage.
 *
 * <p>It takes a triangle mesh as input, for example a {@link TriangleMesh} or {@link
 * TriangleIndexVertexArray}. The BvhTriangleMeshShape class allows for triangle mesh deformations
 * by a refit or partialRefit method.
 *
 * <p>Instead of building the bounding volume hierarchy acceleration structure, it is also possible
 * to serialize (save) and deserialize (load) the structure from disk. See ConcaveDemo for an
 * example.
 *
 * @author jezek2
 */
public class BvhTriangleMeshShape extends TriangleMeshShape {

  private OptimizedBvh bvh;
  private boolean useQuantizedAabbCompression;
  private boolean ownsBvh;

  private ObjectPool<MyNodeOverlapCallback> myNodeCallbacks =
      ObjectPool.get(MyNodeOverlapCallback.class);

  public BvhTriangleMeshShape() {
    super(null);
    this.bvh = null;
    this.ownsBvh = false;
  }

  public BvhTriangleMeshShape(
      StridingMeshInterface meshInterface, boolean useQuantizedAabbCompression) {
    this(meshInterface, useQuantizedAabbCompression, true);
  }

  public BvhTriangleMeshShape(
      StridingMeshInterface meshInterface, boolean useQuantizedAabbCompression, boolean buildBvh) {
    super(meshInterface);
    this.bvh = null;
    this.useQuantizedAabbCompression = useQuantizedAabbCompression;
    this.ownsBvh = false;

    // construct bvh from meshInterface
    // #ifndef DISABLE_BVH

    Vector3f bvhAabbMin = new Vector3f(), bvhAabbMax = new Vector3f();
    meshInterface.calculateAabbBruteForce(bvhAabbMin, bvhAabbMax);

    if (buildBvh) {
      bvh = new OptimizedBvh();
      bvh.build(meshInterface, useQuantizedAabbCompression, bvhAabbMin, bvhAabbMax);
      ownsBvh = true;

      // JAVA NOTE: moved from TriangleMeshShape
      recalcLocalAabb();
    }

    // #endif //DISABLE_BVH
  }

  /**
   * Optionally pass in a larger bvh aabb, used for quantization. This allows for deformations
   * within this aabb.
   */
  public BvhTriangleMeshShape(
      StridingMeshInterface meshInterface,
      boolean useQuantizedAabbCompression,
      Vector3f bvhAabbMin,
      Vector3f bvhAabbMax) {
    this(meshInterface, useQuantizedAabbCompression, bvhAabbMin, bvhAabbMax, true);
  }

  /**
   * Optionally pass in a larger bvh aabb, used for quantization. This allows for deformations
   * within this aabb.
   */
  public BvhTriangleMeshShape(
      StridingMeshInterface meshInterface,
      boolean useQuantizedAabbCompression,
      Vector3f bvhAabbMin,
      Vector3f bvhAabbMax,
      boolean buildBvh) {
    super(meshInterface);

    this.bvh = null;
    this.useQuantizedAabbCompression = useQuantizedAabbCompression;
    this.ownsBvh = false;

    // construct bvh from meshInterface
    // #ifndef DISABLE_BVH

    if (buildBvh) {
      bvh = new OptimizedBvh();

      bvh.build(meshInterface, useQuantizedAabbCompression, bvhAabbMin, bvhAabbMax);
      ownsBvh = true;
    }

    // JAVA NOTE: moved from TriangleMeshShape
    recalcLocalAabb();
    // #endif //DISABLE_BVH
  }

  public boolean getOwnsBvh() {
    return ownsBvh;
  }

  @Override
  public BroadphaseNativeType getShapeType() {
    return BroadphaseNativeType.TRIANGLE_MESH_SHAPE_PROXYTYPE;
  }

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

    bvh.reportRayOverlappingNodex(myNodeCallback, raySource, rayTarget);

    myNodeCallbacks.release(myNodeCallback);
  }

  public void performConvexcast(
      TriangleCallback 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 refitTree(Vector3f aabbMin, Vector3f aabbMax) {
    // JAVA NOTE: update it for 2.70b1
    // bvh.refit(meshInterface, aabbMin, aabbMax);
    bvh.refit(meshInterface);

    recalcLocalAabb();
  }

  /**
   * For a fast incremental refit of parts of the tree. Note: the entire AABB of the tree will
   * become more conservative, it never shrinks.
   */
  public void partialRefitTree(Vector3f aabbMin, Vector3f aabbMax) {
    bvh.refitPartial(meshInterface, aabbMin, aabbMax);

    VectorUtil.setMin(localAabbMin, aabbMin);
    VectorUtil.setMax(localAabbMax, aabbMax);
  }

  @Override
  public String getName() {
    return "BVHTRIANGLEMESH";
  }

  @Override
  public void setLocalScaling(Vector3f scaling) {
    Vector3f tmp = new Vector3f();
    tmp.sub(getLocalScaling(new Vector3f()), scaling);

    if (tmp.lengthSquared() > BulletGlobals.SIMD_EPSILON) {
      super.setLocalScaling(scaling);
      /*
      if (ownsBvh)
      {
      m_bvh->~btOptimizedBvh();
      btAlignedFree(m_bvh);
      }
      */
      /// m_localAabbMin/m_localAabbMax is already re-calculated in btTriangleMeshShape. We could
      // just scale aabb, but this needs some more work
      bvh = new OptimizedBvh();
      // rebuild the bvh...
      bvh.build(meshInterface, useQuantizedAabbCompression, localAabbMin, localAabbMax);
      ownsBvh = true;
    }
  }

  public OptimizedBvh getOptimizedBvh() {
    return bvh;
  }

  public void setOptimizedBvh(OptimizedBvh bvh) {
    Vector3f scaling = new Vector3f();
    scaling.set(1f, 1f, 1f);
    setOptimizedBvh(bvh, scaling);
  }

  public void setOptimizedBvh(OptimizedBvh bvh, Vector3f scaling) {
    assert (this.bvh == null);
    assert (!ownsBvh);

    this.bvh = bvh;
    ownsBvh = false;

    // update the scaling without rebuilding the bvh
    Vector3f tmp = new Vector3f();
    tmp.sub(getLocalScaling(new Vector3f()), scaling);

    if (tmp.lengthSquared() > BulletGlobals.SIMD_EPSILON) {
      super.setLocalScaling(scaling);
    }
  }

  public boolean usesQuantizedAabbCompression() {
    return useQuantizedAabbCompression;
  }

  ////////////////////////////////////////////////////////////////////////////

  protected static class MyNodeOverlapCallback extends NodeOverlapCallback {
    public StridingMeshInterface meshInterface;
    public TriangleCallback callback;

    private Vector3f[] triangle /*[3]*/ =
        new Vector3f[] {new Vector3f(), new Vector3f(), new Vector3f()};

    public MyNodeOverlapCallback() {}

    public void init(TriangleCallback callback, StridingMeshInterface meshInterface) {
      this.meshInterface = meshInterface;
      this.callback = callback;
    }

    public void processNode(int nodeSubPart, int nodeTriangleIndex) {
      VertexData data = meshInterface.getLockedReadOnlyVertexIndexBase(nodeSubPart);

      Vector3f meshScaling = meshInterface.getScaling(new Vector3f());

      data.getTriangle(nodeTriangleIndex * 3, meshScaling, triangle);

      /* Perform ray vs. triangle collision here */
      callback.processTriangle(triangle, nodeSubPart, nodeTriangleIndex);

      meshInterface.unLockReadOnlyVertexBase(nodeSubPart);
    }
  }
}