Package com.bulletphysics.collision.shapes

Source Code of com.bulletphysics.collision.shapes.OptimizedBvh$QuantizedNodeTriangleCallback

/*
* Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz>
*
* Bullet Continuous Collision Detection and Physics Library
* Copyright (c) 2003-2008 Erwin Coumans  http://www.bulletphysics.com/
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
*    claim that you wrote the original software. If you use this software
*    in a product, an acknowledgment in the product documentation would be
*    appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/

package com.bulletphysics.collision.shapes;

import com.bulletphysics.linearmath.AabbUtil2;
import com.bulletphysics.linearmath.MiscUtil;
import com.bulletphysics.linearmath.VectorUtil;
import com.bulletphysics.util.ObjectArrayList;
import cz.advel.stack.Stack;
import java.io.Serializable;
import javax.vecmath.Vector3f;

// JAVA NOTE: OptimizedBvh still from 2.66, update it for 2.70b1

/**
* OptimizedBvh store an AABB tree that can be quickly traversed on CPU (and SPU, GPU in future).
*
* @author jezek2
*/
public class OptimizedBvh implements Serializable {

  private static final long serialVersionUID = 1L;

  //protected final BulletStack stack = BulletStack.get();
 
  private static final boolean DEBUG_TREE_BUILDING = false;
  private static int gStackDepth = 0;
  private static int gMaxStackDepth = 0;
 
  private static int maxIterations = 0;
 
  // Note: currently we have 16 bytes per quantized node
  public static final int MAX_SUBTREE_SIZE_IN_BYTES = 2048;

  // 10 gives the potential for 1024 parts, with at most 2^21 (2097152) (minus one
  // actually) triangles each (since the sign bit is reserved
  public static final int MAX_NUM_PARTS_IN_BITS = 10;

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

  private final ObjectArrayList<OptimizedBvhNode> leafNodes = new ObjectArrayList<OptimizedBvhNode>();
  private final ObjectArrayList<OptimizedBvhNode> contiguousNodes = new ObjectArrayList<OptimizedBvhNode>();

  private QuantizedBvhNodes quantizedLeafNodes = new QuantizedBvhNodes();
  private QuantizedBvhNodes quantizedContiguousNodes = new QuantizedBvhNodes();
 
  private int curNodeIndex;

  // quantization data
  private boolean useQuantization;
  private final Vector3f bvhAabbMin = new Vector3f();
  private final Vector3f bvhAabbMax = new Vector3f();
  private final Vector3f bvhQuantization = new Vector3f();
 
  protected TraversalMode traversalMode = TraversalMode.STACKLESS;
  protected final ObjectArrayList<BvhSubtreeInfo> SubtreeHeaders = new ObjectArrayList<BvhSubtreeInfo>();
  // This is only used for serialization so we don't have to add serialization directly to btAlignedObjectArray
  protected int subtreeHeaderCount;

  // two versions, one for quantized and normal nodes. This allows code-reuse while maintaining readability (no template/macro!)
  // this might be refactored into a virtual, it is usually not calculated at run-time
  public void setInternalNodeAabbMin(int nodeIndex, Vector3f aabbMin) {
    if (useQuantization) {
      quantizedContiguousNodes.setQuantizedAabbMin(nodeIndex, quantizeWithClamp(aabbMin));
    }
    else {
      contiguousNodes.getQuick(nodeIndex).aabbMinOrg.set(aabbMin);
    }
  }

  public void setInternalNodeAabbMax(int nodeIndex, Vector3f aabbMax) {
    if (useQuantization) {
      quantizedContiguousNodes.setQuantizedAabbMax(nodeIndex, quantizeWithClamp(aabbMax));
    }
    else {
      contiguousNodes.getQuick(nodeIndex).aabbMaxOrg.set(aabbMax);
    }
  }
 
  public Vector3f getAabbMin(int nodeIndex) {
    if (useQuantization) {
      Vector3f tmp = new Vector3f();
      unQuantize(tmp, quantizedLeafNodes.getQuantizedAabbMin(nodeIndex));
      return tmp;
    }

    // non-quantized
    return leafNodes.getQuick(nodeIndex).aabbMinOrg;
  }

  public Vector3f getAabbMax(int nodeIndex) {
    if (useQuantization) {
      Vector3f tmp = new Vector3f();
      unQuantize(tmp, quantizedLeafNodes.getQuantizedAabbMax(nodeIndex));
      return tmp;
    }
   
    // non-quantized
    return leafNodes.getQuick(nodeIndex).aabbMaxOrg;
  }

  public void setQuantizationValues(Vector3f aabbMin, Vector3f aabbMax) {
    setQuantizationValues(aabbMin, aabbMax, 1f);
  }
 
  public void setQuantizationValues(Vector3f aabbMin, Vector3f aabbMax, float quantizationMargin) {
    // enlarge the AABB to avoid division by zero when initializing the quantization values
    Vector3f clampValue = Stack.alloc(Vector3f.class);
    clampValue.set(quantizationMargin,quantizationMargin,quantizationMargin);
    bvhAabbMin.sub(aabbMin, clampValue);
    bvhAabbMax.add(aabbMax, clampValue);
    Vector3f aabbSize = Stack.alloc(Vector3f.class);
    aabbSize.sub(bvhAabbMax, bvhAabbMin);
    bvhQuantization.set(65535f, 65535f, 65535f);
    VectorUtil.div(bvhQuantization, bvhQuantization, aabbSize);
  }
 
  public void setInternalNodeEscapeIndex(int nodeIndex, int escapeIndex) {
    if (useQuantization) {
      quantizedContiguousNodes.setEscapeIndexOrTriangleIndex(nodeIndex, -escapeIndex);
    }
    else {
      contiguousNodes.getQuick(nodeIndex).escapeIndex = escapeIndex;
    }
  }

