/* 
 | 
 * Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz> 
 | 
 * 
 | 
 * This source file is part of GIMPACT Library. 
 | 
 * 
 | 
 * For the latest info, see http://gimpact.sourceforge.net/ 
 | 
 * 
 | 
 * Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. 
 | 
 * email: projectileman@yahoo.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.extras.gimpact; 
 | 
  
 | 
import com.bulletphysics.extras.gimpact.BoxCollision.AABB; 
 | 
import com.bulletphysics.linearmath.VectorUtil; 
 | 
import cz.advel.stack.Stack; 
 | 
import javax.vecmath.Vector3f; 
 | 
  
 | 
/** 
 | 
 * 
 | 
 * @author jezek2 
 | 
 */ 
 | 
class BvhTree { 
 | 
  
 | 
    protected int num_nodes = 0; 
 | 
    protected BvhTreeNodeArray node_array = new BvhTreeNodeArray(); 
 | 
     
 | 
    protected int _calc_splitting_axis(BvhDataArray primitive_boxes, int startIndex, int endIndex) { 
 | 
        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); 
 | 
        Vector3f diff2 = Stack.alloc(Vector3f.class); 
 | 
  
 | 
        Vector3f tmp1 = Stack.alloc(Vector3f.class); 
 | 
        Vector3f tmp2 = Stack.alloc(Vector3f.class); 
 | 
  
 | 
        for (int i=startIndex; i<endIndex; i++) { 
 | 
            primitive_boxes.getBoundMax(i, tmp1); 
 | 
            primitive_boxes.getBoundMin(i, tmp2); 
 | 
            center.add(tmp1, tmp2); 
 | 
            center.scale(0.5f); 
 | 
            means.add(center); 
 | 
        } 
 | 
        means.scale(1f / (float)numIndices); 
 | 
  
 | 
        for (int i=startIndex; i<endIndex; i++) { 
 | 
            primitive_boxes.getBoundMax(i, tmp1); 
 | 
            primitive_boxes.getBoundMin(i, tmp2); 
 | 
            center.add(tmp1, tmp2); 
 | 
            center.scale(0.5f); 
 | 
            diff2.sub(center, means); 
 | 
            VectorUtil.mul(diff2, diff2, diff2); 
 | 
            variance.add(diff2); 
 | 
        } 
 | 
        variance.scale(1f / (float)(numIndices - 1)); 
 | 
  
