PageRenderTime 62ms CodeModel.GetById 17ms app.highlight 25ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/ode/ode_source/OPCODE/OPC_PlanesCollider.cpp

http://narutortsproject.googlecode.com/
C++ | 653 lines | 339 code | 110 blank | 204 comment | 63 complexity | 89ee7f185f1bee92a8165058ae067d82 MD5 | raw file
  1///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2/*
  3 *	OPCODE - Optimized Collision Detection
  4 *	Copyright (C) 2001 Pierre Terdiman
  5 *	Homepage: http://www.codercorner.com/Opcode.htm
  6 */
  7///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8
  9///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 10/**
 11 *	Contains code for a planes collider.
 12 *	\file		OPC_PlanesCollider.cpp
 13 *	\author		Pierre Terdiman
 14 *	\date		January, 1st, 2002
 15 */
 16///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 17
 18///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 19/**
 20 *	Contains a Planes-vs-tree collider.
 21 *
 22 *	\class		PlanesCollider
 23 *	\author		Pierre Terdiman
 24 *	\version	1.3
 25 *	\date		January, 1st, 2002
 26*/
 27///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 28
 29///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 30// Precompiled Header
 31#include "Stdafx.h"
 32
 33using namespace Opcode;
 34
 35#include "OPC_PlanesAABBOverlap.h"
 36#include "OPC_PlanesTriOverlap.h"
 37
 38#define SET_CONTACT(prim_index, flag)		\
 39	/* Set contact status */				\
 40	mFlags |= flag;							\
 41	mTouchedPrimitives->Add(udword(prim_index));
 42
 43//! Planes-triangle test
 44#define PLANES_PRIM(prim_index, flag)		\
 45	/* Request vertices from the app */		\
 46	mIMesh->GetTriangle(mVP, prim_index, mVC);	\
 47	/* Perform triangle-box overlap test */	\
 48	if(PlanesTriOverlap(clip_mask))			\
 49	{										\
 50		SET_CONTACT(prim_index, flag)		\
 51	}
 52
 53///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 54/**
 55 *	Constructor.
 56 */
 57///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 58PlanesCollider::PlanesCollider() :
 59	mNbPlanes	(0),
 60	mPlanes		(null)
 61{
 62}
 63
 64///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 65/**
 66 *	Destructor.
 67 */
 68///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 69PlanesCollider::~PlanesCollider()
 70{
 71	DELETEARRAY(mPlanes);
 72}
 73
 74///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 75/**
 76 *	Validates current settings. You should call this method after all the settings and callbacks have been defined.
 77 *	\return		null if everything is ok, else a string describing the problem
 78 */
 79///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 80const char* PlanesCollider::ValidateSettings()
 81{
 82	if(TemporalCoherenceEnabled() && !FirstContactEnabled())	return "Temporal coherence only works with ""First contact"" mode!";
 83
 84	return VolumeCollider::ValidateSettings();
 85}
 86
 87///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 88/**
 89 *	Generic collision query for generic OPCODE models. After the call, access the results:
 90 *	- with GetContactStatus()
 91 *	- with GetNbTouchedPrimitives()
 92 *	- with GetTouchedPrimitives()
 93 *
 94 *	\param		cache		[in/out] a planes cache
 95 *	\param		planes		[in] list of planes in world space
 96 *	\param		nb_planes	[in] number of planes
 97 *	\param		model		[in] Opcode model to collide with
 98 *	\param		worldm		[in] model's world matrix, or null
 99 *	\return		true if success