  public void mergeInternalNodeAabb(int nodeIndex, Vector3f newAabbMin, Vector3f newAabbMax) {
    if (useQuantization) {
      long quantizedAabbMin;
      long quantizedAabbMax;

      quantizedAabbMin = quantizeWithClamp(newAabbMin);
      quantizedAabbMax = quantizeWithClamp(newAabbMax);
      for (int i = 0; i < 3; i++) {
        if (quantizedContiguousNodes.getQuantizedAabbMin(nodeIndex, i) > QuantizedBvhNodes.getCoord(quantizedAabbMin, i)) {
          quantizedContiguousNodes.setQuantizedAabbMin(nodeIndex, i, QuantizedBvhNodes.getCoord(quantizedAabbMin, i));
        }

        if (quantizedContiguousNodes.getQuantizedAabbMax(nodeIndex, i) < QuantizedBvhNodes.getCoord(quantizedAabbMax, i)) {
          quantizedContiguousNodes.setQuantizedAabbMax(nodeIndex, i, QuantizedBvhNodes.getCoord(quantizedAabbMax, i));
        }
      }
    }
    else {
      // non-quantized
      VectorUtil.setMin(contiguousNodes.getQuick(nodeIndex).aabbMinOrg, newAabbMin);
      VectorUtil.setMax(contiguousNodes.getQuick(nodeIndex).aabbMaxOrg, newAabbMax);
    }
  }
 
  public void swapLeafNodes(int i, int splitIndex) {
    if (useQuantization) {
      quantizedLeafNodes.swap(i, splitIndex);
    }
    else {
      // JAVA NOTE: changing reference instead of copy
      OptimizedBvhNode tmp = leafNodes.getQuick(i);
      leafNodes.setQuick(i, leafNodes.getQuick(splitIndex));
      leafNodes.setQuick(splitIndex, tmp);
    }
  }

  public void assignInternalNodeFromLeafNode(int internalNode, int leafNodeIndex) {
    if (useQuantization) {
      quantizedContiguousNodes.set(internalNode, quantizedLeafNodes, leafNodeIndex);
    }
    else {
      contiguousNodes.getQuick(internalNode).set(leafNodes.getQuick(leafNodeIndex));
    }
  }

  private static class NodeTriangleCallback extends InternalTriangleIndexCallback {
    public ObjectArrayList<OptimizedBvhNode> triangleNodes;
   
    public NodeTriangleCallback(ObjectArrayList<OptimizedBvhNode> triangleNodes) {
      this.triangleNodes = triangleNodes;
    }

    private final Vector3f aabbMin = new Vector3f(), aabbMax = new Vector3f();
   
    public void internalProcessTriangleIndex(Vector3f[] triangle, int partId, int triangleIndex) {
      OptimizedBvhNode node = new OptimizedBvhNode();
      aabbMin.set(1e30f, 1e30f, 1e30f);
      aabbMax.set(-1e30f, -1e30f, -1e30f);
      VectorUtil.setMin(aabbMin, triangle[0]);
      VectorUtil.setMax(aabbMax, triangle[0]);
      VectorUtil.setMin(aabbMin, triangle[1]);
      VectorUtil.setMax(aabbMax, triangle[1]);
      VectorUtil.setMin(aabbMin, triangle[2]);
      VectorUtil.setMax(aabbMax, triangle[2]);

      // with quantization?
      node.aabbMinOrg.set(aabbMin);
      node.aabbMaxOrg.set(aabbMax);

      node.escapeIndex = -1;

      // for child nodes
      node.subPart = partId;
      node.triangleIndex = triangleIndex;
      triangleNodes.add(node);
    }
  }

  private static class QuantizedNodeTriangleCallback extends InternalTriangleIndexCallback {
    //protected final BulletStack stack = BulletStack.get();
   
    public QuantizedBvhNodes triangleNodes;
    public OptimizedBvh optimizedTree; // for quantization

    public QuantizedNodeTriangleCallback(QuantizedBvhNodes triangleNodes, OptimizedBvh tree) {
      this.triangleNodes = triangleNodes;
      this.optimizedTree = tree;
    }
   
    public void internalProcessTriangleIndex(Vector3f[] triangle, int partId, int triangleIndex) {
      // The partId and triangle index must fit in the same (positive) integer
      assert (partId < (1 << MAX_NUM_PARTS_IN_BITS));
      assert (triangleIndex < (1 << (31 - MAX_NUM_PARTS_IN_BITS)));
      // negative indices are reserved for escapeIndex
      assert (triangleIndex >= 0);

      int nodeId = triangleNodes.add();
      Vector3f aabbMin = Stack.alloc(Vector3f.class), aabbMax = Stack.alloc(Vector3f.class);
      aabbMin.set(1e30f, 1e30f, 1e30f);
      aabbMax.set(-1e30f, -1e30f, -1e30f);
      VectorUtil.setMin(aabbMin, triangle[0]);
      VectorUtil.setMax(aabbMax, triangle[0]);
      VectorUtil.setMin(aabbMin, triangle[1]);
      VectorUtil.setMax(aabbMax, triangle[1]);
      VectorUtil.setMin(aabbMin, triangle[2]);
      VectorUtil.setMax(aabbMax, triangle[2]);

      // PCK: add these checks for zero dimensions of aabb
      final float MIN_AABB_DIMENSION = 0.002f;
      final float MIN_AABB_HALF_DIMENSION = 0.001f;
      if (aabbMax.x - aabbMin.x < MIN_AABB_DIMENSION) {
        aabbMax.x = (aabbMax.x + MIN_AABB_HALF_DIMENSION);
        aabbMin.x = (aabbMin.x - MIN_AABB_HALF_DIMENSION);
      }
      if (aabbMax.y - aabbMin.y < MIN_AABB_DIMENSION) {
        aabbMax.y = (aabbMax.y + MIN_AABB_HALF_DIMENSION);
        aabbMin.y = (aabbMin.y - MIN_AABB_HALF_DIMENSION);
      }
      if (aabbMax.z - aabbMin.z < MIN_AABB_DIMENSION) {
        aabbMax.z = (aabbMax.z + MIN_AABB_HALF_DIMENSION);
        aabbMin.z = (aabbMin.z - MIN_AABB_HALF_DIMENSION);
      }

      triangleNodes.setQuantizedAabbMin(nodeId, optimizedTree.quantizeWithClamp(aabbMin));
      triangleNodes.setQuantizedAabbMax(nodeId, optimizedTree.quantizeWithClamp(aabbMax));

      triangleNodes.setEscapeIndexOrTriangleIndex(nodeId, (partId << (31 - MAX_NUM_PARTS_IN_BITS)) | triangleIndex);
    }
  }
 
