/** * Converts contained object to byte vector. * * @param bytes Vector to fill. */ void GridFloatHasheableObject::convertToBytes(std::vector<int8_t>& bytes) const { int32_t val = floatToRawIntBits(floatVal); bytes.resize(sizeof(val)); memset(&bytes[0], 0, sizeof(val)); GridClientByteUtils::valueToBytes(val, &bytes[0], sizeof(val), GridClientByteUtils::LITTLE_ENDIAN_ORDER); }
/** * Returns a representation of the specified floating-point value * according to the IEEE 754 floating-point "single format" bit * layout. * <p> * Bit 31 (the bit that is selected by the mask * <code>0x80000000</code>) represents the sign of the floating-point * number. * Bits 30-23 (the bits that are selected by the mask * <code>0x7f800000</code>) represent the exponent. * Bits 22-0 (the bits that are selected by the mask * <code>0x007fffff</code>) represent the significand (sometimes called * the mantissa) of the floating-point number. * <p>If the argument is positive infinity, the result is * <code>0x7f800000</code>. * <p>If the argument is negative infinity, the result is * <code>0xff800000</code>. * <p>If the argument is NaN, the result is <code>0x7fc00000</code>. * <p> * In all cases, the result is an integer that, when given to the * {@link #intBitsToFloat(int)} method, will produce a floating-point * value the same as the argument to <code>floatToIntBits</code> * (except all NaN values are collapsed to a single * "canonical" NaN value). * * @param value a floating-point number. * @return the bits that represent the floating-point number. */ int32_t GridFloatHasheableObject::floatToIntBits(float val) { int32_t result = floatToRawIntBits(val); // Check for NaN based on values of bit fields, maximum // exponent and nonzero significand. if ( ((result & FloatConsts::EXP_BIT_MASK) == FloatConsts::EXP_BIT_MASK) && (result & FloatConsts::SIGNIF_BIT_MASK) != 0) result = 0x7fc00000; return result; }
void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats) { if ((right - left + 1) <= dat.maxPrims || depth >= MAX_STACK_SIZE) { // write leaf node stats.updateLeaf(depth, right - left + 1); createNode(tempTree, nodeIndex, left, right); return; } // calculate extents int axis = -1, prevAxis, rightOrig; float clipL = G3D::fnan(), clipR = G3D::fnan(), prevClip = G3D::fnan(); float split = G3D::fnan(), prevSplit; bool wasLeft = true; while (true) { prevAxis = axis; prevSplit = split; // perform quick consistency checks Vector3 d( gridBox.hi - gridBox.lo ); if (d.x < 0 || d.y < 0 || d.z < 0) throw std::logic_error("negative node extents"); for (int i = 0; i < 3; i++) { if (nodeBox.hi[i] < gridBox.lo[i] || nodeBox.lo[i] > gridBox.hi[i]) { //UI.printError(Module.ACCEL, "Reached tree area in error - discarding node with: %d objects", right - left + 1); throw std::logic_error("invalid node overlap"); } } // find longest axis axis = d.primaryAxis(); split = 0.5f * (gridBox.lo[axis] + gridBox.hi[axis]); // partition L/R subsets clipL = -G3D::inf(); clipR = G3D::inf(); rightOrig = right; // save this for later float nodeL = G3D::inf(); float nodeR = -G3D::inf(); for (int i = left; i <= right;) { int obj = dat.indices[i]; float minb = dat.primBound[obj].low()[axis]; float maxb = dat.primBound[obj].high()[axis]; float center = (minb + maxb) * 0.5f; if (center <= split) { // stay left i++; if (clipL < maxb) clipL = maxb; } else { // move to the right most int t = dat.indices[i]; dat.indices[i] = dat.indices[right]; dat.indices[right] = t; right--; if (clipR > minb) clipR = minb; } nodeL = std::min(nodeL, minb); nodeR = std::max(nodeR, maxb); } // check for empty space if (nodeL > nodeBox.lo[axis] && nodeR < nodeBox.hi[axis]) { float nodeBoxW = nodeBox.hi[axis] - nodeBox.lo[axis]; float nodeNewW = nodeR - nodeL; // node box is too big compare to space occupied by primitives? if (1.3f * nodeNewW < nodeBoxW) { stats.updateBVH2(); int nextIndex = tempTree.size(); // allocate child tempTree.push_back(0); tempTree.push_back(0); tempTree.push_back(0); // write bvh2 clip node stats.updateInner(); tempTree[nodeIndex + 0] = (axis << 30) | (1 << 29) | nextIndex; tempTree[nodeIndex + 1] = floatToRawIntBits(nodeL); tempTree[nodeIndex + 2] = floatToRawIntBits(nodeR); // update nodebox and recurse nodeBox.lo[axis] = nodeL; nodeBox.hi[axis] = nodeR; subdivide(left, rightOrig, tempTree, dat, gridBox, nodeBox, nextIndex, depth + 1, stats); return; } } // ensure we are making progress in the subdivision if (right == rightOrig) { // all left if (prevAxis == axis && G3D::fuzzyEq(prevSplit, split)) { // we are stuck here - create a leaf stats.updateLeaf(depth, right - left + 1); createNode(tempTree, nodeIndex, left, right); return; } if (clipL <= split) { // keep looping on left half gridBox.hi[axis] = split; prevClip = clipL; wasLeft = true; continue; } gridBox.hi[axis] = split; prevClip = G3D::fnan(); } else if (left > right) { // all right if (prevAxis == axis && G3D::fuzzyEq(prevSplit, split)) { // we are stuck here - create a leaf stats.updateLeaf(depth, right - left + 1); createNode(tempTree, nodeIndex, left, right); return; } right = rightOrig; if (clipR >= split) { // keep looping on right half gridBox.lo[axis] = split; prevClip = clipR; wasLeft = false; continue; } gridBox.lo[axis] = split; prevClip = G3D::fnan(); } else { // we are actually splitting stuff if (prevAxis != -1 && !isnan(prevClip)) { // second time through - lets create the previous split // since it produced empty space int nextIndex = tempTree.size(); // allocate child node tempTree.push_back(0); tempTree.push_back(0); tempTree.push_back(0); if (wasLeft) { // create a node with a left child // write leaf node stats.updateInner(); tempTree[nodeIndex + 0] = (prevAxis << 30) | nextIndex; tempTree[nodeIndex + 1] = floatToRawIntBits(prevClip); tempTree[nodeIndex + 2] = floatToRawIntBits(G3D::inf()); } else { // create a node with a right child // write leaf node stats.updateInner(); tempTree[nodeIndex + 0] = (prevAxis << 30) | (nextIndex - 3); tempTree[nodeIndex + 1] = floatToRawIntBits(-G3D::inf()); tempTree[nodeIndex + 2] = floatToRawIntBits(prevClip); } // count stats for the unused leaf depth++; stats.updateLeaf(depth, 0); // now we keep going as we are, with a new nodeIndex: nodeIndex = nextIndex; } break; } } // compute index of child nodes int nextIndex = tempTree.size(); // allocate left node int nl = right - left + 1; int nr = rightOrig - (right + 1) + 1; if (nl > 0) { tempTree.push_back(0); tempTree.push_back(0); tempTree.push_back(0); } else nextIndex -= 3; // allocate right node if (nr > 0) { tempTree.push_back(0); tempTree.push_back(0); tempTree.push_back(0); } // write leaf node stats.updateInner(); tempTree[nodeIndex + 0] = (axis << 30) | nextIndex; tempTree[nodeIndex + 1] = floatToRawIntBits(clipL); tempTree[nodeIndex + 2] = floatToRawIntBits(clipR); // prepare L/R child boxes AABound gridBoxL(gridBox), gridBoxR(gridBox); AABound nodeBoxL(nodeBox), nodeBoxR(nodeBox); gridBoxL.hi[axis] = gridBoxR.lo[axis] = split; nodeBoxL.hi[axis] = clipL; nodeBoxR.lo[axis] = clipR; // recurse if (nl > 0) subdivide(left, right, tempTree, dat, gridBoxL, nodeBoxL, nextIndex, depth + 1, stats); else stats.updateLeaf(depth + 1, 0); if (nr > 0) subdivide(right + 1, rightOrig, tempTree, dat, gridBoxR, nodeBoxR, nextIndex + 3, depth + 1, stats); else stats.updateLeaf(depth + 1, 0); }