/* 
 | 
 * 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 = (Vector3f) 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 = (Vector3f) Stack.alloc(raySource); 
 | 
        Vector3f rayAabbMax = (Vector3f) 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 = (Vector3f) Stack.alloc(raySource); 
 | 
            Vector3f aabbMax = (Vector3f) 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 = (Vector3f) Stack.alloc(raySource); 
 | 
            Vector3f qaabbMax = (Vector3f) 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 = (Vector3f) 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); 
 | 
    } 
 | 
     
 | 
} 
 |