  public void build(StridingMeshInterface triangles, boolean useQuantizedAabbCompression, Vector3f _aabbMin, Vector3f _aabbMax) {
    this.useQuantization = useQuantizedAabbCompression;

    // NodeArray  triangleNodes;

    int numLeafNodes = 0;

    if (useQuantization) {
      // initialize quantization values
      setQuantizationValues(_aabbMin, _aabbMax);

      QuantizedNodeTriangleCallback callback = new QuantizedNodeTriangleCallback(quantizedLeafNodes, this);

      triangles.internalProcessAllTriangles(callback, bvhAabbMin, bvhAabbMax);

      // now we have an array of leafnodes in m_leafNodes
      numLeafNodes = quantizedLeafNodes.size();

      quantizedContiguousNodes.resize(2 * numLeafNodes);
    }
    else {
      NodeTriangleCallback callback = new NodeTriangleCallback(leafNodes);

      Vector3f aabbMin = Stack.alloc(Vector3f.class);
      aabbMin.set(-1e30f, -1e30f, -1e30f);
      Vector3f aabbMax = Stack.alloc(Vector3f.class);
      aabbMax.set(1e30f, 1e30f, 1e30f);

      triangles.internalProcessAllTriangles(callback, aabbMin, aabbMax);

      // now we have an array of leafnodes in m_leafNodes
      numLeafNodes = leafNodes.size();

      // TODO: check
      //contiguousNodes.resize(2*numLeafNodes);
      MiscUtil.resize(contiguousNodes, 2 * numLeafNodes, OptimizedBvhNode.class);
    }

    curNodeIndex = 0;

    buildTree(0, numLeafNodes);

    //  if the entire tree is small then subtree size, we need to create a header info for the tree
    if (useQuantization && SubtreeHeaders.size() == 0) {
      BvhSubtreeInfo subtree = new BvhSubtreeInfo();
      SubtreeHeaders.add(subtree);

      subtree.setAabbFromQuantizeNode(quantizedContiguousNodes, 0);
      subtree.rootNodeIndex = 0;
      subtree.subtreeSize = quantizedContiguousNodes.isLeafNode(0) ? 1 : quantizedContiguousNodes.getEscapeIndex(0);
    }

    // PCK: update the copy of the size
    subtreeHeaderCount = SubtreeHeaders.size();

    // PCK: clear m_quantizedLeafNodes and m_leafNodes, they are temporary
    quantizedLeafNodes.clear();
    leafNodes.clear();
  }
 
  public void refit(StridingMeshInterface meshInterface) {
    if (useQuantization) {
      // calculate new aabb
      Vector3f aabbMin = Stack.alloc(Vector3f.class), aabbMax = Stack.alloc(Vector3f.class);
      meshInterface.calculateAabbBruteForce(aabbMin, aabbMax);

      setQuantizationValues(aabbMin, aabbMax);

      updateBvhNodes(meshInterface, 0, curNodeIndex, 0);

      // now update all subtree headers

      int i;
      for (i = 0; i < SubtreeHeaders.size(); i++) {
        BvhSubtreeInfo subtree = SubtreeHeaders.getQuick(i);
        subtree.setAabbFromQuantizeNode(quantizedContiguousNodes, subtree.rootNodeIndex);
      }

    }
    else {
      // JAVA NOTE: added for testing, it's too slow for practical use
      build(meshInterface, false, null, null);
    }
  }
 
  public void refitPartial(StridingMeshInterface meshInterface, Vector3f aabbMin, Vector3f aabbMax) {
    throw new UnsupportedOperationException();
//    // incrementally initialize quantization values
//    assert (useQuantization);
//
//    btAssert(aabbMin.getX() > m_bvhAabbMin.getX());
//    btAssert(aabbMin.getY() > m_bvhAabbMin.getY());
//    btAssert(aabbMin.getZ() > m_bvhAabbMin.getZ());
//
//    btAssert(aabbMax.getX() < m_bvhAabbMax.getX());
//    btAssert(aabbMax.getY() < m_bvhAabbMax.getY());
//    btAssert(aabbMax.getZ() < m_bvhAabbMax.getZ());
//
//    ///we should update all quantization values, using updateBvhNodes(meshInterface);
//    ///but we only update chunks that overlap the given aabb
//
//    unsigned short  quantizedQueryAabbMin[3];
//    unsigned short  quantizedQueryAabbMax[3];
//
//    quantizeWithClamp(&quantizedQueryAabbMin[0],aabbMin);
//    quantizeWithClamp(&quantizedQueryAabbMax[0],aabbMax);
//
//    int i;
//    for (i=0;i<this->m_SubtreeHeaders.size();i++)
//    {
//      btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i];
//
//      //PCK: unsigned instead of bool
//      unsigned overlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,subtree.m_quantizedAabbMin,subtree.m_quantizedAabbMax);
//      if (overlap != 0)
//      {
//        updateBvhNodes(meshInterface,subtree.m_rootNodeIndex,subtree.m_rootNodeIndex+subtree.m_subtreeSize,i);
//
//        subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[subtree.m_rootNodeIndex]);
//      }
//    }
  }
 