 | 
        return VectorUtil.maxAxis(variance); 
 | 
    } 
 | 
  
 | 
    protected int _sort_and_calc_splitting_index(BvhDataArray primitive_boxes, int startIndex, int endIndex, int splitAxis) { 
 | 
        int splitIndex = startIndex; 
 | 
        int numIndices = endIndex - startIndex; 
 | 
  
 | 
        // average of centers 
 | 
        float splitValue = 0.0f; 
 | 
  
 | 
        Vector3f means = Stack.alloc(Vector3f.class); 
 | 
        means.set(0f, 0f, 0f); 
 | 
  
 | 
        Vector3f center = Stack.alloc(Vector3f.class); 
 | 
  
 | 
        Vector3f tmp1 = Stack.alloc(Vector3f.class); 
 | 
        Vector3f tmp2 = Stack.alloc(Vector3f.class); 
 | 
  
 | 
        for (int i = startIndex; i < endIndex; i++) { 
 | 
            primitive_boxes.getBoundMax(i, tmp1); 
 | 
            primitive_boxes.getBoundMin(i, tmp2); 
 | 
            center.add(tmp1, tmp2); 
 | 
            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 (int i = startIndex; i < endIndex; i++) { 
 | 
            primitive_boxes.getBoundMax(i, tmp1); 
 | 
            primitive_boxes.getBoundMin(i, tmp2); 
 | 
            center.add(tmp1, tmp2); 
 | 
            center.scale(0.5f); 
 | 
  
 | 
            if (VectorUtil.getCoord(center, splitAxis) > splitValue) { 
 | 
                // swap 
 | 
                primitive_boxes.swap(i, splitIndex); 
 | 
                //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 void _build_sub_tree(BvhDataArray primitive_boxes, int startIndex, int endIndex) { 
 | 
        int curIndex = num_nodes; 
 | 
        num_nodes++; 
 | 
  
 | 
        assert ((endIndex - startIndex) > 0); 
 | 
  
 | 
        if ((endIndex - startIndex) == 1) { 
 | 
            // We have a leaf node 
 | 
            //setNodeBound(curIndex,primitive_boxes[startIndex].m_bound); 
 | 
            //m_node_array[curIndex].setDataIndex(primitive_boxes[startIndex].m_data); 
 | 
            node_array.set(curIndex, primitive_boxes, startIndex); 
 | 
  
 | 
            return; 
 | 
        } 
 | 
        // calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'. 
 | 
  
 | 
        // split axis 
 | 
        int splitIndex = _calc_splitting_axis(primitive_boxes, startIndex, endIndex); 
 | 
  
 | 
        splitIndex = _sort_and_calc_splitting_index(primitive_boxes, startIndex, endIndex, splitIndex); 
 | 
  
 | 
        //calc this node bounding box 
 | 
  
 | 
        AABB node_bound = Stack.alloc(AABB.class); 
 | 
        AABB tmpAABB = Stack.alloc(AABB.class); 
 | 
  
 | 
        node_bound.invalidate(); 
 | 
  
 | 
        for (int i=startIndex; i<endIndex; i++) { 
 | 
            primitive_boxes.getBound(i, tmpAABB); 
 | 
            node_bound.merge(tmpAABB); 
 | 
        } 
 | 
  
 | 
        setNodeBound(curIndex, node_bound); 
 | 
  
 | 
        // build left branch 
 | 
        _build_sub_tree(primitive_boxes, startIndex, splitIndex); 
 | 
  
 | 
        // build right branch 
 | 
        _build_sub_tree(primitive_boxes, splitIndex, endIndex); 
 | 
  
 | 
        node_array.setEscapeIndex(curIndex, num_nodes - curIndex); 
 | 
    } 
 | 
     
 | 
    public void build_tree(BvhDataArray primitive_boxes) { 
 | 
        // initialize node count to 0 
 | 
        num_nodes = 0; 
 | 
        // allocate nodes 
 | 
        node_array.resize(primitive_boxes.size()*2); 
 | 
  
 | 
        _build_sub_tree(primitive_boxes, 0, primitive_boxes.size()); 
 | 
    } 
 | 
  
 | 
    public void clearNodes() { 
 | 
        node_array.clear(); 
 | 
        num_nodes = 0; 
 | 
    } 
 | 
  
 | 
    public int getNodeCount() { 
 | 
        return num_nodes; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Tells if the node is a leaf. 
 | 
     */ 
 | 
    public boolean isLeafNode(int nodeindex) { 
 | 
        return node_array.isLeafNode(nodeindex); 
 | 
    } 
 | 
  
 | 
    public int getNodeData(int nodeindex) { 
 | 
        return node_array.getDataIndex(nodeindex); 
 | 
    } 
 | 
  
 | 
    public void getNodeBound(int nodeindex, AABB bound) { 
 | 
        node_array.getBound(nodeindex, bound); 
 | 
    } 
 | 
  
 | 
    public void setNodeBound(int nodeindex, AABB bound) { 
 | 
        node_array.setBound(nodeindex, bound); 
 | 
    } 
 | 
  
 | 
    public int getLeftNode(int nodeindex) { 
 | 
        return nodeindex + 1; 
 | 
    } 
 | 
  
 | 
    public int getRightNode(int nodeindex) { 
 | 
        if (node_array.isLeafNode(nodeindex + 1)) { 
 | 
            return nodeindex + 2; 
 | 
        } 
 | 
        return nodeindex + 1 + node_array.getEscapeIndex(nodeindex + 1); 
 | 
    } 
 | 
  
 | 
    public int getEscapeNodeIndex(int nodeindex) { 
 | 
        return node_array.getEscapeIndex(nodeindex); 
 | 
    } 
 | 
  
 | 
    public BvhTreeNodeArray get_node_pointer() { 
 | 
        return node_array; 
 | 
    } 
 | 
     
 | 
} 
 |