1/*
2Bullet Continuous Collision Detection and Physics Library
3Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
4
5This software is provided 'as-is', without any express or implied warranty.
6In no event will the authors be held liable for any damages arising from the use of this software.
7Permission is granted to anyone to use this software for any purpose,
8including commercial applications, and to alter it and redistribute it freely,
9subject to the following restrictions:
10
111. 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.
122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
133. This notice may not be removed or altered from any source distribution.
14*/
15///btDbvt implementation by Nathanael Presson
16
17#include "btDbvt.h"
18
19//
20typedef btAlignedObjectArray<btDbvtNode*>			tNodeArray;
21typedef btAlignedObjectArray<const btDbvtNode*>	tConstNodeArray;
22
23//
24struct btDbvtNodeEnumerator : btDbvt::ICollide
25{
26	tConstNodeArray	nodes;
27	void Process(const btDbvtNode* n) { nodes.push_back(n); }
28};
29
30//
31static DBVT_INLINE int			indexof(const btDbvtNode* node)
32{
33	return(node->parent->childs[1]==node);
34}
35
36//
37static DBVT_INLINE btDbvtVolume	merge(	const btDbvtVolume& a,
38									  const btDbvtVolume& b)
39{
40#if (DBVT_MERGE_IMPL==DBVT_IMPL_SSE)
41	ATTRIBUTE_ALIGNED16( char locals[sizeof(btDbvtAabbMm)]);
42	btDbvtVolume* ptr = (btDbvtVolume*) locals;
43	btDbvtVolume&	res=*ptr;
44#else
45		btDbvtVolume	res;
46#endif
47	Merge(a,b,res);
48	return(res);
49}
50
51// volume+edge lengths
52static DBVT_INLINE btScalar		size(const btDbvtVolume& a)
53{
54	const btVector3	edges=a.Lengths();
55	return(	edges.x()*edges.y()*edges.z()+
56		edges.x()+edges.y()+edges.z());
57}
58
59//
60static void						getmaxdepth(const btDbvtNode* node,int depth,int& maxdepth)
61{
62	if(node->isinternal())
63	{
64		getmaxdepth(node->childs[0],depth+1,maxdepth);
65		getmaxdepth(node->childs[1],depth+1,maxdepth);
66	} else maxdepth=btMax(maxdepth,depth);
67}
68
69//
70static DBVT_INLINE void			deletenode(	btDbvt* pdbvt,
71										   btDbvtNode* node)
72{
73	btAlignedFree(pdbvt->m_free);
74	pdbvt->m_free=node;
75}
76
77//
78static void						recursedeletenode(	btDbvt* pdbvt,
79												  btDbvtNode* node)
80{
81	if(!node->isleaf())
82	{
83		recursedeletenode(pdbvt,node->childs[0]);
84		recursedeletenode(pdbvt,node->childs[1]);
85	}
86	if(node==pdbvt->m_root) pdbvt->m_root=0;
87	deletenode(pdbvt,node);
88}
89
90//
91static DBVT_INLINE btDbvtNode*	createnode(	btDbvt* pdbvt,
92										   btDbvtNode* parent,
93										   void* data)
94{
95	btDbvtNode*	node;
96	if(pdbvt->m_free)
97	{ node=pdbvt->m_free;pdbvt->m_free=0; }
98	else
99	{ node=new(btAlignedAlloc(sizeof(btDbvtNode),16)) btDbvtNode(); }
100	node->parent	=	parent;
101	node->data		=	data;
102	node->childs[1]	=	0;
103	return(node);
104}
105
106//
107static DBVT_INLINE btDbvtNode*	createnode(	btDbvt* pdbvt,
108										   btDbvtNode* parent,
109										   const btDbvtVolume& volume,
110										   void* data)
111{
112	btDbvtNode*	node=createnode(pdbvt,parent,data);
113	node->volume=volume;
114	return(node);
115}
116
117//
118static DBVT_INLINE btDbvtNode*	createnode(	btDbvt* pdbvt,
119										   btDbvtNode* parent,
120										   const btDbvtVolume& volume0,
121										   const btDbvtVolume& volume1,
122										   void* data)
123{
124	btDbvtNode*	node=createnode(pdbvt,parent,data);
125	Merge(volume0,volume1,node->volume);
126	return(node);
127}
128
129//
130static void						insertleaf(	btDbvt* pdbvt,
131										   btDbvtNode* root,
132										   btDbvtNode* leaf)
133{
134	if(!pdbvt->m_root)
135	{
136		pdbvt->m_root	=	leaf;
137		leaf->parent	=	0;
138	}
139	else
140	{
141		if(!root->isleaf())
142		{
143			do	{
144				root=root->childs[Select(	leaf->volume,
145					root->childs[0]->volume,
146					root->childs[1]->volume)];
147			} while(!root->isleaf());
148		}
149		btDbvtNode*	prev=root->parent;
150		btDbvtNode*	node=createnode(pdbvt,prev,leaf->volume,root->volume,0);
151		if(prev)
152		{
153			prev->childs[indexof(root)]	=	node;
154			node->childs[0]				=	root;root->parent=node;
155			node->childs[1]				=	leaf;leaf->parent=node;
156			do	{
157				if(!prev->volume.Contain(node->volume))
158					Merge(prev->childs[0]->volume,prev->childs[1]->volume,prev->volume);
159				else
160					break;
161				node=prev;
162			} while(0!=(prev=node->parent));
163		}
164		else
165		{
166			node->childs[0]	=	root;root->parent=node;
167			node->childs[1]	=	leaf;leaf->parent=node;
168			pdbvt->m_root	=	node;
169		}
170	}
171}
172
173//
174static btDbvtNode*				removeleaf(	btDbvt* pdbvt,
175										   btDbvtNode* leaf)
176{
177	if(leaf==pdbvt->m_root)
178	{
179		pdbvt->m_root=0;
180		return(0);
181	}
182	else
183	{
184		btDbvtNode*	parent=leaf->parent;
185		btDbvtNode*	prev=parent->parent;
186		btDbvtNode*	sibling=parent->childs[1-indexof(leaf)];
187		if(prev)
188		{
189			prev->childs[indexof(parent)]=sibling;
190			sibling->parent=prev;
191			deletenode(pdbvt,parent);
192			while(prev)
193			{
194				const btDbvtVolume	pb=prev->volume;
195				Merge(prev->childs[0]->volume,prev->childs[1]->volume,prev->volume);
196				if(NotEqual(pb,prev->volume))
197				{
198					prev=prev->parent;
199				} else break;
200			}
201			return(prev?prev:pdbvt->m_root);
202		}
203		else
204		{
205			pdbvt->m_root=sibling;
206			sibling->parent=0;
207			deletenode(pdbvt,parent);
208			return(pdbvt->m_root);
209		}
210	}
211}
212
213//
214static void						fetchleaves(btDbvt* pdbvt,
215											btDbvtNode* root,
216											tNodeArray& leaves,
217											int depth=-1)
218{
219	if(root->isinternal()&&depth)
220	{
221		fetchleaves(pdbvt,root->childs[0],leaves,depth-1);
222		fetchleaves(pdbvt,root->childs[1],leaves,depth-1);
223		deletenode(pdbvt,root);
224	}
225	else
226	{
227		leaves.push_back(root);
228	}
229}
230
231//
232static void						split(	const tNodeArray& leaves,
233									  tNodeArray& left,
234									  tNodeArray& right,
235									  const btVector3& org,
236									  const btVector3& axis)
237{
238	left.resize(0);
239	right.resize(0);
240	for(int i=0,ni=leaves.size();i<ni;++i)
241	{
242		if(btDot(axis,leaves[i]->volume.Center()-org)<0)
243			left.push_back(leaves[i]);
244		else
245			right.push_back(leaves[i]);
246	}
247}
248
249//
250static btDbvtVolume				bounds(	const tNodeArray& leaves)
251{
252#if DBVT_MERGE_IMPL==DBVT_IMPL_SSE
253	ATTRIBUTE_ALIGNED16(char	locals[sizeof(btDbvtVolume)]);
254	btDbvtVolume* ptr = (btDbvtVolume*) locals;
255	btDbvtVolume&	volume=*ptr;
256	volume=leaves[0]->volume;
257#else
258	btDbvtVolume volume=leaves[0]->volume;
259#endif
260	for(int i=1,ni=leaves.size();i<ni;++i)
261	{
262		Merge(volume,leaves[i]->volume,volume);
263	}
264	return(volume);
265}
266
267//
268static void						bottomup(	btDbvt* pdbvt,
269										 tNodeArray& leaves)
270{
271	while(leaves.size()>1)
272	{
273		btScalar	minsize=SIMD_INFINITY;
274		int			minidx[2]={-1,-1};
275		for(int i=0;i<leaves.size();++i)
276		{
277			for(int j=i+1;j<leaves.size();++j)
278			{
279				const btScalar	sz=size(merge(leaves[i]->volume,leaves[j]->volume));
280				if(sz<minsize)
281				{
282					minsize		=	sz;
283					minidx[0]	=	i;
284					minidx[1]	=	j;
285				}
286			}
287		}
288		btDbvtNode*	n[]	=	{leaves[minidx[0]],leaves[minidx[1]]};
289		btDbvtNode*	p	=	createnode(pdbvt,0,n[0]->volume,n[1]->volume,0);
290		p->childs[0]		=	n[0];
291		p->childs[1]		=	n[1];
292		n[0]->parent		=	p;
293		n[1]->parent		=	p;
294		leaves[minidx[0]]	=	p;
295		leaves.swap(minidx[1],leaves.size()-1);
296		leaves.pop_back();
297	}
298}
299
300//
301static btDbvtNode*			topdown(btDbvt* pdbvt,
302									tNodeArray& leaves,
303									int bu_treshold)
304{
305	static const btVector3	axis[]={btVector3(1,0,0),
306		btVector3(0,1,0),
307		btVector3(0,0,1)};
308	if(leaves.size()>1)
309	{
310		if(leaves.size()>bu_treshold)
311		{
312			const btDbvtVolume	vol=bounds(leaves);
313			const btVector3			org=vol.Center();
314			tNodeArray				sets[2];
315			int						bestaxis=-1;
316			int						bestmidp=leaves.size();
317			int						splitcount[3][2]={{0,0},{0,0},{0,0}};
318			int i;
319			for( i=0;i<leaves.size();++i)
320			{
321				const btVector3	x=leaves[i]->volume.Center()-org;
322				for(int j=0;j<3;++j)
323				{
324					++splitcount[j][btDot(x,axis[j])>0?1:0];
325				}
326			}
327			for( i=0;i<3;++i)
328			{
329				if((splitcount[i][0]>0)&&(splitcount[i][1]>0))
330				{
331					const int	midp=(int)btFabs(btScalar(splitcount[i][0]-splitcount[i][1]));
332					if(midp<bestmidp)
333					{
334						bestaxis=i;
335						bestmidp=midp;
336					}
337				}
338			}
339			if(bestaxis>=0)
340			{
341				sets[0].reserve(splitcount[bestaxis][0]);
342				sets[1].reserve(splitcount[bestaxis][1]);
343				split(leaves,sets[0],sets[1],org,axis[bestaxis]);
344			}
345			else
346			{
347				sets[0].reserve(leaves.size()/2+1);
348				sets[1].reserve(leaves.size()/2);
349				for(int i=0,ni=leaves.size();i<ni;++i)
350				{
351					sets[i&1].push_back(leaves[i]);
352				}
353			}
354			btDbvtNode*	node=createnode(pdbvt,0,vol,0);
355			node->childs[0]=topdown(pdbvt,sets[0],bu_treshold);
356			node->childs[1]=topdown(pdbvt,sets[1],bu_treshold);
357			node->childs[0]->parent=node;
358			node->childs[1]->parent=node;
359			return(node);
360		}
361		else
362		{
363			bottomup(pdbvt,leaves);
364			return(leaves[0]);
365		}
366	}
367	return(leaves[0]);
368}
369
370//
371static DBVT_INLINE btDbvtNode*	sort(btDbvtNode* n,btDbvtNode*& r)
372{
373	btDbvtNode*	p=n->parent;
374	btAssert(n->isinternal());
375	if(p>n)
376	{
377		const int		i=indexof(n);
378		const int		j=1-i;
379		btDbvtNode*	s=p->childs[j];
380		btDbvtNode*	q=p->parent;
381		btAssert(n==p->childs[i]);
382		if(q) q->childs[indexof(p)]=n; else r=n;
383		s->parent=n;
384		p->parent=n;
385		n->parent=q;
386		p->childs[0]=n->childs[0];
387		p->childs[1]=n->childs[1];
388		n->childs[0]->parent=p;
389		n->childs[1]->parent=p;
390		n->childs[i]=p;
391		n->childs[j]=s;
392		btSwap(p->volume,n->volume);
393		return(p);
394	}
395	return(n);
396}
397
398#if 0
399static DBVT_INLINE btDbvtNode*	walkup(btDbvtNode* n,int count)
400{
401	while(n&&(count--)) n=n->parent;
402	return(n);
403}
404#endif
405
406//
407// Api
408//
409
410//
411btDbvt::btDbvt()
412{
413	m_root		=	0;
414	m_free		=	0;
415	m_lkhd		=	-1;
416	m_leaves	=	0;
417	m_opath		=	0;
418}
419
420//
421btDbvt::~btDbvt()
422{
423	clear();
424}
425
426//
427void			btDbvt::clear()
428{
429	if(m_root)
430		recursedeletenode(this,m_root);
431	btAlignedFree(m_free);
432	m_free=0;
433	m_lkhd		=	-1;
434	m_stkStack.clear();
435	m_opath		=	0;
436
437}
438
439//
440void			btDbvt::optimizeBottomUp()
441{
442	if(m_root)
443	{
444		tNodeArray leaves;
445		leaves.reserve(m_leaves);
446		fetchleaves(this,m_root,leaves);
447		bottomup(this,leaves);
448		m_root=leaves[0];
449	}
450}
451
452//
453void			btDbvt::optimizeTopDown(int bu_treshold)
454{
455	if(m_root)
456	{
457		tNodeArray	leaves;
458		leaves.reserve(m_leaves);
459		fetchleaves(this,m_root,leaves);
460		m_root=topdown(this,leaves,bu_treshold);
461	}
462}
463
464//
465void			btDbvt::optimizeIncremental(int passes)
466{
467	if(passes<0) passes=m_leaves;
468	if(m_root&&(passes>0))
469	{
470		do	{
471			btDbvtNode*		node=m_root;
472			unsigned	bit=0;
473			while(node->isinternal())
474			{
475				node=sort(node,m_root)->childs[(m_opath>>bit)&1];
476				bit=(bit+1)&(sizeof(unsigned)*8-1);
477			}
478			update(node);
479			++m_opath;
480		} while(--passes);
481	}
482}
483
484//
485btDbvtNode*	btDbvt::insert(const btDbvtVolume& volume,void* data)
486{
487	btDbvtNode*	leaf=createnode(this,0,volume,data);
488	insertleaf(this,m_root,leaf);
489	++m_leaves;
490	return(leaf);
491}
492
493//
494void			btDbvt::update(btDbvtNode* leaf,int lookahead)
495{
496	btDbvtNode*	root=removeleaf(this,leaf);
497	if(root)
498	{
499		if(lookahead>=0)
500		{
501			for(int i=0;(i<lookahead)&&root->parent;++i)
502			{
503				root=root->parent;
504			}
505		} else root=m_root;
506	}
507	insertleaf(this,root,leaf);
508}
509
510//
511void			btDbvt::update(btDbvtNode* leaf,btDbvtVolume& volume)
512{
513	btDbvtNode*	root=removeleaf(this,leaf);
514	if(root)
515	{
516		if(m_lkhd>=0)
517		{
518			for(int i=0;(i<m_lkhd)&&root->parent;++i)
519			{
520				root=root->parent;
521			}
522		} else root=m_root;
523	}
524	leaf->volume=volume;
525	insertleaf(this,root,leaf);
526}
527
528//
529bool			btDbvt::update(btDbvtNode* leaf,btDbvtVolume& volume,const btVector3& velocity,btScalar margin)
530{
531	if(leaf->volume.Contain(volume)) return(false);
532	volume.Expand(btVector3(margin,margin,margin));
533	volume.SignedExpand(velocity);
534	update(leaf,volume);
535	return(true);
536}
537
538//
539bool			btDbvt::update(btDbvtNode* leaf,btDbvtVolume& volume,const btVector3& velocity)
540{
541	if(leaf->volume.Contain(volume)) return(false);
542	volume.SignedExpand(velocity);
543	update(leaf,volume);
544	return(true);
545}
546
547//
548bool			btDbvt::update(btDbvtNode* leaf,btDbvtVolume& volume,btScalar margin)
549{
550	if(leaf->volume.Contain(volume)) return(false);
551	volume.Expand(btVector3(margin,margin,margin));
552	update(leaf,volume);
553	return(true);
554}
555
556//
557void			btDbvt::remove(btDbvtNode* leaf)
558{
559	removeleaf(this,leaf);
560	deletenode(this,leaf);
561	--m_leaves;
562}
563
564//
565void			btDbvt::write(IWriter* iwriter) const
566{
567	btDbvtNodeEnumerator	nodes;
568	nodes.nodes.reserve(m_leaves*2);
569	enumNodes(m_root,nodes);
570	iwriter->Prepare(m_root,nodes.nodes.size());
571	for(int i=0;i<nodes.nodes.size();++i)
572	{
573		const btDbvtNode* n=nodes.nodes[i];
574		int			p=-1;
575		if(n->parent) p=nodes.nodes.findLinearSearch(n->parent);
576		if(n->isinternal())
577		{
578			const int	c0=nodes.nodes.findLinearSearch(n->childs[0]);
579			const int	c1=nodes.nodes.findLinearSearch(n->childs[1]);
580			iwriter->WriteNode(n,i,p,c0,c1);
581		}
582		else
583		{
584			iwriter->WriteLeaf(n,i,p);
585		}
586	}
587}
588
589//
590void			btDbvt::clone(btDbvt& dest,IClone* iclone) const
591{
592	dest.clear();
593	if(m_root!=0)
594	{
595		btAlignedObjectArray<sStkCLN>	stack;
596		stack.reserve(m_leaves);
597		stack.push_back(sStkCLN(m_root,0));
598		do	{
599			const int		i=stack.size()-1;
600			const sStkCLN	e=stack[i];
601			btDbvtNode*			n=createnode(&dest,e.parent,e.node->volume,e.node->data);
602			stack.pop_back();
603			if(e.parent!=0)
604				e.parent->childs[i&1]=n;
605			else
606				dest.m_root=n;
607			if(e.node->isinternal())
608			{
609				stack.push_back(sStkCLN(e.node->childs[0],n));
610				stack.push_back(sStkCLN(e.node->childs[1],n));
611			}
612			else
613			{
614				iclone->CloneLeaf(n);
615			}
616		} while(stack.size()>0);
617	}
618}
619
620//
621int				btDbvt::maxdepth(const btDbvtNode* node)
622{
623	int	depth=0;
624	if(node) getmaxdepth(node,1,depth);
625	return(depth);
626}
627
628//
629int				btDbvt::countLeaves(const btDbvtNode* node)
630{
631	if(node->isinternal())
632		return(countLeaves(node->childs[0])+countLeaves(node->childs[1]));
633	else
634		return(1);
635}
636
637//
638void			btDbvt::extractLeaves(const btDbvtNode* node,btAlignedObjectArray<const btDbvtNode*>& leaves)
639{
640	if(node->isinternal())
641	{
642		extractLeaves(node->childs[0],leaves);
643		extractLeaves(node->childs[1],leaves);
644	}
645	else
646	{
647		leaves.push_back(node);
648	}
649}
650
651//
652#if DBVT_ENABLE_BENCHMARK
653
654#include <stdio.h>
655#include <stdlib.h>
656#include "LinearMath/btQuickProf.h"
657
658/*
659q6600,2.4ghz
660
661/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"
662/GF /FD /MT /GS- /Gy /arch:SSE2 /Zc:wchar_t- /Fp"..\..\out\release8\build\libbulletcollision\libbulletcollision.pch"
663/Fo"..\..\out\release8\build\libbulletcollision\\"
664/Fd"..\..\out\release8\build\libbulletcollision\bulletcollision.pdb"
665/W3 /nologo /c /Wp64 /Zi /errorReport:prompt
666
667Benchmarking dbvt...
668World scale: 100.000000
669Extents base: 1.000000
670Extents range: 4.000000
671Leaves: 8192
672sizeof(btDbvtVolume): 32 bytes
673sizeof(btDbvtNode):   44 bytes
674[1] btDbvtVolume intersections: 3499 ms (-1%)
675[2] btDbvtVolume merges: 1934 ms (0%)
676[3] btDbvt::collideTT: 5485 ms (-21%)
677[4] btDbvt::collideTT self: 2814 ms (-20%)
678[5] btDbvt::collideTT xform: 7379 ms (-1%)
679[6] btDbvt::collideTT xform,self: 7270 ms (-2%)
680[7] btDbvt::rayTest: 6314 ms (0%),(332143 r/s)
681[8] insert/remove: 2093 ms (0%),(1001983 ir/s)
682[9] updates (teleport): 1879 ms (-3%),(1116100 u/s)
683[10] updates (jitter): 1244 ms (-4%),(1685813 u/s)
684[11] optimize (incremental): 2514 ms (0%),(1668000 o/s)
685[12] btDbvtVolume notequal: 3659 ms (0%)
686[13] culling(OCL+fullsort): 2218 ms (0%),(461 t/s)
687[14] culling(OCL+qsort): 3688 ms (5%),(2221 t/s)
688[15] culling(KDOP+qsort): 1139 ms (-1%),(7192 t/s)
689[16] insert/remove batch(256): 5092 ms (0%),(823704 bir/s)
690[17] btDbvtVolume select: 3419 ms (0%)
691*/
692
693struct btDbvtBenchmark
694{
695	struct NilPolicy : btDbvt::ICollide
696	{
697		NilPolicy() : m_pcount(0),m_depth(-SIMD_INFINITY),m_checksort(true)		{}
698		void	Process(const btDbvtNode*,const btDbvtNode*)				{ ++m_pcount; }
699		void	Process(const btDbvtNode*)									{ ++m_pcount; }
700		void	Process(const btDbvtNode*,btScalar depth)
701		{
702			++m_pcount;
703			if(m_checksort)
704			{ if(depth>=m_depth) m_depth=depth; else printf("wrong depth: %f (should be >= %f)\r\n",depth,m_depth); }
705		}
706		int			m_pcount;
707		btScalar	m_depth;
708		bool		m_checksort;
709	};
710	struct P14 : btDbvt::ICollide
711	{
712		struct Node
713		{
714			const btDbvtNode*	leaf;
715			btScalar			depth;
716		};
717		void Process(const btDbvtNode* leaf,btScalar depth)
718		{
719			Node	n;
720			n.leaf	=	leaf;
721			n.depth	=	depth;
722		}
723		static int sortfnc(const Node& a,const Node& b)
724		{
725			if(a.depth<b.depth) return(+1);
726			if(a.depth>b.depth) return(-1);
727			return(0);
728		}
729		btAlignedObjectArray<Node>		m_nodes;
730	};
731	struct P15 : btDbvt::ICollide
732	{
733		struct Node
734		{
735			const btDbvtNode*	leaf;
736			btScalar			depth;
737		};
738		void Process(const btDbvtNode* leaf)
739		{
740			Node	n;
741			n.leaf	=	leaf;
742			n.depth	=	dot(leaf->volume.Center(),m_axis);
743		}
744		static int sortfnc(const Node& a,const Node& b)
745		{
746			if(a.depth<b.depth) return(+1);
747			if(a.depth>b.depth) return(-1);
748			return(0);
749		}
750		btAlignedObjectArray<Node>		m_nodes;
751		btVector3						m_axis;
752	};
753	static btScalar			RandUnit()
754	{
755		return(rand()/(btScalar)RAND_MAX);
756	}
757	static btVector3		RandVector3()
758	{
759		return(btVector3(RandUnit(),RandUnit(),RandUnit()));
760	}
761	static btVector3		RandVector3(btScalar cs)
762	{
763		return(RandVector3()*cs-btVector3(cs,cs,cs)/2);
764	}
765	static btDbvtVolume	RandVolume(btScalar cs,btScalar eb,btScalar es)
766	{
767		return(btDbvtVolume::FromCE(RandVector3(cs),btVector3(eb,eb,eb)+RandVector3()*es));
768	}
769	static btTransform		RandTransform(btScalar cs)
770	{
771		btTransform	t;
772		t.setOrigin(RandVector3(cs));
773		t.setRotation(btQuaternion(RandUnit()*SIMD_PI*2,RandUnit()*SIMD_PI*2,RandUnit()*SIMD_PI*2).normalized());
774		return(t);
775	}
776	static void				RandTree(btScalar cs,btScalar eb,btScalar es,int leaves,btDbvt& dbvt)
777	{
778		dbvt.clear();
779		for(int i=0;i<leaves;++i)
780		{
781			dbvt.insert(RandVolume(cs,eb,es),0);
782		}
783	}
784};
785
786void			btDbvt::benchmark()
787{
788	static const btScalar	cfgVolumeCenterScale		=	100;
789	static const btScalar	cfgVolumeExentsBase			=	1;
790	static const btScalar	cfgVolumeExentsScale		=	4;
791	static const int		cfgLeaves					=	8192;
792	static const bool		cfgEnable					=	true;
793
794	//[1] btDbvtVolume intersections
795	bool					cfgBenchmark1_Enable		=	cfgEnable;
796	static const int		cfgBenchmark1_Iterations	=	8;
797	static const int		cfgBenchmark1_Reference		=	3499;
798	//[2] btDbvtVolume merges
799	bool					cfgBenchmark2_Enable		=	cfgEnable;
800	static const int		cfgBenchmark2_Iterations	=	4;
801	static const int		cfgBenchmark2_Reference		=	1945;
802	//[3] btDbvt::collideTT
803	bool					cfgBenchmark3_Enable		=	cfgEnable;
804	static const int		cfgBenchmark3_Iterations	=	512;
805	static const int		cfgBenchmark3_Reference		=	5485;
806	//[4] btDbvt::collideTT self
807	bool					cfgBenchmark4_Enable		=	cfgEnable;
808	static const int		cfgBenchmark4_Iterations	=	512;
809	static const int		cfgBenchmark4_Reference		=	2814;
810	//[5] btDbvt::collideTT xform
811	bool					cfgBenchmark5_Enable		=	cfgEnable;
812	static const int		cfgBenchmark5_Iterations	=	512;
813	static const btScalar	cfgBenchmark5_OffsetScale	=	2;
814	static const int		cfgBenchmark5_Reference		=	7379;
815	//[6] btDbvt::collideTT xform,self
816	bool					cfgBenchmark6_Enable		=	cfgEnable;
817	static const int		cfgBenchmark6_Iterations	=	512;
818	static const btScalar	cfgBenchmark6_OffsetScale	=	2;
819	static const int		cfgBenchmark6_Reference		=	7270;
820	//[7] btDbvt::rayTest
821	bool					cfgBenchmark7_Enable		=	cfgEnable;
822	static const int		cfgBenchmark7_Passes		=	32;
823	static const int		cfgBenchmark7_Iterations	=	65536;
824	static const int		cfgBenchmark7_Reference		=	6307;
825	//[8] insert/remove
826	bool					cfgBenchmark8_Enable		=	cfgEnable;
827	static const int		cfgBenchmark8_Passes		=	32;
828	static const int		cfgBenchmark8_Iterations	=	65536;
829	static const int		cfgBenchmark8_Reference		=	2105;
830	//[9] updates (teleport)
831	bool					cfgBenchmark9_Enable		=	cfgEnable;
832	static const int		cfgBenchmark9_Passes		=	32;
833	static const int		cfgBenchmark9_Iterations	=	65536;
834	static const int		cfgBenchmark9_Reference		=	1879;
835	//[10] updates (jitter)
836	bool					cfgBenchmark10_Enable		=	cfgEnable;
837	static const btScalar	cfgBenchmark10_Scale		=	cfgVolumeCenterScale/10000;
838	static const int		cfgBenchmark10_Passes		=	32;
839	static const int		cfgBenchmark10_Iterations	=	65536;
840	static const int		cfgBenchmark10_Reference	=	1244;
841	//[11] optimize (incremental)
842	bool					cfgBenchmark11_Enable		=	cfgEnable;
843	static const int		cfgBenchmark11_Passes		=	64;
844	static const int		cfgBenchmark11_Iterations	=	65536;
845	static const int		cfgBenchmark11_Reference	=	2510;
846	//[12] btDbvtVolume notequal
847	bool					cfgBenchmark12_Enable		=	cfgEnable;
848	static const int		cfgBenchmark12_Iterations	=	32;
849	static const int		cfgBenchmark12_Reference	=	3677;
850	//[13] culling(OCL+fullsort)
851	bool					cfgBenchmark13_Enable		=	cfgEnable;
852	static const int		cfgBenchmark13_Iterations	=	1024;
853	static const int		cfgBenchmark13_Reference	=	2231;
854	//[14] culling(OCL+qsort)
855	bool					cfgBenchmark14_Enable		=	cfgEnable;
856	static const int		cfgBenchmark14_Iterations	=	8192;
857	static const int		cfgBenchmark14_Reference	=	3500;
858	//[15] culling(KDOP+qsort)
859	bool					cfgBenchmark15_Enable		=	cfgEnable;
860	static const int		cfgBenchmark15_Iterations	=	8192;
861	static const int		cfgBenchmark15_Reference	=	1151;
862	//[16] insert/remove batch
863	bool					cfgBenchmark16_Enable		=	cfgEnable;
864	static const int		cfgBenchmark16_BatchCount	=	256;
865	static const int		cfgBenchmark16_Passes		=	16384;
866	static const int		cfgBenchmark16_Reference	=	5138;
867	//[17] select
868	bool					cfgBenchmark17_Enable		=	cfgEnable;
869	static const int		cfgBenchmark17_Iterations	=	4;
870	static const int		cfgBenchmark17_Reference	=	3390;
871
872	btClock					wallclock;
873	printf("Benchmarking dbvt...\r\n");
874	printf("\tWorld scale: %f\r\n",cfgVolumeCenterScale);
875	printf("\tExtents base: %f\r\n",cfgVolumeExentsBase);
876	printf("\tExtents range: %f\r\n",cfgVolumeExentsScale);
877	printf("\tLeaves: %u\r\n",cfgLeaves);
878	printf("\tsizeof(btDbvtVolume): %u bytes\r\n",sizeof(btDbvtVolume));
879	printf("\tsizeof(btDbvtNode):   %u bytes\r\n",sizeof(btDbvtNode));
880	if(cfgBenchmark1_Enable)
881	{// Benchmark 1
882		srand(380843);
883		btAlignedObjectArray<btDbvtVolume>	volumes;
884		btAlignedObjectArray<bool>			results;
885		volumes.resize(cfgLeaves);
886		results.resize(cfgLeaves);
887		for(int i=0;i<cfgLeaves;++i)
888		{
889			volumes[i]=btDbvtBenchmark::RandVolume(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale);
890		}
891		printf("[1] btDbvtVolume intersections: ");
892		wallclock.reset();
893		for(int i=0;i<cfgBenchmark1_Iterations;++i)
894		{
895			for(int j=0;j<cfgLeaves;++j)
896			{
897				for(int k=0;k<cfgLeaves;++k)
898				{
899					results[k]=Intersect(volumes[j],volumes[k]);
900				}
901			}
902		}
903		const int time=(int)wallclock.getTimeMilliseconds();
904		printf("%u ms (%i%%)\r\n",time,(time-cfgBenchmark1_Reference)*100/time);
905	}
906	if(cfgBenchmark2_Enable)
907	{// Benchmark 2
908		srand(380843);
909		btAlignedObjectArray<btDbvtVolume>	volumes;
910		btAlignedObjectArray<btDbvtVolume>	results;
911		volumes.resize(cfgLeaves);
912		results.resize(cfgLeaves);
913		for(int i=0;i<cfgLeaves;++i)
914		{
915			volumes[i]=btDbvtBenchmark::RandVolume(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale);
916		}
917		printf("[2] btDbvtVolume merges: ");
918		wallclock.reset();
919		for(int i=0;i<cfgBenchmark2_Iterations;++i)
920		{
921			for(int j=0;j<cfgLeaves;++j)
922			{
923				for(int k=0;k<cfgLeaves;++k)
924				{
925					Merge(volumes[j],volumes[k],results[k]);
926				}
927			}
928		}
929		const int time=(int)wallclock.getTimeMilliseconds();
930		printf("%u ms (%i%%)\r\n",time,(time-cfgBenchmark2_Reference)*100/time);
931	}
932	if(cfgBenchmark3_Enable)
933	{// Benchmark 3
934		srand(380843);
935		btDbvt						dbvt[2];
936		btDbvtBenchmark::NilPolicy	policy;
937		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt[0]);
938		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt[1]);
939		dbvt[0].optimizeTopDown();
940		dbvt[1].optimizeTopDown();
941		printf("[3] btDbvt::collideTT: ");
942		wallclock.reset();
943		for(int i=0;i<cfgBenchmark3_Iterations;++i)
944		{
945			btDbvt::collideTT(dbvt[0].m_root,dbvt[1].m_root,policy);
946		}
947		const int time=(int)wallclock.getTimeMilliseconds();
948		printf("%u ms (%i%%)\r\n",time,(time-cfgBenchmark3_Reference)*100/time);
949	}
950	if(cfgBenchmark4_Enable)
951	{// Benchmark 4
952		srand(380843);
953		btDbvt						dbvt;
954		btDbvtBenchmark::NilPolicy	policy;
955		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt);
956		dbvt.optimizeTopDown();
957		printf("[4] btDbvt::collideTT self: ");
958		wallclock.reset();
959		for(int i=0;i<cfgBenchmark4_Iterations;++i)
960		{
961			btDbvt::collideTT(dbvt.m_root,dbvt.m_root,policy);
962		}
963		const int time=(int)wallclock.getTimeMilliseconds();
964		printf("%u ms (%i%%)\r\n",time,(time-cfgBenchmark4_Reference)*100/time);
965	}
966	if(cfgBenchmark5_Enable)
967	{// Benchmark 5
968		srand(380843);
969		btDbvt								dbvt[2];
970		btAlignedObjectArray<btTransform>	transforms;
971		btDbvtBenchmark::NilPolicy			policy;
972		transforms.resize(cfgBenchmark5_Iterations);
973		for(int i=0;i<transforms.size();++i)
974		{
975			transforms[i]=btDbvtBenchmark::RandTransform(cfgVolumeCenterScale*cfgBenchmark5_OffsetScale);
976		}
977		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt[0]);
978		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt[1]);
979		dbvt[0].optimizeTopDown();
980		dbvt[1].optimizeTopDown();
981		printf("[5] btDbvt::collideTT xform: ");
982		wallclock.reset();
983		for(int i=0;i<cfgBenchmark5_Iterations;++i)
984		{
985			btDbvt::collideTT(dbvt[0].m_root,dbvt[1].m_root,transforms[i],policy);
986		}
987		const int time=(int)wallclock.getTimeMilliseconds();
988		printf("%u ms (%i%%)\r\n",time,(time-cfgBenchmark5_Reference)*100/time);
989	}
990	if(cfgBenchmark6_Enable)
991	{// Benchmark 6
992		srand(380843);
993		btDbvt								dbvt;
994		btAlignedObjectArray<btTransform>	transforms;
995		btDbvtBenchmark::NilPolicy			policy;
996		transforms.resize(cfgBenchmark6_Iterations);
997		for(int i=0;i<transforms.size();++i)
998		{
999			transforms[i]=btDbvtBenchmark::RandTransform(cfgVolumeCenterScale*cfgBenchmark6_OffsetScale);
1000		}
1001		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt);
1002		dbvt.optimizeTopDown();
1003		printf("[6] btDbvt::collideTT xform,self: ");
1004		wallclock.reset();
1005		for(int i=0;i<cfgBenchmark6_Iterations;++i)
1006		{
1007			btDbvt::collideTT(dbvt.m_root,dbvt.m_root,transforms[i],policy);
1008		}
1009		const int time=(int)wallclock.getTimeMilliseconds();
1010		printf("%u ms (%i%%)\r\n",time,(time-cfgBenchmark6_Reference)*100/time);
1011	}
1012	if(cfgBenchmark7_Enable)
1013	{// Benchmark 7
1014		srand(380843);
1015		btDbvt								dbvt;
1016		btAlignedObjectArray<btVector3>		rayorg;
1017		btAlignedObjectArray<btVector3>		raydir;
1018		btDbvtBenchmark::NilPolicy			policy;
1019		rayorg.resize(cfgBenchmark7_Iterations);
1020		raydir.resize(cfgBenchmark7_Iterations);
1021		for(int i=0;i<rayorg.size();++i)
1022		{
1023			rayorg[i]=btDbvtBenchmark::RandVector3(cfgVolumeCenterScale*2);
1024			raydir[i]=btDbvtBenchmark::RandVector3(cfgVolumeCenterScale*2);
1025		}
1026		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt);
1027		dbvt.optimizeTopDown();
1028		printf("[7] btDbvt::rayTest: ");
1029		wallclock.reset();
1030		for(int i=0;i<cfgBenchmark7_Passes;++i)
1031		{
1032			for(int j=0;j<cfgBenchmark7_Iterations;++j)
1033			{
1034				btDbvt::rayTest(dbvt.m_root,rayorg[j],rayorg[j]+raydir[j],policy);
1035			}
1036		}
1037		const int	time=(int)wallclock.getTimeMilliseconds();
1038		unsigned	rays=cfgBenchmark7_Passes*cfgBenchmark7_Iterations;
1039		printf("%u ms (%i%%),(%u r/s)\r\n",time,(time-cfgBenchmark7_Reference)*100/time,(rays*1000)/time);
1040	}
1041	if(cfgBenchmark8_Enable)
1042	{// Benchmark 8
1043		srand(380843);
1044		btDbvt								dbvt;
1045		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt);
1046		dbvt.optimizeTopDown();
1047		printf("[8] insert/remove: ");
1048		wallclock.reset();
1049		for(int i=0;i<cfgBenchmark8_Passes;++i)
1050		{
1051			for(int j=0;j<cfgBenchmark8_Iterations;++j)
1052			{
1053				dbvt.remove(dbvt.insert(btDbvtBenchmark::RandVolume(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale),0));
1054			}
1055		}
1056		const int	time=(int)wallclock.getTimeMilliseconds();
1057		const int	ir=cfgBenchmark8_Passes*cfgBenchmark8_Iterations;
1058		printf("%u ms (%i%%),(%u ir/s)\r\n",time,(time-cfgBenchmark8_Reference)*100/time,ir*1000/time);
1059	}
1060	if(cfgBenchmark9_Enable)
1061	{// Benchmark 9
1062		srand(380843);
1063		btDbvt										dbvt;
1064		btAlignedObjectArray<const btDbvtNode*>	leaves;
1065		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt);
1066		dbvt.optimizeTopDown();
1067		dbvt.extractLeaves(dbvt.m_root,leaves);
1068		printf("[9] updates (teleport): ");
1069		wallclock.reset();
1070		for(int i=0;i<cfgBenchmark9_Passes;++i)
1071		{
1072			for(int j=0;j<cfgBenchmark9_Iterations;++j)
1073			{
1074				dbvt.update(const_cast<btDbvtNode*>(leaves[rand()%cfgLeaves]),
1075					btDbvtBenchmark::RandVolume(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale));
1076			}
1077		}
1078		const int	time=(int)wallclock.getTimeMilliseconds();
1079		const int	up=cfgBenchmark9_Passes*cfgBenchmark9_Iterations;
1080		printf("%u ms (%i%%),(%u u/s)\r\n",time,(time-cfgBenchmark9_Reference)*100/time,up*1000/time);
1081	}
1082	if(cfgBenchmark10_Enable)
1083	{// Benchmark 10
1084		srand(380843);
1085		btDbvt										dbvt;
1086		btAlignedObjectArray<const btDbvtNode*>	leaves;
1087		btAlignedObjectArray<btVector3>				vectors;
1088		vectors.resize(cfgBenchmark10_Iterations);
1089		for(int i=0;i<vectors.size();++i)
1090		{
1091			vectors[i]=(btDbvtBenchmark::RandVector3()*2-btVector3(1,1,1))*cfgBenchmark10_Scale;
1092		}
1093		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt);
1094		dbvt.optimizeTopDown();
1095		dbvt.extractLeaves(dbvt.m_root,leaves);
1096		printf("[10] updates (jitter): ");
1097		wallclock.reset();
1098
1099		for(int i=0;i<cfgBenchmark10_Passes;++i)
1100		{
1101			for(int j=0;j<cfgBenchmark10_Iterations;++j)
1102			{
1103				const btVector3&	d=vectors[j];
1104				btDbvtNode*		l=const_cast<btDbvtNode*>(leaves[rand()%cfgLeaves]);
1105				btDbvtVolume		v=btDbvtVolume::FromMM(l->volume.Mins()+d,l->volume.Maxs()+d);
1106				dbvt.update(l,v);
1107			}
1108		}
1109		const int	time=(int)wallclock.getTimeMilliseconds();
1110		const int	up=cfgBenchmark10_Passes*cfgBenchmark10_Iterations;
1111		printf("%u ms (%i%%),(%u u/s)\r\n",time,(time-cfgBenchmark10_Reference)*100/time,up*1000/time);
1112	}
1113	if(cfgBenchmark11_Enable)
1114	{// Benchmark 11
1115		srand(380843);
1116		btDbvt										dbvt;
1117		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt);
1118		dbvt.optimizeTopDown();
1119		printf("[11] optimize (incremental): ");
1120		wallclock.reset();
1121		for(int i=0;i<cfgBenchmark11_Passes;++i)
1122		{
1123			dbvt.optimizeIncremental(cfgBenchmark11_Iterations);
1124		}
1125		const int	time=(int)wallclock.getTimeMilliseconds();
1126		const int	op=cfgBenchmark11_Passes*cfgBenchmark11_Iterations;
1127		printf("%u ms (%i%%),(%u o/s)\r\n",time,(time-cfgBenchmark11_Reference)*100/time,op/time*1000);
1128	}
1129	if(cfgBenchmark12_Enable)
1130	{// Benchmark 12
1131		srand(380843);
1132		btAlignedObjectArray<btDbvtVolume>	volumes;
1133		btAlignedObjectArray<bool>				results;
1134		volumes.resize(cfgLeaves);
1135		results.resize(cfgLeaves);
1136		for(int i=0;i<cfgLeaves;++i)
1137		{
1138			volumes[i]=btDbvtBenchmark::RandVolume(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale);
1139		}
1140		printf("[12] btDbvtVolume notequal: ");
1141		wallclock.reset();
1142		for(int i=0;i<cfgBenchmark12_Iterations;++i)
1143		{
1144			for(int j=0;j<cfgLeaves;++j)
1145			{
1146				for(int k=0;k<cfgLeaves;++k)
1147				{
1148					results[k]=NotEqual(volumes[j],volumes[k]);
1149				}
1150			}
1151		}
1152		const int time=(int)wallclock.getTimeMilliseconds();
1153		printf("%u ms (%i%%)\r\n",time,(time-cfgBenchmark12_Reference)*100/time);
1154	}
1155	if(cfgBenchmark13_Enable)
1156	{// Benchmark 13
1157		srand(380843);
1158		btDbvt								dbvt;
1159		btAlignedObjectArray<btVector3>		vectors;
1160		btDbvtBenchmark::NilPolicy			policy;
1161		vectors.resize(cfgBenchmark13_Iterations);
1162		for(int i=0;i<vectors.size();++i)
1163		{
1164			vectors[i]=(btDbvtBenchmark::RandVector3()*2-btVector3(1,1,1)).normalized();
1165		}
1166		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt);
1167		dbvt.optimizeTopDown();
1168		printf("[13] culling(OCL+fullsort): ");
1169		wallclock.reset();
1170		for(int i=0;i<cfgBenchmark13_Iterations;++i)
1171		{
1172			static const btScalar	offset=0;
1173			policy.m_depth=-SIMD_INFINITY;
1174			dbvt.collideOCL(dbvt.m_root,&vectors[i],&offset,vectors[i],1,policy);
1175		}
1176		const int	time=(int)wallclock.getTimeMilliseconds();
1177		const int	t=cfgBenchmark13_Iterations;
1178		printf("%u ms (%i%%),(%u t/s)\r\n",time,(time-cfgBenchmark13_Reference)*100/time,(t*1000)/time);
1179	}
1180	if(cfgBenchmark14_Enable)
1181	{// Benchmark 14
1182		srand(380843);
1183		btDbvt								dbvt;
1184		btAlignedObjectArray<btVector3>		vectors;
1185		btDbvtBenchmark::P14				policy;
1186		vectors.resize(cfgBenchmark14_Iterations);
1187		for(int i=0;i<vectors.size();++i)
1188		{
1189			vectors[i]=(btDbvtBenchmark::RandVector3()*2-btVector3(1,1,1)).normalized();
1190		}
1191		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt);
1192		dbvt.optimizeTopDown();
1193		policy.m_nodes.reserve(cfgLeaves);
1194		printf("[14] culling(OCL+qsort): ");
1195		wallclock.reset();
1196		for(int i=0;i<cfgBenchmark14_Iterations;++i)
1197		{
1198			static const btScalar	offset=0;
1199			policy.m_nodes.resize(0);
1200			dbvt.collideOCL(dbvt.m_root,&vectors[i],&offset,vectors[i],1,policy,false);
1201			policy.m_nodes.quickSort(btDbvtBenchmark::P14::sortfnc);
1202		}
1203		const int	time=(int)wallclock.getTimeMilliseconds();
1204		const int	t=cfgBenchmark14_Iterations;
1205		printf("%u ms (%i%%),(%u t/s)\r\n",time,(time-cfgBenchmark14_Reference)*100/time,(t*1000)/time);
1206	}
1207	if(cfgBenchmark15_Enable)
1208	{// Benchmark 15
1209		srand(380843);
1210		btDbvt								dbvt;
1211		btAlignedObjectArray<btVector3>		vectors;
1212		btDbvtBenchmark::P15				policy;
1213		vectors.resize(cfgBenchmark15_Iterations);
1214		for(int i=0;i<vectors.size();++i)
1215		{
1216			vectors[i]=(btDbvtBenchmark::RandVector3()*2-btVector3(1,1,1)).normalized();
1217		}
1218		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt);
1219		dbvt.optimizeTopDown();
1220		policy.m_nodes.reserve(cfgLeaves);
1221		printf("[15] culling(KDOP+qsort): ");
1222		wallclock.reset();
1223		for(int i=0;i<cfgBenchmark15_Iterations;++i)
1224		{
1225			static const btScalar	offset=0;
1226			policy.m_nodes.resize(0);
1227			policy.m_axis=vectors[i];
1228			dbvt.collideKDOP(dbvt.m_root,&vectors[i],&offset,1,policy);
1229			policy.m_nodes.quickSort(btDbvtBenchmark::P15::sortfnc);
1230		}
1231		const int	time=(int)wallclock.getTimeMilliseconds();
1232		const int	t=cfgBenchmark15_Iterations;
1233		printf("%u ms (%i%%),(%u t/s)\r\n",time,(time-cfgBenchmark15_Reference)*100/time,(t*1000)/time);
1234	}
1235	if(cfgBenchmark16_Enable)
1236	{// Benchmark 16
1237		srand(380843);
1238		btDbvt								dbvt;
1239		btAlignedObjectArray<btDbvtNode*>	batch;
1240		btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt);
1241		dbvt.optimizeTopDown();
1242		batch.reserve(cfgBenchmark16_BatchCount);
1243		printf("[16] insert/remove batch(%u): ",cfgBenchmark16_BatchCount);
1244		wallclock.reset();
1245		for(int i=0;i<cfgBenchmark16_Passes;++i)
1246		{
1247			for(int j=0;j<cfgBenchmark16_BatchCount;++j)
1248			{
1249				batch.push_back(dbvt.insert(btDbvtBenchmark::RandVolume(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale),0));
1250			}
1251			for(int j=0;j<cfgBenchmark16_BatchCount;++j)
1252			{
1253				dbvt.remove(batch[j]);
1254			}
1255			batch.resize(0);
1256		}
1257		const int	time=(int)wallclock.getTimeMilliseconds();
1258		const int	ir=cfgBenchmark16_Passes*cfgBenchmark16_BatchCount;
1259		printf("%u ms (%i%%),(%u bir/s)\r\n",time,(time-cfgBenchmark16_Reference)*100/time,int(ir*1000.0/time));
1260	}
1261	if(cfgBenchmark17_Enable)
1262	{// Benchmark 17
1263		srand(380843);
1264		btAlignedObjectArray<btDbvtVolume>	volumes;
1265		btAlignedObjectArray<int>			results;
1266		btAlignedObjectArray<int>			indices;
1267		volumes.resize(cfgLeaves);
1268		results.resize(cfgLeaves);
1269		indices.resize(cfgLeaves);
1270		for(int i=0;i<cfgLeaves;++i)
1271		{
1272			indices[i]=i;
1273			volumes[i]=btDbvtBenchmark::RandVolume(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale);
1274		}
1275		for(int i=0;i<cfgLeaves;++i)
1276		{
1277			btSwap(indices[i],indices[rand()%cfgLeaves]);
1278		}
1279		printf("[17] btDbvtVolume select: ");
1280		wallclock.reset();
1281		for(int i=0;i<cfgBenchmark17_Iterations;++i)
1282		{
1283			for(int j=0;j<cfgLeaves;++j)
1284			{
1285				for(int k=0;k<cfgLeaves;++k)
1286				{
1287					const int idx=indices[k];
1288					results[idx]=Select(volumes[idx],volumes[j],volumes[k]);
1289				}
1290			}
1291		}
1292		const int time=(int)wallclock.getTimeMilliseconds();
1293		printf("%u ms (%i%%)\r\n",time,(time-cfgBenchmark17_Reference)*100/time);
1294	}
1295	printf("\r\n\r\n");
1296}
1297#endif
1298