  public void updateBvhNodes(StridingMeshInterface meshInterface, int firstNode, int endNode, int index) {
    assert (useQuantization);

    int curNodeSubPart = -1;

    Vector3f[] triangleVerts/*[3]*/ = new Vector3f[] { Stack.alloc(Vector3f.class), Stack.alloc(Vector3f.class), Stack.alloc(Vector3f.class) };
    Vector3f aabbMin = Stack.alloc(Vector3f.class), aabbMax = Stack.alloc(Vector3f.class);
    Vector3f meshScaling = meshInterface.getScaling(Stack.alloc(Vector3f.class));

    VertexData data = null;

    for (int i = endNode - 1; i >= firstNode; i--) {
      QuantizedBvhNodes curNodes = quantizedContiguousNodes;
      int curNodeId = i;

      if (curNodes.isLeafNode(curNodeId)) {
        // recalc aabb from triangle data
        int nodeSubPart = curNodes.getPartId(curNodeId);
        int nodeTriangleIndex = curNodes.getTriangleIndex(curNodeId);
        if (nodeSubPart != curNodeSubPart) {
          if (curNodeSubPart >= 0) {
            meshInterface.unLockReadOnlyVertexBase(curNodeSubPart);
          }
          data = meshInterface.getLockedReadOnlyVertexIndexBase(nodeSubPart);
        }
        //triangles->getLockedReadOnlyVertexIndexBase(vertexBase,numVerts,

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

        aabbMin.set(1e30f, 1e30f, 1e30f);
        aabbMax.set(-1e30f, -1e30f, -1e30f);
        VectorUtil.setMin(aabbMin, triangleVerts[0]);
        VectorUtil.setMax(aabbMax, triangleVerts[0]);
        VectorUtil.setMin(aabbMin, triangleVerts[1]);
        VectorUtil.setMax(aabbMax, triangleVerts[1]);
        VectorUtil.setMin(aabbMin, triangleVerts[2]);
        VectorUtil.setMax(aabbMax, triangleVerts[2]);

        curNodes.setQuantizedAabbMin(curNodeId, quantizeWithClamp(aabbMin));
        curNodes.setQuantizedAabbMax(curNodeId, quantizeWithClamp(aabbMax));
      }
      else {
        // combine aabb from both children

        //quantizedContiguousNodes
        int leftChildNodeId = i + 1;

        int rightChildNodeId = quantizedContiguousNodes.isLeafNode(leftChildNodeId) ? i + 2 : i + 1 + quantizedContiguousNodes.getEscapeIndex(leftChildNodeId);

        for (int i2 = 0; i2 < 3; i2++) {
          curNodes.setQuantizedAabbMin(curNodeId, i2, quantizedContiguousNodes.getQuantizedAabbMin(leftChildNodeId, i2));
          if (curNodes.getQuantizedAabbMin(curNodeId, i2) > quantizedContiguousNodes.getQuantizedAabbMin(rightChildNodeId, i2)) {
            curNodes.setQuantizedAabbMin(curNodeId, i2, quantizedContiguousNodes.getQuantizedAabbMin(rightChildNodeId, i2));
          }

          curNodes.setQuantizedAabbMax(curNodeId, i2, quantizedContiguousNodes.getQuantizedAabbMax(leftChildNodeId, i2));
          if (curNodes.getQuantizedAabbMax(curNodeId, i2) < quantizedContiguousNodes.getQuantizedAabbMax(rightChildNodeId, i2)) {
            curNodes.setQuantizedAabbMax(curNodeId, i2, quantizedContiguousNodes.getQuantizedAabbMax(rightChildNodeId, i2));
          }
        }
      }
    }

    if (curNodeSubPart >= 0) {
      meshInterface.unLockReadOnlyVertexBase(curNodeSubPart);
    }
  }
 
  protected void buildTree(int startIndex, int endIndex) {
    //#ifdef DEBUG_TREE_BUILDING
    if (DEBUG_TREE_BUILDING) {
      gStackDepth++;
      if (gStackDepth > gMaxStackDepth) {
        gMaxStackDepth = gStackDepth;
      }
    }
    //#endif //DEBUG_TREE_BUILDING

    int splitAxis, splitIndex, i;
    int numIndices = endIndex - startIndex;
    int curIndex = curNodeIndex;

    assert (numIndices > 0);

    if (numIndices == 1) {
      //#ifdef DEBUG_TREE_BUILDING
      if (DEBUG_TREE_BUILDING) {
        gStackDepth--;
      }
      //#endif //DEBUG_TREE_BUILDING

      assignInternalNodeFromLeafNode(curNodeIndex, startIndex);

      curNodeIndex++;
      return;
    }
    // calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'.

    splitAxis = calcSplittingAxis(startIndex, endIndex);

    splitIndex = sortAndCalcSplittingIndex(startIndex, endIndex, splitAxis);

    int internalNodeIndex = curNodeIndex;

    Vector3f tmp1 = Stack.alloc(Vector3f.class);
    tmp1.set(-1e30f, -1e30f, -1e30f);
    setInternalNodeAabbMax(curNodeIndex, tmp1);
    Vector3f tmp2 = Stack.alloc(Vector3f.class);
    tmp2.set(1e30f, 1e30f, 1e30f);
    setInternalNodeAabbMin(curNodeIndex, tmp2);

    for (i = startIndex; i < endIndex; i++) {
      mergeInternalNodeAabb(curNodeIndex, getAabbMin(i), getAabbMax(i));
    }

    curNodeIndex++;

    //internalNode->m_escapeIndex;

    int leftChildNodexIndex = curNodeIndex;

    //build left child tree
    buildTree(startIndex, splitIndex);

    int rightChildNodexIndex = curNodeIndex;
    // build right child tree
    buildTree(splitIndex, endIndex);

    //#ifdef DEBUG_TREE_BUILDING
    if (DEBUG_TREE_BUILDING) {
      gStackDepth--;
    }
    //#endif //DEBUG_TREE_BUILDING

    int escapeIndex = curNodeIndex - curIndex;

    if (useQuantization) {
      // escapeIndex is the number of nodes of this subtree
      int sizeQuantizedNode = QuantizedBvhNodes.getNodeSize();
      int treeSizeInBytes = escapeIndex * sizeQuantizedNode;
      if (treeSizeInBytes > MAX_SUBTREE_SIZE_IN_BYTES) {
        updateSubtreeHeaders(leftChildNodexIndex, rightChildNodexIndex);
      }
    }

    setInternalNodeEscapeIndex(internalNodeIndex, escapeIndex);
  }