100 *	\warning	SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
101 */
102///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
103bool PlanesCollider::Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const Model& model, const Matrix4x4* worldm)
104{
105	// Checkings
106	if(!Setup(&model))	return false;
107
108	// Init collision query
109	if(InitQuery(cache, planes, nb_planes, worldm))	return true;
110
111	udword PlaneMask = (1<<nb_planes)-1;
112
113	if(!model.HasLeafNodes())
114	{
115		if(model.IsQuantized())
116		{
117			const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
118
119			// Setup dequantization coeffs
120			mCenterCoeff	= Tree->mCenterCoeff;
121			mExtentsCoeff	= Tree->mExtentsCoeff;
122
123			// Perform collision query
124			if(SkipPrimitiveTests())	_CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
125			else						_Collide(Tree->GetNodes(), PlaneMask);
126		}
127		else
128		{
129			const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
130
131			// Perform collision query
132			if(SkipPrimitiveTests())	_CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
133			else						_Collide(Tree->GetNodes(), PlaneMask);
134		}
135	}
136	else
137	{
138		if(model.IsQuantized())
139		{
140			const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
141
142			// Setup dequantization coeffs
143			mCenterCoeff	= Tree->mCenterCoeff;
144			mExtentsCoeff	= Tree->mExtentsCoeff;
145
146			// Perform collision query
147			if(SkipPrimitiveTests())	_CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
148			else						_Collide(Tree->GetNodes(), PlaneMask);
149		}
150		else
151		{
152			const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
153
154			// Perform collision query
155			if(SkipPrimitiveTests())	_CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
156			else						_Collide(Tree->GetNodes(), PlaneMask);
157		}
158	}
159	return true;
160}
161
162///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
163/**
164 *	Initializes a collision query :
165 *	- reset stats & contact status
166 *	- compute planes in model space
167 *	- check temporal coherence
168 *
169 *	\param		cache		[in/out] a planes cache
170 *	\param		planes		[in] list of planes
171 *	\param		nb_planes	[in] number of planes
172 *	\param		worldm		[in] model's world matrix, or null
173 *	\return		TRUE if we can return immediately
174 *	\warning	SCALE NOT SUPPORTED. The matrix must contain rotation & translation parts only.
175 */
176///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
177BOOL PlanesCollider::InitQuery(PlanesCache& cache, const Plane* planes, udword nb_planes, const Matrix4x4* worldm)
178{
179	// 1) Call the base method
180	VolumeCollider::InitQuery();
181
182	// 2) Compute planes in model space
183	if(nb_planes>mNbPlanes)
184	{
185		DELETEARRAY(mPlanes);
186		mPlanes = new Plane[nb_planes];
187	}
188	mNbPlanes = nb_planes;
189
190	if(worldm)
191	{
192		Matrix4x4 InvWorldM;
193		InvertPRMatrix(InvWorldM, *worldm);
194
195//		for(udword i=0;i<nb_planes;i++)	mPlanes[i] = planes[i] * InvWorldM;
196		for(udword i=0;i<nb_planes;i++)	TransformPlane(mPlanes[i], planes[i], InvWorldM);
197	}
198	else CopyMemory(mPlanes, planes, nb_planes*sizeof(Plane));
199
200	// 3) Setup destination pointer
201	mTouchedPrimitives = &cache.TouchedPrimitives;
202
203	// 4) Special case: 1-triangle meshes [Opcode 1.3]
204	if(mCurrentModel && mCurrentModel->HasSingleNode())
205	{
206		if(!SkipPrimitiveTests())
207		{
208			// We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0.
209			mTouchedPrimitives->Reset();
210
211			// Perform overlap test between the unique triangle and the planes (and set contact status if needed)
212			udword clip_mask = (1<<mNbPlanes)-1;
213			PLANES_PRIM(udword(0), OPC_CONTACT)
214
215			// Return immediately regardless of status
216			return TRUE;
217		}
218	}
219
220	// 4) Check temporal coherence:
221	if(TemporalCoherenceEnabled())
222	{
223		// Here we use temporal coherence
224		// => check results from previous frame before performing the collision query
225		if(FirstContactEnabled())
226		{
227			// We're only interested in the first contact found => test the unique previously touched face
228			if(mTouchedPrimitives->GetNbEntries())
229			{
230				// Get index of previously touched face = the first entry in the array
231				udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0);
232
233				// Then reset the array:
234				// - if the overlap test below is successful, the index we'll get added back anyway
235				// - if it isn't, then the array should be reset anyway for the normal query
236				mTouchedPrimitives->Reset();
237
238				// Perform overlap test between the cached triangle and the planes (and set contact status if needed)
239				udword clip_mask = (1<<mNbPlanes)-1;
240				PLANES_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT)
241
242				// Return immediately if possible
243				if(GetContactStatus())	return TRUE;
244			}
245			// else no face has been touched during previous query
246			// => we'll have to perform a normal query
247		}
248		else mTouchedPrimitives->Reset();
249	}
250	else
251	{
252		// Here we don't use temporal coherence => do a normal query
253		mTouchedPrimitives->Reset();
254	}
255
256	return FALSE;
257}
258
259#define TEST_CLIP_MASK																					\
260	/* If the box is completely included, so are its children. We don't need to do extra tests, we */	\
261	/* can immediately output a list of visible children. Those ones won't need to be clipped. */		\
262	if(!OutClipMask)																					\
263	{																									\
264		/* Set contact status */																		\
265		mFlags |= OPC_CONTACT;																			\
266		_Dump(node);																					\
267		return;																							\
268	}
269
270///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
271/**
272 *	Recursive collision query for normal AABB trees.
273 *	\param		node	[in] current collision node
274 */
275///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
276void PlanesCollider::_Collide(const AABBCollisionNode* node, udword clip_mask)
277{
278	// Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
279	udword OutClipMask;
280	if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask))	return;
281
282	TEST_CLIP_MASK
283
284	// Else the box straddles one or several planes, so we need to recurse down the tree.
285	if(node->IsLeaf())
286	{
287		PLANES_PRIM(node->GetPrimitive(), OPC_CONTACT)
288	}
289	else
290	{
291		_Collide(node->GetPos(), OutClipMask);
292
293		if(ContactFound()) return;
294
295		_Collide(node->GetNeg(), OutClipMask);
296	}
297}
298
299///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
300/**
301 *	Recursive collision query for normal AABB trees.
302 *	\param		node	[in] current collision node
303 */
304///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
305void PlanesCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node, udword clip_mask)
306{
307	// Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
308	udword OutClipMask;
309	if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask))	return;
310
311	TEST_CLIP_MASK
312
313	// Else the box straddles one or several planes, so we need to recurse down the tree.
314	if(node->IsLeaf())
315	{
316		SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
317	}
318	else
319	{
320		_CollideNoPrimitiveTest(node->GetPos(), OutClipMask);
321
322		if(ContactFound()) return;
323
324		_CollideNoPrimitiveTest(node->GetNeg(), OutClipMask);
325	}
326}
327
328///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
329/**
330 *	Recursive collision query for quantized AABB trees.
331 *	\param		node	[in] current collision node
332 */
333///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
334void PlanesCollider::_Collide(const AABBQuantizedNode* node, udword clip_mask)
335{
336	// Dequantize box
337	const QuantizedAABB& Box = node->mAABB;
338	const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
339	const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
340
341	// Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
342	udword OutClipMask;
343	if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask))	return;
344
345	TEST_CLIP_MASK
346
347	// Else the box straddles one or several planes, so we need to recurse down the tree.
348	if(node->IsLeaf())
349	{
350		PLANES_PRIM(node->GetPrimitive(), OPC_CONTACT)
351	}
352	else
353	{
354		_Collide(node->GetPos(), OutClipMask);
355
356		if(ContactFound()) return;
357
358		_Collide(node->GetNeg(), OutClipMask);
359	}
360}
361
362///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
363/**
364 *	Recursive collision query for quantized AABB trees.
365 *	\param		node	[in] current collision node
366 */
367///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
368void PlanesCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node, udword clip_mask)
369{
370	// Dequantize box
371	const QuantizedAABB& Box = node->mAABB;
372	const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
373	const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
374
375	// Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
376	udword OutClipMask;
377	if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask))	return;
378
379	TEST_CLIP_MASK
380
381	// Else the box straddles one or several planes, so we need to recurse down the tree.
382	if(node->IsLeaf())
383	{
384		SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
385	}
386	else
387	{
388		_CollideNoPrimitiveTest(node->GetPos(), OutClipMask);
389
390		if(ContactFound()) return;
391
392		_CollideNoPrimitiveTest(node->GetNeg(), OutClipMask);
393	}
394}
395
396///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
397/**
398 *	Recursive collision query for no-leaf AABB trees.
399 *	\param		node	[in] current collision node
400 */
401///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
402void PlanesCollider::_Collide(const AABBNoLeafNode* node, udword clip_mask)
403{
404	// Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
405	udword OutClipMask;
406	if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask))	return;
407
408	TEST_CLIP_MASK
409
410	// Else the box straddles one or several planes, so we need to recurse down the tree.
411	if(node->HasPosLeaf())	{ PLANES_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
412	else					_Collide(node->GetPos(), OutClipMask);
413
414	if(ContactFound()) return;
415
416	if(node->HasNegLeaf())	{ PLANES_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
417	else					_Collide(node->GetNeg(), OutClipMask);
418}
419
420///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
421/**
422 *	Recursive collision query for no-leaf AABB trees.
423 *	\param		node	[in] current collision node
424 */
425///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
426void PlanesCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node, udword clip_mask)
427{
428	// Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
429	udword OutClipMask;
430	if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask))	return;
431
432	TEST_CLIP_MASK
433
434	// Else the box straddles one or several planes, so we need to recurse down the tree.
435	if(node->HasPosLeaf())	{ SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
436	else					_CollideNoPrimitiveTest(node->GetPos(), OutClipMask);
437
438	if(ContactFound()) return;
439
440	if(node->HasNegLeaf())	{ SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
441	else					_CollideNoPrimitiveTest(node->GetNeg(), OutClipMask);
442}
443
444///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
445/**
446 *	Recursive collision query for quantized no-leaf AABB trees.
447 *	\param		node	[in] current collision node
448 */
449///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
450void PlanesCollider::_Collide(const AABBQuantizedNoLeafNode* node, udword clip_mask)
451{
452	// Dequantize box
453	const QuantizedAABB& Box = node->mAABB;
454	const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
455	const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
456
457	// Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
458	udword OutClipMask;
459	if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask))	return;
460
461	TEST_CLIP_MASK
462
463	// Else the box straddles one or several planes, so we need to recurse down the tree.
464	if(node->HasPosLeaf())	{ PLANES_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
465	else					_Collide(node->GetPos(), OutClipMask);
466
467	if(ContactFound()) return;
468
469	if(node->HasNegLeaf())	{ PLANES_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
470	else					_Collide(node->GetNeg(), OutClipMask);
471}
472
473///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
474/**
475 *	Recursive collision query for quantized no-leaf AABB trees.
476 *	\param		node	[in] current collision node
477 */
478///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
479void PlanesCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node, udword clip_mask)
480{
481	// Dequantize box
482	const QuantizedAABB& Box = node->mAABB;
483	const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
484	const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
485
486	// Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
487	udword OutClipMask;
488	if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask))	return;
489
490	TEST_CLIP_MASK
491
492	// Else the box straddles one or several planes, so we need to recurse down the tree.
493	if(node->HasPosLeaf())	{ SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
494	else					_CollideNoPrimitiveTest(node->GetPos(), OutClipMask);
495
496	if(ContactFound()) return;
497
498	if(node->HasNegLeaf())	{ SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
499	else					_CollideNoPrimitiveTest(node->GetNeg(), OutClipMask);
500}
501
502
503
504
505
506
507
508///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
509/**
510 *	Constructor.
511 */
512///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
513HybridPlanesCollider::HybridPlanesCollider()
514{
515}
516
517///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
518/**
519 *	Destructor.
520 */
521///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
522HybridPlanesCollider::~HybridPlanesCollider()
523{
524}
525
526bool HybridPlanesCollider::Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const HybridModel& model, const Matrix4x4* worldm)
527{
528	// We don't want primitive tests here!
529	mFlags |= OPC_NO_PRIMITIVE_TESTS;
530
531	// Checkings
532	if(!Setup(&model))	return false;
533
534	// Init collision query
535	if(InitQuery(cache, planes, nb_planes, worldm))	return true;
536
537	// Special case for 1-leaf trees
538	if(mCurrentModel && mCurrentModel->HasSingleNode())
539	{
540		// Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles
541		udword Nb = mIMesh->GetNbTriangles();
542
543		// Loop through all triangles
544		udword clip_mask = (1<<mNbPlanes)-1;
545		for(udword i=0;i<Nb;i++)
546		{
547			PLANES_PRIM(i, OPC_CONTACT)
548		}
549		return true;
550	}
551
552	// Override destination array since we're only going to get leaf boxes here
553	mTouchedBoxes.Reset();
554	mTouchedPrimitives = &mTouchedBoxes;
555
556	udword PlaneMask = (1<<nb_planes)-1;
557
558	// Now, do the actual query against leaf boxes
559	if(!model.HasLeafNodes())
560	{
561		if(model.IsQuantized())
562		{
563			const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
564
565			// Setup dequantization coeffs
566			mCenterCoeff	= Tree->mCenterCoeff;
567			mExtentsCoeff	= Tree->mExtentsCoeff;
568
569			// Perform collision query - we don't want primitive tests here!
570			_CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
571		}
572		else
573		{
574			const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
575
576			// Perform collision query - we don't want primitive tests here!
577			_CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
578		}
579	}
580	else
581	{
582		if(model.IsQuantized())
583		{
584			const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
585
586			// Setup dequantization coeffs
587			mCenterCoeff	= Tree->mCenterCoeff;
588			mExtentsCoeff	= Tree->mExtentsCoeff;
589
590			// Perform collision query - we don't want primitive tests here!
591			_CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
592		}
593		else
594		{
595			const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
596
597			// Perform collision query - we don't want primitive tests here!
598			_CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
599		}
600	}
601
602	// We only have a list of boxes so far
603	if(GetContactStatus())
604	{
605		// Reset contact status, since it currently only reflects collisions with leaf boxes
606		Collider::InitQuery();
607
608		// Change dest container so that we can use built-in overlap tests and get collided primitives
609		cache.TouchedPrimitives.Reset();
610		mTouchedPrimitives = &cache.TouchedPrimitives;
611
612		// Read touched leaf boxes
613		udword Nb = mTouchedBoxes.GetNbEntries();
614		const udword* Touched = mTouchedBoxes.GetEntries();
615
616		const LeafTriangles* LT = model.GetLeafTriangles();
617		const udword* Indices = model.GetIndices();
618
619		// Loop through touched leaves
620		udword clip_mask = (1<<mNbPlanes)-1;
621		while(Nb--)
622		{
623			const LeafTriangles& CurrentLeaf = LT[*Touched++];
624
625			// Each leaf box has a set of triangles
626			udword NbTris = CurrentLeaf.GetNbTriangles();
627			if(Indices)
628			{
629				const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
630
631				// Loop through triangles and test each of them
632				while(NbTris--)
633				{
634					udword TriangleIndex = *T++;
635					PLANES_PRIM(TriangleIndex, OPC_CONTACT)
636				}
637			}
638			else
639			{
640				udword BaseIndex = CurrentLeaf.GetTriangleIndex();
641
642				// Loop through triangles and test each of them
643				while(NbTris--)
644				{
645					udword TriangleIndex = BaseIndex++;
646					PLANES_PRIM(TriangleIndex, OPC_CONTACT)
647				}
648			}
649		}
650	}
651
652	return true;
653}