2020-11-16 14:47:43 +08:00
|
|
|
/*
|
|
|
|
Bullet Continuous Collision Detection and Physics Library
|
2021-12-20 18:52:45 +08:00
|
|
|
Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
|
2020-11-16 14:47:43 +08:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
///btDbvt implementation by Nathanael Presson
|
|
|
|
|
|
|
|
#include "btDbvt.h"
|
|
|
|
|
|
|
|
//
|
|
|
|
typedef btAlignedObjectArray<btDbvtNode*> tNodeArray;
|
|
|
|
typedef btAlignedObjectArray<const btDbvtNode*> tConstNodeArray;
|
|
|
|
|
|
|
|
//
|
|
|
|
struct btDbvtNodeEnumerator : btDbvt::ICollide
|
|
|
|
{
|
|
|
|
tConstNodeArray nodes;
|
|
|
|
void Process(const btDbvtNode* n) { nodes.push_back(n); }
|
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
static DBVT_INLINE int indexof(const btDbvtNode* node)
|
|
|
|
{
|
|
|
|
return (node->parent->childs[1] == node);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static DBVT_INLINE btDbvtVolume merge(const btDbvtVolume& a,
|
|
|
|
const btDbvtVolume& b)
|
|
|
|
{
|
|
|
|
#ifdef BT_USE_SSE
|
|
|
|
ATTRIBUTE_ALIGNED16(char locals[sizeof(btDbvtAabbMm)]);
|
|
|
|
btDbvtVolume* ptr = (btDbvtVolume*)locals;
|
|
|
|
btDbvtVolume& res = *ptr;
|
|
|
|
#else
|
|
|
|
btDbvtVolume res;
|
|
|
|
#endif
|
|
|
|
Merge(a, b, res);
|
|
|
|
return (res);
|
|
|
|
}
|
|
|
|
|
|
|
|
// volume+edge lengths
|
|
|
|
static DBVT_INLINE btScalar size(const btDbvtVolume& a)
|
|
|
|
{
|
|
|
|
const btVector3 edges = a.Lengths();
|
|
|
|
return (edges.x() * edges.y() * edges.z() +
|
|
|
|
edges.x() + edges.y() + edges.z());
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static void getmaxdepth(const btDbvtNode* node, int depth, int& maxdepth)
|
|
|
|
{
|
|
|
|
if (node->isinternal())
|
|
|
|
{
|
|
|
|
getmaxdepth(node->childs[0], depth + 1, maxdepth);
|
|
|
|
getmaxdepth(node->childs[1], depth + 1, maxdepth);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
maxdepth = btMax(maxdepth, depth);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static DBVT_INLINE void deletenode(btDbvt* pdbvt,
|
|
|
|
btDbvtNode* node)
|
|
|
|
{
|
|
|
|
btAlignedFree(pdbvt->m_free);
|
|
|
|
pdbvt->m_free = node;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static void recursedeletenode(btDbvt* pdbvt,
|
|
|
|
btDbvtNode* node)
|
|
|
|
{
|
|
|
|
if (node == 0) return;
|
|
|
|
if (!node->isleaf())
|
|
|
|
{
|
|
|
|
recursedeletenode(pdbvt, node->childs[0]);
|
|
|
|
recursedeletenode(pdbvt, node->childs[1]);
|
|
|
|
}
|
|
|
|
if (node == pdbvt->m_root) pdbvt->m_root = 0;
|
|
|
|
deletenode(pdbvt, node);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static DBVT_INLINE btDbvtNode* createnode(btDbvt* pdbvt,
|
|
|
|
btDbvtNode* parent,
|
|
|
|
void* data)
|
|
|
|
{
|
|
|
|
btDbvtNode* node;
|
|
|
|
if (pdbvt->m_free)
|
|
|
|
{
|
|
|
|
node = pdbvt->m_free;
|
|
|
|
pdbvt->m_free = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
node = new (btAlignedAlloc(sizeof(btDbvtNode), 16)) btDbvtNode();
|
|
|
|
}
|
|
|
|
node->parent = parent;
|
|
|
|
node->data = data;
|
|
|
|
node->childs[1] = 0;
|
|
|
|
return (node);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static DBVT_INLINE btDbvtNode* createnode(btDbvt* pdbvt,
|
|
|
|
btDbvtNode* parent,
|
|
|
|
const btDbvtVolume& volume,
|
|
|
|
void* data)
|
|
|
|
{
|
|
|
|
btDbvtNode* node = createnode(pdbvt, parent, data);
|
|
|
|
node->volume = volume;
|
|
|
|
return (node);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static DBVT_INLINE btDbvtNode* createnode(btDbvt* pdbvt,
|
|
|
|
btDbvtNode* parent,
|
|
|
|
const btDbvtVolume& volume0,
|
|
|
|
const btDbvtVolume& volume1,
|
|
|
|
void* data)
|
|
|
|
{
|
|
|
|
btDbvtNode* node = createnode(pdbvt, parent, data);
|
|
|
|
Merge(volume0, volume1, node->volume);
|
|
|
|
return (node);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static void insertleaf(btDbvt* pdbvt,
|
|
|
|
btDbvtNode* root,
|
|
|
|
btDbvtNode* leaf)
|
|
|
|
{
|
|
|
|
if (!pdbvt->m_root)
|
|
|
|
{
|
|
|
|
pdbvt->m_root = leaf;
|
|
|
|
leaf->parent = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!root->isleaf())
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
root = root->childs[Select(leaf->volume,
|
|
|
|
root->childs[0]->volume,
|
|
|
|
root->childs[1]->volume)];
|
|
|
|
} while (!root->isleaf());
|
|
|
|
}
|
|
|
|
btDbvtNode* prev = root->parent;
|
|
|
|
btDbvtNode* node = createnode(pdbvt, prev, leaf->volume, root->volume, 0);
|
|
|
|
if (prev)
|
|
|
|
{
|
|
|
|
prev->childs[indexof(root)] = node;
|
|
|
|
node->childs[0] = root;
|
|
|
|
root->parent = node;
|
|
|
|
node->childs[1] = leaf;
|
|
|
|
leaf->parent = node;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (!prev->volume.Contain(node->volume))
|
|
|
|
Merge(prev->childs[0]->volume, prev->childs[1]->volume, prev->volume);
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
node = prev;
|
|
|
|
} while (0 != (prev = node->parent));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
node->childs[0] = root;
|
|
|
|
root->parent = node;
|
|
|
|
node->childs[1] = leaf;
|
|
|
|
leaf->parent = node;
|
|
|
|
pdbvt->m_root = node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static btDbvtNode* removeleaf(btDbvt* pdbvt,
|
|
|
|
btDbvtNode* leaf)
|
|
|
|
{
|
|
|
|
if (leaf == pdbvt->m_root)
|
|
|
|
{
|
|
|
|
pdbvt->m_root = 0;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
btDbvtNode* parent = leaf->parent;
|
|
|
|
btDbvtNode* prev = parent->parent;
|
|
|
|
btDbvtNode* sibling = parent->childs[1 - indexof(leaf)];
|
|
|
|
if (prev)
|
|
|
|
{
|
|
|
|
prev->childs[indexof(parent)] = sibling;
|
|
|
|
sibling->parent = prev;
|
|
|
|
deletenode(pdbvt, parent);
|
|
|
|
while (prev)
|
|
|
|
{
|
|
|
|
const btDbvtVolume pb = prev->volume;
|
|
|
|
Merge(prev->childs[0]->volume, prev->childs[1]->volume, prev->volume);
|
|
|
|
if (NotEqual(pb, prev->volume))
|
|
|
|
{
|
|
|
|
prev = prev->parent;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (prev ? prev : pdbvt->m_root);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pdbvt->m_root = sibling;
|
|
|
|
sibling->parent = 0;
|
|
|
|
deletenode(pdbvt, parent);
|
|
|
|
return (pdbvt->m_root);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static void fetchleaves(btDbvt* pdbvt,
|
|
|
|
btDbvtNode* root,
|
|
|
|
tNodeArray& leaves,
|
|
|
|
int depth = -1)
|
|
|
|
{
|
|
|
|
if (root->isinternal() && depth)
|
|
|
|
{
|
|
|
|
fetchleaves(pdbvt, root->childs[0], leaves, depth - 1);
|
|
|
|
fetchleaves(pdbvt, root->childs[1], leaves, depth - 1);
|
|
|
|
deletenode(pdbvt, root);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
leaves.push_back(root);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static bool leftOfAxis(const btDbvtNode* node,
|
|
|
|
const btVector3& org,
|
|
|
|
const btVector3& axis)
|
|
|
|
{
|
|
|
|
return btDot(axis, node->volume.Center() - org) <= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Partitions leaves such that leaves[0, n) are on the
|
|
|
|
// left of axis, and leaves[n, count) are on the right
|
|
|
|
// of axis. returns N.
|
|
|
|
static int split(btDbvtNode** leaves,
|
|
|
|
int count,
|
|
|
|
const btVector3& org,
|
|
|
|
const btVector3& axis)
|
|
|
|
{
|
|
|
|
int begin = 0;
|
|
|
|
int end = count;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
while (begin != end && leftOfAxis(leaves[begin], org, axis))
|
|
|
|
{
|
|
|
|
++begin;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (begin == end)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (begin != end && !leftOfAxis(leaves[end - 1], org, axis))
|
|
|
|
{
|
|
|
|
--end;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (begin == end)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// swap out of place nodes
|
|
|
|
--end;
|
|
|
|
btDbvtNode* temp = leaves[begin];
|
|
|
|
leaves[begin] = leaves[end];
|
|
|
|
leaves[end] = temp;
|
|
|
|
++begin;
|
|
|
|
}
|
|
|
|
|
|
|
|
return begin;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static btDbvtVolume bounds(btDbvtNode** leaves,
|
|
|
|
int count)
|
|
|
|
{
|
|
|
|
#ifdef BT_USE_SSE
|
|
|
|
ATTRIBUTE_ALIGNED16(char locals[sizeof(btDbvtVolume)]);
|
|
|
|
btDbvtVolume* ptr = (btDbvtVolume*)locals;
|
|
|
|
btDbvtVolume& volume = *ptr;
|
|
|
|
volume = leaves[0]->volume;
|
|
|
|
#else
|
|
|
|
btDbvtVolume volume = leaves[0]->volume;
|
|
|
|
#endif
|
|
|
|
for (int i = 1, ni = count; i < ni; ++i)
|
|
|
|
{
|
|
|
|
Merge(volume, leaves[i]->volume, volume);
|
|
|
|
}
|
|
|
|
return (volume);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static void bottomup(btDbvt* pdbvt,
|
|
|
|
btDbvtNode** leaves,
|
|
|
|
int count)
|
|
|
|
{
|
|
|
|
while (count > 1)
|
|
|
|
{
|
|
|
|
btScalar minsize = SIMD_INFINITY;
|
|
|
|
int minidx[2] = {-1, -1};
|
|
|
|
for (int i = 0; i < count; ++i)
|
|
|
|
{
|
|
|
|
for (int j = i + 1; j < count; ++j)
|
|
|
|
{
|
|
|
|
const btScalar sz = size(merge(leaves[i]->volume, leaves[j]->volume));
|
|
|
|
if (sz < minsize)
|
|
|
|
{
|
|
|
|
minsize = sz;
|
|
|
|
minidx[0] = i;
|
|
|
|
minidx[1] = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
btDbvtNode* n[] = {leaves[minidx[0]], leaves[minidx[1]]};
|
|
|
|
btDbvtNode* p = createnode(pdbvt, 0, n[0]->volume, n[1]->volume, 0);
|
|
|
|
p->childs[0] = n[0];
|
|
|
|
p->childs[1] = n[1];
|
|
|
|
n[0]->parent = p;
|
|
|
|
n[1]->parent = p;
|
|
|
|
leaves[minidx[0]] = p;
|
|
|
|
leaves[minidx[1]] = leaves[count - 1];
|
|
|
|
--count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static btDbvtNode* topdown(btDbvt* pdbvt,
|
|
|
|
btDbvtNode** leaves,
|
|
|
|
int count,
|
|
|
|
int bu_treshold)
|
|
|
|
{
|
|
|
|
static const btVector3 axis[] = {btVector3(1, 0, 0),
|
|
|
|
btVector3(0, 1, 0),
|
|
|
|
btVector3(0, 0, 1)};
|
|
|
|
btAssert(bu_treshold > 2);
|
|
|
|
if (count > 1)
|
|
|
|
{
|
|
|
|
if (count > bu_treshold)
|
|
|
|
{
|
|
|
|
const btDbvtVolume vol = bounds(leaves, count);
|
|
|
|
const btVector3 org = vol.Center();
|
|
|
|
int partition;
|
|
|
|
int bestaxis = -1;
|
|
|
|
int bestmidp = count;
|
|
|
|
int splitcount[3][2] = {{0, 0}, {0, 0}, {0, 0}};
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < count; ++i)
|
|
|
|
{
|
|
|
|
const btVector3 x = leaves[i]->volume.Center() - org;
|
|
|
|
for (int j = 0; j < 3; ++j)
|
|
|
|
{
|
|
|
|
++splitcount[j][btDot(x, axis[j]) > 0 ? 1 : 0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < 3; ++i)
|
|
|
|
{
|
|
|
|
if ((splitcount[i][0] > 0) && (splitcount[i][1] > 0))
|
|
|
|
{
|
|
|
|
const int midp = (int)btFabs(btScalar(splitcount[i][0] - splitcount[i][1]));
|
|
|
|
if (midp < bestmidp)
|
|
|
|
{
|
|
|
|
bestaxis = i;
|
|
|
|
bestmidp = midp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bestaxis >= 0)
|
|
|
|
{
|
|
|
|
partition = split(leaves, count, org, axis[bestaxis]);
|
|
|
|
btAssert(partition != 0 && partition != count);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
partition = count / 2 + 1;
|
|
|
|
}
|
|
|
|
btDbvtNode* node = createnode(pdbvt, 0, vol, 0);
|
|
|
|
node->childs[0] = topdown(pdbvt, &leaves[0], partition, bu_treshold);
|
|
|
|
node->childs[1] = topdown(pdbvt, &leaves[partition], count - partition, bu_treshold);
|
|
|
|
node->childs[0]->parent = node;
|
|
|
|
node->childs[1]->parent = node;
|
|
|
|
return (node);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bottomup(pdbvt, leaves, count);
|
|
|
|
return (leaves[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (leaves[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static DBVT_INLINE btDbvtNode* sort(btDbvtNode* n, btDbvtNode*& r)
|
|
|
|
{
|
|
|
|
btDbvtNode* p = n->parent;
|
|
|
|
btAssert(n->isinternal());
|
|
|
|
if (p > n)
|
|
|
|
{
|
|
|
|
const int i = indexof(n);
|
|
|
|
const int j = 1 - i;
|
|
|
|
btDbvtNode* s = p->childs[j];
|
|
|
|
btDbvtNode* q = p->parent;
|
|
|
|
btAssert(n == p->childs[i]);
|
|
|
|
if (q)
|
|
|
|
q->childs[indexof(p)] = n;
|
|
|
|
else
|
|
|
|
r = n;
|
|
|
|
s->parent = n;
|
|
|
|
p->parent = n;
|
|
|
|
n->parent = q;
|
|
|
|
p->childs[0] = n->childs[0];
|
|
|
|
p->childs[1] = n->childs[1];
|
|
|
|
n->childs[0]->parent = p;
|
|
|
|
n->childs[1]->parent = p;
|
|
|
|
n->childs[i] = p;
|
|
|
|
n->childs[j] = s;
|
|
|
|
btSwap(p->volume, n->volume);
|
|
|
|
return (p);
|
|
|
|
}
|
|
|
|
return (n);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static DBVT_INLINE btDbvtNode* walkup(btDbvtNode* n,int count)
|
|
|
|
{
|
|
|
|
while(n&&(count--)) n=n->parent;
|
|
|
|
return(n);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
|
|
// Api
|
|
|
|
//
|
|
|
|
|
|
|
|
//
|
|
|
|
btDbvt::btDbvt()
|
|
|
|
{
|
|
|
|
m_root = 0;
|
|
|
|
m_free = 0;
|
|
|
|
m_lkhd = -1;
|
|
|
|
m_leaves = 0;
|
|
|
|
m_opath = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
btDbvt::~btDbvt()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
void btDbvt::clear()
|
|
|
|
{
|
|
|
|
if (m_root)
|
|
|
|
recursedeletenode(this, m_root);
|
|
|
|
btAlignedFree(m_free);
|
|
|
|
m_free = 0;
|
|
|
|
m_lkhd = -1;
|
|
|
|
m_stkStack.clear();
|
|
|
|
m_opath = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
void btDbvt::optimizeBottomUp()
|
|
|
|
{
|
|
|
|
if (m_root)
|
|
|
|
{
|
|
|
|
tNodeArray leaves;
|
|
|
|
leaves.reserve(m_leaves);
|
|
|
|
fetchleaves(this, m_root, leaves);
|
|
|
|
bottomup(this, &leaves[0], leaves.size());
|
|
|
|
m_root = leaves[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
void btDbvt::optimizeTopDown(int bu_treshold)
|
|
|
|
{
|
|
|
|
if (m_root)
|
|
|
|
{
|
|
|
|
tNodeArray leaves;
|
|
|
|
leaves.reserve(m_leaves);
|
|
|
|
fetchleaves(this, m_root, leaves);
|
|
|
|
m_root = topdown(this, &leaves[0], leaves.size(), bu_treshold);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
void btDbvt::optimizeIncremental(int passes)
|
|
|
|
{
|
|
|
|
if (passes < 0) passes = m_leaves;
|
|
|
|
if (m_root && (passes > 0))
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
btDbvtNode* node = m_root;
|
|
|
|
unsigned bit = 0;
|
|
|
|
while (node->isinternal())
|
|
|
|
{
|
|
|
|
node = sort(node, m_root)->childs[(m_opath >> bit) & 1];
|
|
|
|
bit = (bit + 1) & (sizeof(unsigned) * 8 - 1);
|
|
|
|
}
|
|
|
|
update(node);
|
|
|
|
++m_opath;
|
|
|
|
} while (--passes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
btDbvtNode* btDbvt::insert(const btDbvtVolume& volume, void* data)
|
|
|
|
{
|
|
|
|
btDbvtNode* leaf = createnode(this, 0, volume, data);
|
|
|
|
insertleaf(this, m_root, leaf);
|
|
|
|
++m_leaves;
|
|
|
|
return (leaf);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
void btDbvt::update(btDbvtNode* leaf, int lookahead)
|
|
|
|
{
|
|
|
|
btDbvtNode* root = removeleaf(this, leaf);
|
|
|
|
if (root)
|
|
|
|
{
|
|
|
|
if (lookahead >= 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; (i < lookahead) && root->parent; ++i)
|
|
|
|
{
|
|
|
|
root = root->parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
root = m_root;
|
|
|
|
}
|
|
|
|
insertleaf(this, root, leaf);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
void btDbvt::update(btDbvtNode* leaf, btDbvtVolume& volume)
|
|
|
|
{
|
|
|
|
btDbvtNode* root = removeleaf(this, leaf);
|
|
|
|
if (root)
|
|
|
|
{
|
|
|
|
if (m_lkhd >= 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; (i < m_lkhd) && root->parent; ++i)
|
|
|
|
{
|
|
|
|
root = root->parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
root = m_root;
|
|
|
|
}
|
|
|
|
leaf->volume = volume;
|
|
|
|
insertleaf(this, root, leaf);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
bool btDbvt::update(btDbvtNode* leaf, btDbvtVolume& volume, const btVector3& velocity, btScalar margin)
|
|
|
|
{
|
|
|
|
if (leaf->volume.Contain(volume)) return (false);
|
|
|
|
volume.Expand(btVector3(margin, margin, margin));
|
|
|
|
volume.SignedExpand(velocity);
|
|
|
|
update(leaf, volume);
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
bool btDbvt::update(btDbvtNode* leaf, btDbvtVolume& volume, const btVector3& velocity)
|
|
|
|
{
|
|
|
|
if (leaf->volume.Contain(volume)) return (false);
|
|
|
|
volume.SignedExpand(velocity);
|
|
|
|
update(leaf, volume);
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
bool btDbvt::update(btDbvtNode* leaf, btDbvtVolume& volume, btScalar margin)
|
|
|
|
{
|
|
|
|
if (leaf->volume.Contain(volume)) return (false);
|
|
|
|
volume.Expand(btVector3(margin, margin, margin));
|
|
|
|
update(leaf, volume);
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
void btDbvt::remove(btDbvtNode* leaf)
|
|
|
|
{
|
|
|
|
removeleaf(this, leaf);
|
|
|
|
deletenode(this, leaf);
|
|
|
|
--m_leaves;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
void btDbvt::write(IWriter* iwriter) const
|
|
|
|
{
|
|
|
|
btDbvtNodeEnumerator nodes;
|
|
|
|
nodes.nodes.reserve(m_leaves * 2);
|
|
|
|
enumNodes(m_root, nodes);
|
|
|
|
iwriter->Prepare(m_root, nodes.nodes.size());
|
|
|
|
for (int i = 0; i < nodes.nodes.size(); ++i)
|
|
|
|
{
|
|
|
|
const btDbvtNode* n = nodes.nodes[i];
|
|
|
|
int p = -1;
|
|
|
|
if (n->parent) p = nodes.nodes.findLinearSearch(n->parent);
|
|
|
|
if (n->isinternal())
|
|
|
|
{
|
|
|
|
const int c0 = nodes.nodes.findLinearSearch(n->childs[0]);
|
|
|
|
const int c1 = nodes.nodes.findLinearSearch(n->childs[1]);
|
|
|
|
iwriter->WriteNode(n, i, p, c0, c1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iwriter->WriteLeaf(n, i, p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
void btDbvt::clone(btDbvt& dest, IClone* iclone) const
|
|
|
|
{
|
|
|
|
dest.clear();
|
|
|
|
if (m_root != 0)
|
|
|
|
{
|
|
|
|
btAlignedObjectArray<sStkCLN> stack;
|
|
|
|
stack.reserve(m_leaves);
|
|
|
|
stack.push_back(sStkCLN(m_root, 0));
|
|
|
|
do
|
|
|
|
{
|
|
|
|
const int i = stack.size() - 1;
|
|
|
|
const sStkCLN e = stack[i];
|
|
|
|
btDbvtNode* n = createnode(&dest, e.parent, e.node->volume, e.node->data);
|
|
|
|
stack.pop_back();
|
|
|
|
if (e.parent != 0)
|
|
|
|
e.parent->childs[i & 1] = n;
|
|
|
|
else
|
|
|
|
dest.m_root = n;
|
|
|
|
if (e.node->isinternal())
|
|
|
|
{
|
|
|
|
stack.push_back(sStkCLN(e.node->childs[0], n));
|
|
|
|
stack.push_back(sStkCLN(e.node->childs[1], n));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iclone->CloneLeaf(n);
|
|
|
|
}
|
|
|
|
} while (stack.size() > 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
int btDbvt::maxdepth(const btDbvtNode* node)
|
|
|
|
{
|
|
|
|
int depth = 0;
|
|
|
|
if (node) getmaxdepth(node, 1, depth);
|
|
|
|
return (depth);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
int btDbvt::countLeaves(const btDbvtNode* node)
|
|
|
|
{
|
|
|
|
if (node->isinternal())
|
|
|
|
return (countLeaves(node->childs[0]) + countLeaves(node->childs[1]));
|
|
|
|
else
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
void btDbvt::extractLeaves(const btDbvtNode* node, btAlignedObjectArray<const btDbvtNode*>& leaves)
|
|
|
|
{
|
|
|
|
if (node->isinternal())
|
|
|
|
{
|
|
|
|
extractLeaves(node->childs[0], leaves);
|
|
|
|
extractLeaves(node->childs[1], leaves);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
leaves.push_back(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
#if DBVT_ENABLE_BENCHMARK
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "LinearMath/btQuickProf.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
q6600,2.4ghz
|
|
|
|
|
|
|
|
/Ox /Ob2 /Oi /Ot /I "." /I "..\.." /I "..\..\src" /D "NDEBUG" /D "_LIB" /D "_WINDOWS" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "WIN32"
|
|
|
|
/GF /FD /MT /GS- /Gy /arch:SSE2 /Zc:wchar_t- /Fp"..\..\out\release8\build\libbulletcollision\libbulletcollision.pch"
|
|
|
|
/Fo"..\..\out\release8\build\libbulletcollision\\"
|
|
|
|
/Fd"..\..\out\release8\build\libbulletcollision\bulletcollision.pdb"
|
|
|
|
/W3 /nologo /c /Wp64 /Zi /errorReport:prompt
|
|
|
|
|
|
|
|
Benchmarking dbvt...
|
|
|
|
World scale: 100.000000
|
|
|
|
Extents base: 1.000000
|
|
|
|
Extents range: 4.000000
|
|
|
|
Leaves: 8192
|
|
|
|
sizeof(btDbvtVolume): 32 bytes
|
|
|
|
sizeof(btDbvtNode): 44 bytes
|
|
|
|
[1] btDbvtVolume intersections: 3499 ms (-1%)
|
|
|
|
[2] btDbvtVolume merges: 1934 ms (0%)
|
|
|
|
[3] btDbvt::collideTT: 5485 ms (-21%)
|
|
|
|
[4] btDbvt::collideTT self: 2814 ms (-20%)
|
|
|
|
[5] btDbvt::collideTT xform: 7379 ms (-1%)
|
|
|
|
[6] btDbvt::collideTT xform,self: 7270 ms (-2%)
|
|
|
|
[7] btDbvt::rayTest: 6314 ms (0%),(332143 r/s)
|
|
|
|
[8] insert/remove: 2093 ms (0%),(1001983 ir/s)
|
|
|
|
[9] updates (teleport): 1879 ms (-3%),(1116100 u/s)
|
|
|
|
[10] updates (jitter): 1244 ms (-4%),(1685813 u/s)
|
|
|
|
[11] optimize (incremental): 2514 ms (0%),(1668000 o/s)
|
|
|
|
[12] btDbvtVolume notequal: 3659 ms (0%)
|
|
|
|
[13] culling(OCL+fullsort): 2218 ms (0%),(461 t/s)
|
|
|
|
[14] culling(OCL+qsort): 3688 ms (5%),(2221 t/s)
|
|
|
|
[15] culling(KDOP+qsort): 1139 ms (-1%),(7192 t/s)
|
|
|
|
[16] insert/remove batch(256): 5092 ms (0%),(823704 bir/s)
|
|
|
|
[17] btDbvtVolume select: 3419 ms (0%)
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct btDbvtBenchmark
|
|
|
|
{
|
|
|
|
struct NilPolicy : btDbvt::ICollide
|
|
|
|
{
|
|
|
|
NilPolicy() : m_pcount(0), m_depth(-SIMD_INFINITY), m_checksort(true) {}
|
|
|
|
void Process(const btDbvtNode*, const btDbvtNode*) { ++m_pcount; }
|
|
|
|
void Process(const btDbvtNode*) { ++m_pcount; }
|
|
|
|
void Process(const btDbvtNode*, btScalar depth)
|
|
|
|
{
|
|
|
|
++m_pcount;
|
|
|
|
if (m_checksort)
|
|
|
|
{
|
|
|
|
if (depth >= m_depth)
|
|
|
|
m_depth = depth;
|
|
|
|
else
|
|
|
|
printf("wrong depth: %f (should be >= %f)\r\n", depth, m_depth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int m_pcount;
|
|
|
|
btScalar m_depth;
|
|
|
|
bool m_checksort;
|
|
|
|
};
|
|
|
|
struct P14 : btDbvt::ICollide
|
|
|
|
{
|
|
|
|
struct Node
|
|
|
|
{
|
|
|
|
const btDbvtNode* leaf;
|
|
|
|
btScalar depth;
|
|
|
|
};
|
|
|
|
void Process(const btDbvtNode* leaf, btScalar depth)
|
|
|
|
{
|
|
|
|
Node n;
|
|
|
|
n.leaf = leaf;
|
|
|
|
n.depth = depth;
|
|
|
|
}
|
|
|
|
static int sortfnc(const Node& a, const Node& b)
|
|
|
|
{
|
|
|
|
if (a.depth < b.depth) return (+1);
|
|
|
|
if (a.depth > b.depth) return (-1);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
btAlignedObjectArray<Node> m_nodes;
|
|
|
|
};
|
|
|
|
struct P15 : btDbvt::ICollide
|
|
|
|
{
|
|
|
|
struct Node
|
|
|
|
{
|
|
|
|
const btDbvtNode* leaf;
|
|
|
|
btScalar depth;
|
|
|
|
};
|
|
|
|
void Process(const btDbvtNode* leaf)
|
|
|
|
{
|
|
|
|
Node n;
|
|
|
|
n.leaf = leaf;
|
|
|
|
n.depth = dot(leaf->volume.Center(), m_axis);
|
|
|
|
}
|
|
|
|
static int sortfnc(const Node& a, const Node& b)
|
|
|
|
{
|
|
|
|
if (a.depth < b.depth) return (+1);
|
|
|
|
if (a.depth > b.depth) return (-1);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
btAlignedObjectArray<Node> m_nodes;
|
|
|
|
btVector3 m_axis;
|
|
|
|
};
|
|
|
|
static btScalar RandUnit()
|
|
|
|
{
|
|
|
|
return (rand() / (btScalar)RAND_MAX);
|
|
|
|
}
|
|
|
|
static btVector3 RandVector3()
|
|
|
|
{
|
|
|
|
return (btVector3(RandUnit(), RandUnit(), RandUnit()));
|
|
|
|
}
|
|
|
|
static btVector3 RandVector3(btScalar cs)
|
|
|
|
{
|
|
|
|
return (RandVector3() * cs - btVector3(cs, cs, cs) / 2);
|
|
|
|
}
|
|
|
|
static btDbvtVolume RandVolume(btScalar cs, btScalar eb, btScalar es)
|
|
|
|
{
|
|
|
|
return (btDbvtVolume::FromCE(RandVector3(cs), btVector3(eb, eb, eb) + RandVector3() * es));
|
|
|
|
}
|
|
|
|
static btTransform RandTransform(btScalar cs)
|
|
|
|
{
|
|
|
|
btTransform t;
|
|
|
|
t.setOrigin(RandVector3(cs));
|
|
|
|
t.setRotation(btQuaternion(RandUnit() * SIMD_PI * 2, RandUnit() * SIMD_PI * 2, RandUnit() * SIMD_PI * 2).normalized());
|
|
|
|
return (t);
|
|
|
|
}
|
|
|
|
static void RandTree(btScalar cs, btScalar eb, btScalar es, int leaves, btDbvt& dbvt)
|
|
|
|
{
|
|
|
|
dbvt.clear();
|
|
|
|
for (int i = 0; i < leaves; ++i)
|
|
|
|
{
|
|
|
|
dbvt.insert(RandVolume(cs, eb, es), 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void btDbvt::benchmark()
|
|
|
|
{
|
|
|
|
static const btScalar cfgVolumeCenterScale = 100;
|
|
|
|
static const btScalar cfgVolumeExentsBase = 1;
|
|
|
|
static const btScalar cfgVolumeExentsScale = 4;
|
|
|
|
static const int cfgLeaves = 8192;
|
|
|
|
static const bool cfgEnable = true;
|
|
|
|
|
|
|
|
//[1] btDbvtVolume intersections
|
|
|
|
bool cfgBenchmark1_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark1_Iterations = 8;
|
|
|
|
static const int cfgBenchmark1_Reference = 3499;
|
|
|
|
//[2] btDbvtVolume merges
|
|
|
|
bool cfgBenchmark2_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark2_Iterations = 4;
|
|
|
|
static const int cfgBenchmark2_Reference = 1945;
|
|
|
|
//[3] btDbvt::collideTT
|
|
|
|
bool cfgBenchmark3_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark3_Iterations = 512;
|
|
|
|
static const int cfgBenchmark3_Reference = 5485;
|
|
|
|
//[4] btDbvt::collideTT self
|
|
|
|
bool cfgBenchmark4_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark4_Iterations = 512;
|
|
|
|
static const int cfgBenchmark4_Reference = 2814;
|
|
|
|
//[5] btDbvt::collideTT xform
|
|
|
|
bool cfgBenchmark5_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark5_Iterations = 512;
|
|
|
|
static const btScalar cfgBenchmark5_OffsetScale = 2;
|
|
|
|
static const int cfgBenchmark5_Reference = 7379;
|
|
|
|
//[6] btDbvt::collideTT xform,self
|
|
|
|
bool cfgBenchmark6_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark6_Iterations = 512;
|
|
|
|
static const btScalar cfgBenchmark6_OffsetScale = 2;
|
|
|
|
static const int cfgBenchmark6_Reference = 7270;
|
|
|
|
//[7] btDbvt::rayTest
|
|
|
|
bool cfgBenchmark7_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark7_Passes = 32;
|
|
|
|
static const int cfgBenchmark7_Iterations = 65536;
|
|
|
|
static const int cfgBenchmark7_Reference = 6307;
|
|
|
|
//[8] insert/remove
|
|
|
|
bool cfgBenchmark8_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark8_Passes = 32;
|
|
|
|
static const int cfgBenchmark8_Iterations = 65536;
|
|
|
|
static const int cfgBenchmark8_Reference = 2105;
|
|
|
|
//[9] updates (teleport)
|
|
|
|
bool cfgBenchmark9_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark9_Passes = 32;
|
|
|
|
static const int cfgBenchmark9_Iterations = 65536;
|
|
|
|
static const int cfgBenchmark9_Reference = 1879;
|
|
|
|
//[10] updates (jitter)
|
|
|
|
bool cfgBenchmark10_Enable = cfgEnable;
|
|
|
|
static const btScalar cfgBenchmark10_Scale = cfgVolumeCenterScale / 10000;
|
|
|
|
static const int cfgBenchmark10_Passes = 32;
|
|
|
|
static const int cfgBenchmark10_Iterations = 65536;
|
|
|
|
static const int cfgBenchmark10_Reference = 1244;
|
|
|
|
//[11] optimize (incremental)
|
|
|
|
bool cfgBenchmark11_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark11_Passes = 64;
|
|
|
|
static const int cfgBenchmark11_Iterations = 65536;
|
|
|
|
static const int cfgBenchmark11_Reference = 2510;
|
|
|
|
//[12] btDbvtVolume notequal
|
|
|
|
bool cfgBenchmark12_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark12_Iterations = 32;
|
|
|
|
static const int cfgBenchmark12_Reference = 3677;
|
|
|
|
//[13] culling(OCL+fullsort)
|
|
|
|
bool cfgBenchmark13_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark13_Iterations = 1024;
|
|
|
|
static const int cfgBenchmark13_Reference = 2231;
|
|
|
|
//[14] culling(OCL+qsort)
|
|
|
|
bool cfgBenchmark14_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark14_Iterations = 8192;
|
|
|
|
static const int cfgBenchmark14_Reference = 3500;
|
|
|
|
//[15] culling(KDOP+qsort)
|
|
|
|
bool cfgBenchmark15_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark15_Iterations = 8192;
|
|
|
|
static const int cfgBenchmark15_Reference = 1151;
|
|
|
|
//[16] insert/remove batch
|
|
|
|
bool cfgBenchmark16_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark16_BatchCount = 256;
|
|
|
|
static const int cfgBenchmark16_Passes = 16384;
|
|
|
|
static const int cfgBenchmark16_Reference = 5138;
|
|
|
|
//[17] select
|
|
|
|
bool cfgBenchmark17_Enable = cfgEnable;
|
|
|
|
static const int cfgBenchmark17_Iterations = 4;
|
|
|
|
static const int cfgBenchmark17_Reference = 3390;
|
|
|
|
|
|
|
|
btClock wallclock;
|
|
|
|
printf("Benchmarking dbvt...\r\n");
|
|
|
|
printf("\tWorld scale: %f\r\n", cfgVolumeCenterScale);
|
|
|
|
printf("\tExtents base: %f\r\n", cfgVolumeExentsBase);
|
|
|
|
printf("\tExtents range: %f\r\n", cfgVolumeExentsScale);
|
|
|
|
printf("\tLeaves: %u\r\n", cfgLeaves);
|
|
|
|
printf("\tsizeof(btDbvtVolume): %u bytes\r\n", sizeof(btDbvtVolume));
|
|
|
|
printf("\tsizeof(btDbvtNode): %u bytes\r\n", sizeof(btDbvtNode));
|
|
|
|
if (cfgBenchmark1_Enable)
|
|
|
|
{ // Benchmark 1
|
|
|
|
srand(380843);
|
|
|
|
btAlignedObjectArray<btDbvtVolume> volumes;
|
|
|
|
btAlignedObjectArray<bool> results;
|
|
|
|
volumes.resize(cfgLeaves);
|
|
|
|
results.resize(cfgLeaves);
|
|
|
|
for (int i = 0; i < cfgLeaves; ++i)
|
|
|
|
{
|
|
|
|
volumes[i] = btDbvtBenchmark::RandVolume(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale);
|
|
|
|
}
|
|
|
|
printf("[1] btDbvtVolume intersections: ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark1_Iterations; ++i)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < cfgLeaves; ++j)
|
|
|
|
{
|
|
|
|
for (int k = 0; k < cfgLeaves; ++k)
|
|
|
|
{
|
|
|
|
results[k] = Intersect(volumes[j], volumes[k]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
printf("%u ms (%i%%)\r\n", time, (time - cfgBenchmark1_Reference) * 100 / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark2_Enable)
|
|
|
|
{ // Benchmark 2
|
|
|
|
srand(380843);
|
|
|
|
btAlignedObjectArray<btDbvtVolume> volumes;
|
|
|
|
btAlignedObjectArray<btDbvtVolume> results;
|
|
|
|
volumes.resize(cfgLeaves);
|
|
|
|
results.resize(cfgLeaves);
|
|
|
|
for (int i = 0; i < cfgLeaves; ++i)
|
|
|
|
{
|
|
|
|
volumes[i] = btDbvtBenchmark::RandVolume(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale);
|
|
|
|
}
|
|
|
|
printf("[2] btDbvtVolume merges: ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark2_Iterations; ++i)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < cfgLeaves; ++j)
|
|
|
|
{
|
|
|
|
for (int k = 0; k < cfgLeaves; ++k)
|
|
|
|
{
|
|
|
|
Merge(volumes[j], volumes[k], results[k]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
printf("%u ms (%i%%)\r\n", time, (time - cfgBenchmark2_Reference) * 100 / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark3_Enable)
|
|
|
|
{ // Benchmark 3
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt[2];
|
|
|
|
btDbvtBenchmark::NilPolicy policy;
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt[0]);
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt[1]);
|
|
|
|
dbvt[0].optimizeTopDown();
|
|
|
|
dbvt[1].optimizeTopDown();
|
|
|
|
printf("[3] btDbvt::collideTT: ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark3_Iterations; ++i)
|
|
|
|
{
|
|
|
|
btDbvt::collideTT(dbvt[0].m_root, dbvt[1].m_root, policy);
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
printf("%u ms (%i%%)\r\n", time, (time - cfgBenchmark3_Reference) * 100 / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark4_Enable)
|
|
|
|
{ // Benchmark 4
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt;
|
|
|
|
btDbvtBenchmark::NilPolicy policy;
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt);
|
|
|
|
dbvt.optimizeTopDown();
|
|
|
|
printf("[4] btDbvt::collideTT self: ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark4_Iterations; ++i)
|
|
|
|
{
|
|
|
|
btDbvt::collideTT(dbvt.m_root, dbvt.m_root, policy);
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
printf("%u ms (%i%%)\r\n", time, (time - cfgBenchmark4_Reference) * 100 / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark5_Enable)
|
|
|
|
{ // Benchmark 5
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt[2];
|
|
|
|
btAlignedObjectArray<btTransform> transforms;
|
|
|
|
btDbvtBenchmark::NilPolicy policy;
|
|
|
|
transforms.resize(cfgBenchmark5_Iterations);
|
|
|
|
for (int i = 0; i < transforms.size(); ++i)
|
|
|
|
{
|
|
|
|
transforms[i] = btDbvtBenchmark::RandTransform(cfgVolumeCenterScale * cfgBenchmark5_OffsetScale);
|
|
|
|
}
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt[0]);
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt[1]);
|
|
|
|
dbvt[0].optimizeTopDown();
|
|
|
|
dbvt[1].optimizeTopDown();
|
|
|
|
printf("[5] btDbvt::collideTT xform: ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark5_Iterations; ++i)
|
|
|
|
{
|
|
|
|
btDbvt::collideTT(dbvt[0].m_root, dbvt[1].m_root, transforms[i], policy);
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
printf("%u ms (%i%%)\r\n", time, (time - cfgBenchmark5_Reference) * 100 / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark6_Enable)
|
|
|
|
{ // Benchmark 6
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt;
|
|
|
|
btAlignedObjectArray<btTransform> transforms;
|
|
|
|
btDbvtBenchmark::NilPolicy policy;
|
|
|
|
transforms.resize(cfgBenchmark6_Iterations);
|
|
|
|
for (int i = 0; i < transforms.size(); ++i)
|
|
|
|
{
|
|
|
|
transforms[i] = btDbvtBenchmark::RandTransform(cfgVolumeCenterScale * cfgBenchmark6_OffsetScale);
|
|
|
|
}
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt);
|
|
|
|
dbvt.optimizeTopDown();
|
|
|
|
printf("[6] btDbvt::collideTT xform,self: ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark6_Iterations; ++i)
|
|
|
|
{
|
|
|
|
btDbvt::collideTT(dbvt.m_root, dbvt.m_root, transforms[i], policy);
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
printf("%u ms (%i%%)\r\n", time, (time - cfgBenchmark6_Reference) * 100 / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark7_Enable)
|
|
|
|
{ // Benchmark 7
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt;
|
|
|
|
btAlignedObjectArray<btVector3> rayorg;
|
|
|
|
btAlignedObjectArray<btVector3> raydir;
|
|
|
|
btDbvtBenchmark::NilPolicy policy;
|
|
|
|
rayorg.resize(cfgBenchmark7_Iterations);
|
|
|
|
raydir.resize(cfgBenchmark7_Iterations);
|
|
|
|
for (int i = 0; i < rayorg.size(); ++i)
|
|
|
|
{
|
|
|
|
rayorg[i] = btDbvtBenchmark::RandVector3(cfgVolumeCenterScale * 2);
|
|
|
|
raydir[i] = btDbvtBenchmark::RandVector3(cfgVolumeCenterScale * 2);
|
|
|
|
}
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt);
|
|
|
|
dbvt.optimizeTopDown();
|
|
|
|
printf("[7] btDbvt::rayTest: ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark7_Passes; ++i)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < cfgBenchmark7_Iterations; ++j)
|
|
|
|
{
|
|
|
|
btDbvt::rayTest(dbvt.m_root, rayorg[j], rayorg[j] + raydir[j], policy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
unsigned rays = cfgBenchmark7_Passes * cfgBenchmark7_Iterations;
|
|
|
|
printf("%u ms (%i%%),(%u r/s)\r\n", time, (time - cfgBenchmark7_Reference) * 100 / time, (rays * 1000) / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark8_Enable)
|
|
|
|
{ // Benchmark 8
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt;
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt);
|
|
|
|
dbvt.optimizeTopDown();
|
|
|
|
printf("[8] insert/remove: ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark8_Passes; ++i)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < cfgBenchmark8_Iterations; ++j)
|
|
|
|
{
|
|
|
|
dbvt.remove(dbvt.insert(btDbvtBenchmark::RandVolume(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale), 0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
const int ir = cfgBenchmark8_Passes * cfgBenchmark8_Iterations;
|
|
|
|
printf("%u ms (%i%%),(%u ir/s)\r\n", time, (time - cfgBenchmark8_Reference) * 100 / time, ir * 1000 / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark9_Enable)
|
|
|
|
{ // Benchmark 9
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt;
|
|
|
|
btAlignedObjectArray<const btDbvtNode*> leaves;
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt);
|
|
|
|
dbvt.optimizeTopDown();
|
|
|
|
dbvt.extractLeaves(dbvt.m_root, leaves);
|
|
|
|
printf("[9] updates (teleport): ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark9_Passes; ++i)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < cfgBenchmark9_Iterations; ++j)
|
|
|
|
{
|
|
|
|
dbvt.update(const_cast<btDbvtNode*>(leaves[rand() % cfgLeaves]),
|
|
|
|
btDbvtBenchmark::RandVolume(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
const int up = cfgBenchmark9_Passes * cfgBenchmark9_Iterations;
|
|
|
|
printf("%u ms (%i%%),(%u u/s)\r\n", time, (time - cfgBenchmark9_Reference) * 100 / time, up * 1000 / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark10_Enable)
|
|
|
|
{ // Benchmark 10
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt;
|
|
|
|
btAlignedObjectArray<const btDbvtNode*> leaves;
|
|
|
|
btAlignedObjectArray<btVector3> vectors;
|
|
|
|
vectors.resize(cfgBenchmark10_Iterations);
|
|
|
|
for (int i = 0; i < vectors.size(); ++i)
|
|
|
|
{
|
|
|
|
vectors[i] = (btDbvtBenchmark::RandVector3() * 2 - btVector3(1, 1, 1)) * cfgBenchmark10_Scale;
|
|
|
|
}
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt);
|
|
|
|
dbvt.optimizeTopDown();
|
|
|
|
dbvt.extractLeaves(dbvt.m_root, leaves);
|
|
|
|
printf("[10] updates (jitter): ");
|
|
|
|
wallclock.reset();
|
|
|
|
|
|
|
|
for (int i = 0; i < cfgBenchmark10_Passes; ++i)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < cfgBenchmark10_Iterations; ++j)
|
|
|
|
{
|
|
|
|
const btVector3& d = vectors[j];
|
|
|
|
btDbvtNode* l = const_cast<btDbvtNode*>(leaves[rand() % cfgLeaves]);
|
|
|
|
btDbvtVolume v = btDbvtVolume::FromMM(l->volume.Mins() + d, l->volume.Maxs() + d);
|
|
|
|
dbvt.update(l, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
const int up = cfgBenchmark10_Passes * cfgBenchmark10_Iterations;
|
|
|
|
printf("%u ms (%i%%),(%u u/s)\r\n", time, (time - cfgBenchmark10_Reference) * 100 / time, up * 1000 / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark11_Enable)
|
|
|
|
{ // Benchmark 11
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt;
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt);
|
|
|
|
dbvt.optimizeTopDown();
|
|
|
|
printf("[11] optimize (incremental): ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark11_Passes; ++i)
|
|
|
|
{
|
|
|
|
dbvt.optimizeIncremental(cfgBenchmark11_Iterations);
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
const int op = cfgBenchmark11_Passes * cfgBenchmark11_Iterations;
|
|
|
|
printf("%u ms (%i%%),(%u o/s)\r\n", time, (time - cfgBenchmark11_Reference) * 100 / time, op / time * 1000);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark12_Enable)
|
|
|
|
{ // Benchmark 12
|
|
|
|
srand(380843);
|
|
|
|
btAlignedObjectArray<btDbvtVolume> volumes;
|
|
|
|
btAlignedObjectArray<bool> results;
|
|
|
|
volumes.resize(cfgLeaves);
|
|
|
|
results.resize(cfgLeaves);
|
|
|
|
for (int i = 0; i < cfgLeaves; ++i)
|
|
|
|
{
|
|
|
|
volumes[i] = btDbvtBenchmark::RandVolume(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale);
|
|
|
|
}
|
|
|
|
printf("[12] btDbvtVolume notequal: ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark12_Iterations; ++i)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < cfgLeaves; ++j)
|
|
|
|
{
|
|
|
|
for (int k = 0; k < cfgLeaves; ++k)
|
|
|
|
{
|
|
|
|
results[k] = NotEqual(volumes[j], volumes[k]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
printf("%u ms (%i%%)\r\n", time, (time - cfgBenchmark12_Reference) * 100 / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark13_Enable)
|
|
|
|
{ // Benchmark 13
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt;
|
|
|
|
btAlignedObjectArray<btVector3> vectors;
|
|
|
|
btDbvtBenchmark::NilPolicy policy;
|
|
|
|
vectors.resize(cfgBenchmark13_Iterations);
|
|
|
|
for (int i = 0; i < vectors.size(); ++i)
|
|
|
|
{
|
|
|
|
vectors[i] = (btDbvtBenchmark::RandVector3() * 2 - btVector3(1, 1, 1)).normalized();
|
|
|
|
}
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt);
|
|
|
|
dbvt.optimizeTopDown();
|
|
|
|
printf("[13] culling(OCL+fullsort): ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark13_Iterations; ++i)
|
|
|
|
{
|
|
|
|
static const btScalar offset = 0;
|
|
|
|
policy.m_depth = -SIMD_INFINITY;
|
|
|
|
dbvt.collideOCL(dbvt.m_root, &vectors[i], &offset, vectors[i], 1, policy);
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
const int t = cfgBenchmark13_Iterations;
|
|
|
|
printf("%u ms (%i%%),(%u t/s)\r\n", time, (time - cfgBenchmark13_Reference) * 100 / time, (t * 1000) / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark14_Enable)
|
|
|
|
{ // Benchmark 14
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt;
|
|
|
|
btAlignedObjectArray<btVector3> vectors;
|
|
|
|
btDbvtBenchmark::P14 policy;
|
|
|
|
vectors.resize(cfgBenchmark14_Iterations);
|
|
|
|
for (int i = 0; i < vectors.size(); ++i)
|
|
|
|
{
|
|
|
|
vectors[i] = (btDbvtBenchmark::RandVector3() * 2 - btVector3(1, 1, 1)).normalized();
|
|
|
|
}
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt);
|
|
|
|
dbvt.optimizeTopDown();
|
|
|
|
policy.m_nodes.reserve(cfgLeaves);
|
|
|
|
printf("[14] culling(OCL+qsort): ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark14_Iterations; ++i)
|
|
|
|
{
|
|
|
|
static const btScalar offset = 0;
|
|
|
|
policy.m_nodes.resize(0);
|
|
|
|
dbvt.collideOCL(dbvt.m_root, &vectors[i], &offset, vectors[i], 1, policy, false);
|
|
|
|
policy.m_nodes.quickSort(btDbvtBenchmark::P14::sortfnc);
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
const int t = cfgBenchmark14_Iterations;
|
|
|
|
printf("%u ms (%i%%),(%u t/s)\r\n", time, (time - cfgBenchmark14_Reference) * 100 / time, (t * 1000) / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark15_Enable)
|
|
|
|
{ // Benchmark 15
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt;
|
|
|
|
btAlignedObjectArray<btVector3> vectors;
|
|
|
|
btDbvtBenchmark::P15 policy;
|
|
|
|
vectors.resize(cfgBenchmark15_Iterations);
|
|
|
|
for (int i = 0; i < vectors.size(); ++i)
|
|
|
|
{
|
|
|
|
vectors[i] = (btDbvtBenchmark::RandVector3() * 2 - btVector3(1, 1, 1)).normalized();
|
|
|
|
}
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt);
|
|
|
|
dbvt.optimizeTopDown();
|
|
|
|
policy.m_nodes.reserve(cfgLeaves);
|
|
|
|
printf("[15] culling(KDOP+qsort): ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark15_Iterations; ++i)
|
|
|
|
{
|
|
|
|
static const btScalar offset = 0;
|
|
|
|
policy.m_nodes.resize(0);
|
|
|
|
policy.m_axis = vectors[i];
|
|
|
|
dbvt.collideKDOP(dbvt.m_root, &vectors[i], &offset, 1, policy);
|
|
|
|
policy.m_nodes.quickSort(btDbvtBenchmark::P15::sortfnc);
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
const int t = cfgBenchmark15_Iterations;
|
|
|
|
printf("%u ms (%i%%),(%u t/s)\r\n", time, (time - cfgBenchmark15_Reference) * 100 / time, (t * 1000) / time);
|
|
|
|
}
|
|
|
|
if (cfgBenchmark16_Enable)
|
|
|
|
{ // Benchmark 16
|
|
|
|
srand(380843);
|
|
|
|
btDbvt dbvt;
|
|
|
|
btAlignedObjectArray<btDbvtNode*> batch;
|
|
|
|
btDbvtBenchmark::RandTree(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale, cfgLeaves, dbvt);
|
|
|
|
dbvt.optimizeTopDown();
|
|
|
|
batch.reserve(cfgBenchmark16_BatchCount);
|
|
|
|
printf("[16] insert/remove batch(%u): ", cfgBenchmark16_BatchCount);
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark16_Passes; ++i)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < cfgBenchmark16_BatchCount; ++j)
|
|
|
|
{
|
|
|
|
batch.push_back(dbvt.insert(btDbvtBenchmark::RandVolume(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale), 0));
|
|
|
|
}
|
|
|
|
for (int j = 0; j < cfgBenchmark16_BatchCount; ++j)
|
|
|
|
{
|
|
|
|
dbvt.remove(batch[j]);
|
|
|
|
}
|
|
|
|
batch.resize(0);
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
const int ir = cfgBenchmark16_Passes * cfgBenchmark16_BatchCount;
|
|
|
|
printf("%u ms (%i%%),(%u bir/s)\r\n", time, (time - cfgBenchmark16_Reference) * 100 / time, int(ir * 1000.0 / time));
|
|
|
|
}
|
|
|
|
if (cfgBenchmark17_Enable)
|
|
|
|
{ // Benchmark 17
|
|
|
|
srand(380843);
|
|
|
|
btAlignedObjectArray<btDbvtVolume> volumes;
|
|
|
|
btAlignedObjectArray<int> results;
|
|
|
|
btAlignedObjectArray<int> indices;
|
|
|
|
volumes.resize(cfgLeaves);
|
|
|
|
results.resize(cfgLeaves);
|
|
|
|
indices.resize(cfgLeaves);
|
|
|
|
for (int i = 0; i < cfgLeaves; ++i)
|
|
|
|
{
|
|
|
|
indices[i] = i;
|
|
|
|
volumes[i] = btDbvtBenchmark::RandVolume(cfgVolumeCenterScale, cfgVolumeExentsBase, cfgVolumeExentsScale);
|
|
|
|
}
|
|
|
|
for (int i = 0; i < cfgLeaves; ++i)
|
|
|
|
{
|
|
|
|
btSwap(indices[i], indices[rand() % cfgLeaves]);
|
|
|
|
}
|
|
|
|
printf("[17] btDbvtVolume select: ");
|
|
|
|
wallclock.reset();
|
|
|
|
for (int i = 0; i < cfgBenchmark17_Iterations; ++i)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < cfgLeaves; ++j)
|
|
|
|
{
|
|
|
|
for (int k = 0; k < cfgLeaves; ++k)
|
|
|
|
{
|
|
|
|
const int idx = indices[k];
|
|
|
|
results[idx] = Select(volumes[idx], volumes[j], volumes[k]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const int time = (int)wallclock.getTimeMilliseconds();
|
|
|
|
printf("%u ms (%i%%)\r\n", time, (time - cfgBenchmark17_Reference) * 100 / time);
|
|
|
|
}
|
|
|
|
printf("\r\n\r\n");
|
|
|
|
}
|
|
|
|
#endif
|