  protected boolean testQuantizedAabbAgainstQuantizedAabb(long aabbMin1, long aabbMax1, long aabbMin2, long aabbMax2) {
    int aabbMin1_0 = QuantizedBvhNodes.getCoord(aabbMin1, 0);
    int aabbMin1_1 = QuantizedBvhNodes.getCoord(aabbMin1, 1);
    int aabbMin1_2 = QuantizedBvhNodes.getCoord(aabbMin1, 2);

    int aabbMax1_0 = QuantizedBvhNodes.getCoord(aabbMax1, 0);
    int aabbMax1_1 = QuantizedBvhNodes.getCoord(aabbMax1, 1);
    int aabbMax1_2 = QuantizedBvhNodes.getCoord(aabbMax1, 2);

    int aabbMin2_0 = QuantizedBvhNodes.getCoord(aabbMin2, 0);
    int aabbMin2_1 = QuantizedBvhNodes.getCoord(aabbMin2, 1);
    int aabbMin2_2 = QuantizedBvhNodes.getCoord(aabbMin2, 2);

    int aabbMax2_0 = QuantizedBvhNodes.getCoord(aabbMax2, 0);
    int aabbMax2_1 = QuantizedBvhNodes.getCoord(aabbMax2, 1);
    int aabbMax2_2 = QuantizedBvhNodes.getCoord(aabbMax2, 2);

    boolean overlap = true;
    overlap = (aabbMin1_0 > aabbMax2_0 || aabbMax1_0 < aabbMin2_0) ? false : overlap;
    overlap = (aabbMin1_2 > aabbMax2_2 || aabbMax1_2 < aabbMin2_2) ? false : overlap;
    overlap = (aabbMin1_1 > aabbMax2_1 || aabbMax1_1 < aabbMin2_1) ? false : overlap;
    return overlap;
  }

  protected void updateSubtreeHeaders(int leftChildNodexIndex, int rightChildNodexIndex) {
    assert (useQuantization);

    //btQuantizedBvhNode& leftChildNode = m_quantizedContiguousNodes[leftChildNodexIndex];
    int leftSubTreeSize = quantizedContiguousNodes.isLeafNode(leftChildNodexIndex) ? 1 : quantizedContiguousNodes.getEscapeIndex(leftChildNodexIndex);
    int leftSubTreeSizeInBytes = leftSubTreeSize * QuantizedBvhNodes.getNodeSize();

    //btQuantizedBvhNode& rightChildNode = m_quantizedContiguousNodes[rightChildNodexIndex];
    int rightSubTreeSize = quantizedContiguousNodes.isLeafNode(rightChildNodexIndex) ? 1 : quantizedContiguousNodes.getEscapeIndex(rightChildNodexIndex);
    int rightSubTreeSizeInBytes = rightSubTreeSize * QuantizedBvhNodes.getNodeSize();

    if (leftSubTreeSizeInBytes <= MAX_SUBTREE_SIZE_IN_BYTES) {
      BvhSubtreeInfo subtree = new BvhSubtreeInfo();
      SubtreeHeaders.add(subtree);

      subtree.setAabbFromQuantizeNode(quantizedContiguousNodes, leftChildNodexIndex);
      subtree.rootNodeIndex = leftChildNodexIndex;
      subtree.subtreeSize = leftSubTreeSize;
    }

    if (rightSubTreeSizeInBytes <= MAX_SUBTREE_SIZE_IN_BYTES) {
      BvhSubtreeInfo subtree = new BvhSubtreeInfo();
      SubtreeHeaders.add(subtree);

      subtree.setAabbFromQuantizeNode(quantizedContiguousNodes, rightChildNodexIndex);
      subtree.rootNodeIndex = rightChildNodexIndex;
      subtree.subtreeSize = rightSubTreeSize;
    }

    // PCK: update the copy of the size
    subtreeHeaderCount = SubtreeHeaders.size();
  }
 
  protected int sortAndCalcSplittingIndex(int startIndex, int endIndex, int splitAxis) {
    int i;
    int splitIndex = startIndex;
    int numIndices = endIndex - startIndex;
    float splitValue;

    Vector3f means = Stack.alloc(Vector3f.class);
    means.set(0f, 0f, 0f);
    Vector3f center = Stack.alloc(Vector3f.class);
    for (i = startIndex; i < endIndex; i++) {
      center.add(getAabbMax(i), getAabbMin(i));
      center.scale(0.5f);
      means.add(center);
    }
    means.scale(1f / (float) numIndices);

    splitValue = VectorUtil.getCoord(means, splitAxis);

    //sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'.
    for (i = startIndex; i < endIndex; i++) {
      //Vector3f center = new Vector3f();
      center.add(getAabbMax(i), getAabbMin(i));
      center.scale(0.5f);

      if (VectorUtil.getCoord(center, splitAxis) > splitValue) {
        // swap
        swapLeafNodes(i, splitIndex);
        splitIndex++;
      }
    }

    // if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex
    // otherwise the tree-building might fail due to stack-overflows in certain cases.
    // unbalanced1 is unsafe: it can cause stack overflows
    // bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1)));

    // unbalanced2 should work too: always use center (perfect balanced trees) 
    // bool unbalanced2 = true;

    // this should be safe too:
    int rangeBalancedIndices = numIndices / 3;
    boolean unbalanced = ((splitIndex <= (startIndex + rangeBalancedIndices)) || (splitIndex >= (endIndex - 1 - rangeBalancedIndices)));

    if (unbalanced) {
      splitIndex = startIndex + (numIndices >> 1);
    }

    boolean unbal = (splitIndex == startIndex) || (splitIndex == (endIndex));
    assert (!unbal);

    return splitIndex;
  }

  protected int calcSplittingAxis(int startIndex, int endIndex) {
    int i;

    Vector3f means = Stack.alloc(Vector3f.class);
    means.set(0f, 0f, 0f);
    Vector3f variance = Stack.alloc(Vector3f.class);
    variance.set(0f, 0f, 0f);
    int numIndices = endIndex - startIndex;

    Vector3f center = Stack.alloc(Vector3f.class);
    for (i = startIndex; i < endIndex; i++) {
      center.add(getAabbMax(i), getAabbMin(i));
      center.scale(0.5f);
      means.add(center);
    }
    means.scale(1f / (float) numIndices);

    Vector3f diff2 = Stack.alloc(Vector3f.class);
    for (i = startIndex; i < endIndex; i++) {
      center.add(getAabbMax(i), getAabbMin(i));
      center.scale(0.5f);
      diff2.sub(center, means);
      //diff2 = diff2 * diff2;
      VectorUtil.mul(diff2, diff2, diff2);
      variance.add(diff2);
    }
    variance.scale(1f / ((float) numIndices - 1));

    return VectorUtil.maxAxis(variance);
  }

  public void reportAabbOverlappingNodex(NodeOverlapCallback nodeCallback, Vector3f aabbMin, Vector3f aabbMax) {
    // either choose recursive traversal (walkTree) or stackless (walkStacklessTree)

    if (useQuantization) {
      // quantize query AABB
      long quantizedQueryAabbMin;
      long quantizedQueryAabbMax;
      quantizedQueryAabbMin = quantizeWithClamp(aabbMin);
      quantizedQueryAabbMax = quantizeWithClamp(aabbMax);

      // JAVA TODO:
      switch (traversalMode) {
        case STACKLESS:
          walkStacklessQuantizedTree(nodeCallback, quantizedQueryAabbMin, quantizedQueryAabbMax, 0, curNodeIndex);
          break;
         
//        case STACKLESS_CACHE_FRIENDLY:
//          walkStacklessQuantizedTreeCacheFriendly(nodeCallback, quantizedQueryAabbMin, quantizedQueryAabbMax);
//          break;
         
        case RECURSIVE:
          walkRecursiveQuantizedTreeAgainstQueryAabb(quantizedContiguousNodes, 0, nodeCallback, quantizedQueryAabbMin, quantizedQueryAabbMax);
          break;
         
        default:
          assert (false); // unsupported
      }
    }
    else {
      walkStacklessTree(nodeCallback, aabbMin, aabbMax);
    }
  }
 
  protected void walkStacklessTree(NodeOverlapCallback nodeCallback, Vector3f aabbMin, Vector3f aabbMax) {
    assert (!useQuantization);

    // JAVA NOTE: rewritten
    OptimizedBvhNode rootNode = null;//contiguousNodes.get(0);
    int rootNode_index = 0;

    int escapeIndex, curIndex = 0;
    int walkIterations = 0;
    boolean isLeafNode;
    //PCK: unsigned instead of bool
    //unsigned aabbOverlap;
    boolean aabbOverlap;

    while (curIndex < curNodeIndex) {
      // catch bugs in tree data
      assert (walkIterations < curNodeIndex);

      walkIterations++;

      rootNode = contiguousNodes.getQuick(rootNode_index);

      aabbOverlap = AabbUtil2.testAabbAgainstAabb2(aabbMin, aabbMax, rootNode.aabbMinOrg, rootNode.aabbMaxOrg);
      isLeafNode = (rootNode.escapeIndex == -1);

      // PCK: unsigned instead of bool
      if (isLeafNode && (aabbOverlap/* != 0*/)) {
        nodeCallback.processNode(rootNode.subPart, rootNode.triangleIndex);
      }

      rootNode = null;

      //PCK: unsigned instead of bool
      if ((aabbOverlap/* != 0*/) || isLeafNode) {
        rootNode_index++;
        curIndex++;
      }
      else {
        escapeIndex = /*rootNode*/ contiguousNodes.getQuick(rootNode_index).escapeIndex;
        rootNode_index += escapeIndex;
        curIndex += escapeIndex;
      }
    }
    if (maxIterations < walkIterations) {
      maxIterations = walkIterations;
    }
  }

  protected void walkRecursiveQuantizedTreeAgainstQueryAabb(QuantizedBvhNodes currentNodes, int currentNodeId, NodeOverlapCallback nodeCallback, long quantizedQueryAabbMin, long quantizedQueryAabbMax) {
    assert (useQuantization);

    boolean isLeafNode;
    boolean aabbOverlap;

    aabbOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin, quantizedQueryAabbMax, currentNodes.getQuantizedAabbMin(currentNodeId), currentNodes.getQuantizedAabbMax(currentNodeId));
    isLeafNode = currentNodes.isLeafNode(currentNodeId);

    if (aabbOverlap) {
      if (isLeafNode) {
        nodeCallback.processNode(currentNodes.getPartId(currentNodeId), currentNodes.getTriangleIndex(currentNodeId));
      }
      else {
        // process left and right children
        int leftChildNodeId = currentNodeId + 1;
        walkRecursiveQuantizedTreeAgainstQueryAabb(currentNodes, leftChildNodeId, nodeCallback, quantizedQueryAabbMin, quantizedQueryAabbMax);

        int rightChildNodeId = currentNodes.isLeafNode(leftChildNodeId) ? leftChildNodeId + 1 : leftChildNodeId + currentNodes.getEscapeIndex(leftChildNodeId);
        walkRecursiveQuantizedTreeAgainstQueryAabb(currentNodes, rightChildNodeId, nodeCallback, quantizedQueryAabbMin, quantizedQueryAabbMax);
      }
    }
  }

  protected void walkStacklessQuantizedTreeAgainstRay(NodeOverlapCallback nodeCallback, Vector3f raySource, Vector3f rayTarget, Vector3f aabbMin, Vector3f aabbMax, int startNodeIndex, int endNodeIndex) {
    assert (useQuantization);

    Vector3f tmp = Stack.alloc(Vector3f.class);

    int curIndex = startNodeIndex;
    int walkIterations = 0;
    int subTreeSize = endNodeIndex - startNodeIndex;

    QuantizedBvhNodes rootNode = quantizedContiguousNodes;
    int rootNode_idx = startNodeIndex;
    int escapeIndex;

    boolean isLeafNode;
    boolean boxBoxOverlap = false;
    boolean rayBoxOverlap = false;

    float lambda_max = 1f;
    //#define RAYAABB2
    //#ifdef RAYAABB2
    Vector3f rayFrom = Stack.alloc(raySource);
    Vector3f rayDirection = Stack.alloc(Vector3f.class);
    tmp.sub(rayTarget, raySource);
    rayDirection.normalize(tmp);
    lambda_max = rayDirection.dot(tmp);
    rayDirection.x = 1f / rayDirection.x;
    rayDirection.y = 1f / rayDirection.y;
    rayDirection.z = 1f / rayDirection.z;
//    boolean sign_x = rayDirection.x < 0f;
//    boolean sign_y = rayDirection.y < 0f;
//    boolean sign_z = rayDirection.z < 0f;
    //#endif

    /* Quick pruning by quantized box */
    Vector3f rayAabbMin = Stack.alloc(raySource);
    Vector3f rayAabbMax = Stack.alloc(raySource);
    VectorUtil.setMin(rayAabbMin, rayTarget);
    VectorUtil.setMax(rayAabbMax, rayTarget);

    /* Add box cast extents to bounding box */
    rayAabbMin.add(aabbMin);
    rayAabbMax.add(aabbMax);

    long quantizedQueryAabbMin;
    long quantizedQueryAabbMax;
    quantizedQueryAabbMin = quantizeWithClamp(rayAabbMin);
    quantizedQueryAabbMax = quantizeWithClamp(rayAabbMax);

    Vector3f bounds_0 = Stack.alloc(Vector3f.class);
    Vector3f bounds_1 = Stack.alloc(Vector3f.class);
    Vector3f normal = Stack.alloc(Vector3f.class);
    float[] param = new float[1];

    while (curIndex < endNodeIndex) {
     
      //#define VISUALLY_ANALYZE_BVH 1
      //#ifdef VISUALLY_ANALYZE_BVH
      //    //some code snippet to debugDraw aabb, to visually analyze bvh structure
      //    static int drawPatch = 0;
      //    //need some global access to a debugDrawer
      //    extern btIDebugDraw* debugDrawerPtr;
      //    if (curIndex==drawPatch)
      //    {
      //      btVector3 aabbMin,aabbMax;
      //      aabbMin = unQuantize(rootNode->m_quantizedAabbMin);
      //      aabbMax = unQuantize(rootNode->m_quantizedAabbMax);
      //      btVector3  color(1,0,0);
      //      debugDrawerPtr->drawAabb(aabbMin,aabbMax,color);
      //    }
      //#endif//VISUALLY_ANALYZE_BVH

      // catch bugs in tree data
      assert (walkIterations < subTreeSize);

      walkIterations++;
      // only interested if this is closer than any previous hit
      param[0] = 1f;
      rayBoxOverlap = false;
      boxBoxOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin, quantizedQueryAabbMax, rootNode.getQuantizedAabbMin(rootNode_idx), rootNode.getQuantizedAabbMax(rootNode_idx));
      isLeafNode = rootNode.isLeafNode(rootNode_idx);
      if (boxBoxOverlap) {
        unQuantize(bounds_0, rootNode.getQuantizedAabbMin(rootNode_idx));
        unQuantize(bounds_1, rootNode.getQuantizedAabbMax(rootNode_idx));
        /* Add box cast extents */
        bounds_0.add(aabbMin);
        bounds_1.add(aabbMax);
        //#if 0
        //      bool ra2 = btRayAabb2 (raySource, rayDirection, sign, bounds, param, 0.0, lambda_max);
        //      bool ra = btRayAabb (raySource, rayTarget, bounds[0], bounds[1], param, normal);
        //      if (ra2 != ra)
        //      {
        //        printf("functions don't match\n");
        //      }
        //#endif
        //#ifdef RAYAABB2
        //      rayBoxOverlap = AabbUtil2.rayAabb2 (raySource, rayDirection, sign, bounds, param, 0.0, lambda_max);
        //#else
        rayBoxOverlap = AabbUtil2.rayAabb(raySource, rayTarget, bounds_0, bounds_1, param, normal);
        //#endif
      }

      if (isLeafNode && rayBoxOverlap) {
        nodeCallback.processNode(rootNode.getPartId(rootNode_idx), rootNode.getTriangleIndex(rootNode_idx));
      }

      if (rayBoxOverlap || isLeafNode) {
        rootNode_idx++;
        curIndex++;
      }
      else {
        escapeIndex = rootNode.getEscapeIndex(rootNode_idx);
        rootNode_idx += escapeIndex;
        curIndex += escapeIndex;
      }
    }
   
    if (maxIterations < walkIterations) {
      maxIterations = walkIterations;
    }
  }

  protected void walkStacklessQuantizedTree(NodeOverlapCallback nodeCallback, long quantizedQueryAabbMin, long quantizedQueryAabbMax, int startNodeIndex, int endNodeIndex) {
    assert (useQuantization);

    int curIndex = startNodeIndex;
    int walkIterations = 0;
    int subTreeSize = endNodeIndex - startNodeIndex;

    QuantizedBvhNodes rootNode = quantizedContiguousNodes;
    int rootNode_idx = startNodeIndex;
    int escapeIndex;

    boolean isLeafNode;
    boolean aabbOverlap;

    while (curIndex < endNodeIndex) {
      ////#define VISUALLY_ANALYZE_BVH 1
      //#ifdef VISUALLY_ANALYZE_BVH
      ////some code snippet to debugDraw aabb, to visually analyze bvh structure
      //static int drawPatch = 0;
      ////need some global access to a debugDrawer
      //extern btIDebugDraw* debugDrawerPtr;
      //if (curIndex==drawPatch)
      //{
      //  btVector3 aabbMin,aabbMax;
      //  aabbMin = unQuantize(rootNode->m_quantizedAabbMin);
      //  aabbMax = unQuantize(rootNode->m_quantizedAabbMax);
      //  btVector3  color(1,0,0);
      //  debugDrawerPtr->drawAabb(aabbMin,aabbMax,color);
      //}
      //#endif//VISUALLY_ANALYZE_BVH

      // catch bugs in tree data
      assert (walkIterations < subTreeSize);

      walkIterations++;
      aabbOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin, quantizedQueryAabbMax, rootNode.getQuantizedAabbMin(rootNode_idx), rootNode.getQuantizedAabbMax(rootNode_idx));
      isLeafNode = rootNode.isLeafNode(rootNode_idx);

      if (isLeafNode && aabbOverlap) {
        nodeCallback.processNode(rootNode.getPartId(rootNode_idx), rootNode.getTriangleIndex(rootNode_idx));
      }

      if (aabbOverlap || isLeafNode) {
        rootNode_idx++;
        curIndex++;
      }
      else {
        escapeIndex = rootNode.getEscapeIndex(rootNode_idx);
        rootNode_idx += escapeIndex;
        curIndex += escapeIndex;
      }
    }

    if (maxIterations < walkIterations) {
      maxIterations = walkIterations;
    }
  }
 
  public void reportRayOverlappingNodex(NodeOverlapCallback nodeCallback, Vector3f raySource, Vector3f rayTarget) {
    boolean fast_path = useQuantization && traversalMode == TraversalMode.STACKLESS;
    if (fast_path) {
      Vector3f tmp = Stack.alloc(Vector3f.class);
      tmp.set(0f, 0f, 0f);
      walkStacklessQuantizedTreeAgainstRay(nodeCallback, raySource, rayTarget, tmp, tmp, 0, curNodeIndex);
    }
    else {
      /* Otherwise fallback to AABB overlap test */
      Vector3f aabbMin = Stack.alloc(raySource);
      Vector3f aabbMax = Stack.alloc(raySource);
      VectorUtil.setMin(aabbMin, rayTarget);
      VectorUtil.setMax(aabbMax, rayTarget);
      reportAabbOverlappingNodex(nodeCallback, aabbMin, aabbMax);
    }
  }

  public void reportBoxCastOverlappingNodex(NodeOverlapCallback nodeCallback, Vector3f raySource, Vector3f rayTarget, Vector3f aabbMin, Vector3f aabbMax) {
    boolean fast_path = useQuantization && traversalMode == TraversalMode.STACKLESS;
    if (fast_path) {
      walkStacklessQuantizedTreeAgainstRay(nodeCallback, raySource, rayTarget, aabbMin, aabbMax, 0, curNodeIndex);
    }
    else {
      /* Slow path:
      Construct the bounding box for the entire box cast and send that down the tree */
      Vector3f qaabbMin = Stack.alloc(raySource);
      Vector3f qaabbMax = Stack.alloc(raySource);
      VectorUtil.setMin(qaabbMin, rayTarget);
      VectorUtil.setMax(qaabbMax, rayTarget);
      qaabbMin.add(aabbMin);
      qaabbMax.add(aabbMax);
      reportAabbOverlappingNodex(nodeCallback, qaabbMin, qaabbMax);
    }
  }
 
  public long quantizeWithClamp(Vector3f point) {
    assert (useQuantization);

    Vector3f clampedPoint = Stack.alloc(point);
    VectorUtil.setMax(clampedPoint, bvhAabbMin);
    VectorUtil.setMin(clampedPoint, bvhAabbMax);

    Vector3f v = Stack.alloc(Vector3f.class);
    v.sub(clampedPoint, bvhAabbMin);
    VectorUtil.mul(v, v, bvhQuantization);

    int out0 = (int)(v.x + 0.5f) & 0xFFFF;
    int out1 = (int)(v.y + 0.5f) & 0xFFFF;
    int out2 = (int)(v.z + 0.5f) & 0xFFFF;

    return ((long)out0) | (((long)out1) << 16) | (((long)out2) << 32);
  }
 
  public void unQuantize(Vector3f vecOut, long vecIn) {
    int vecIn0 = (int)((vecIn & 0x00000000FFFFL));
    int vecIn1 = (int)((vecIn & 0x0000FFFF0000L) >>> 16);
    int vecIn2 = (int)((vecIn & 0xFFFF00000000L) >>> 32);

    vecOut.x = (float)vecIn0 / (bvhQuantization.x);
    vecOut.y = (float)vecIn1 / (bvhQuantization.y);
    vecOut.z = (float)vecIn2 / (bvhQuantization.z);

    vecOut.add(bvhAabbMin);
  }
 
}
TOP

Related Classes of com.bulletphysics.collision.shapes.OptimizedBvh$QuantizedNodeTriangleCallback

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.