void SceneQueryManager::validateSimUpdates()
{
	if (mPrunerExt[1].type() != PxPruningStructureType::eDYNAMIC_AABB_TREE)
		return;

	
	Sc::BodyCore*const* activeBodies = mScene.getActiveBodiesArray();
	const PxU32 nbActiveBodies = mScene.getNumActiveBodies();

	for (PxU32 i = 0; i < nbActiveBodies; ++i)
	{
		const Sc::BodyCore* bCore = activeBodies[i];

		if (bCore->isFrozen())
			continue;

		PxRigidBody* pxBody = static_cast<PxRigidBody*>(bCore->getPxActor());

		PX_ASSERT(pxBody->getConcreteType() == PxConcreteType::eRIGID_DYNAMIC || pxBody->getConcreteType() == PxConcreteType::eARTICULATION_LINK);

		NpShapeManager& shapeManager = *NpActor::getShapeManager(*pxBody);
		const PxU32 nbShapes = shapeManager.getNbShapes();
		NpShape* const* shape = shapeManager.getShapes();
		

		for (PxU32 j = 0; j<nbShapes; j++)
		{
			PrunerData prunerData = shapeManager.getPrunerData(j);
			if (prunerData != INVALID_PRUNERHANDLE)
			{
				const PrunerHandle handle = getPrunerHandle(prunerData);
				const PxBounds3 worldAABB = computeWorldAABB(shape[j]->getScbShape(), *bCore);
				PxBounds3 prunerAABB = static_cast<AABBPruner*>(mPrunerExt[1].pruner())->getAABB(handle);
				PX_ASSERT((worldAABB.minimum - prunerAABB.minimum).magnitudeSquared() < 0.005f*mScene.getPxScene()->getPhysics().getTolerancesScale().length);
				PX_ASSERT((worldAABB.maximum - prunerAABB.maximum).magnitudeSquared() < 0.005f*mScene.getPxScene()->getPhysics().getTolerancesScale().length);
				PX_UNUSED(worldAABB);
				PX_UNUSED(prunerAABB);
			}
		}
	}
}
void SceneQueryManager::processSimUpdates()
{
	PX_PROFILE_ZONE("Sim.updatePruningTrees", mScene.getContextId());

	{
		PX_PROFILE_ZONE("SceneQuery.processActiveShapes", mScene.getContextId());

		// update all active objects
		BodyCore*const* activeBodies = mScene.getScScene().getActiveBodiesArray();
		PxU32 nbActiveBodies = mScene.getScScene().getNumActiveBodies();

#define NB_BATCHED_OBJECTS	128
		PrunerHandle batchedHandles[NB_BATCHED_OBJECTS];
		PxU32 nbBatchedObjects = 0;
		Pruner* pruner = mPrunerExt[PruningIndex::eDYNAMIC].pruner();

		while(nbActiveBodies--)
		{
			// PT: TODO: don't put frozen objects in "active bodies" array? After all they
			// are also not included in the 'active transforms' or 'active actors' arrays.
			BodyCore* currentBody = *activeBodies++;
			if(currentBody->isFrozen())
				continue;

			PxActorType::Enum type;
			PxRigidBody* pxBody = static_cast<PxRigidBody*>(getPxActorFromBodyCore(currentBody, type));
			PX_ASSERT(pxBody->getConcreteType()==PxConcreteType::eRIGID_DYNAMIC || pxBody->getConcreteType()==PxConcreteType::eARTICULATION_LINK);

			NpShapeManager* shapeManager;
			if(type==PxActorType::eRIGID_DYNAMIC)
			{
				NpRigidDynamic* rigidDynamic = static_cast<NpRigidDynamic*>(pxBody);
				shapeManager = &rigidDynamic->getShapeManager();
			}
			else
			{
				NpArticulationLink* articulationLink = static_cast<NpArticulationLink*>(pxBody);
				shapeManager = &articulationLink->getShapeManager();
			}

			const PxU32 nbShapes = shapeManager->getNbShapes();
			for(PxU32 i=0; i<nbShapes; i++)
			{
				const PrunerData data = shapeManager->getPrunerData(i);
				if(data!=SQ_INVALID_PRUNER_DATA)
				{
					// PT: index can't be zero here!
					PX_ASSERT(getPrunerIndex(data)==PruningIndex::eDYNAMIC);

					const PrunerHandle handle = getPrunerHandle(data);

					if(!mPrunerExt[PruningIndex::eDYNAMIC].isDirty(handle))	// PT: if dirty, will be updated in "flushShapes"
					{
						batchedHandles[nbBatchedObjects] = handle;

						PxBounds3* bounds;
						const PrunerPayload& pp = pruner->getPayload(handle, bounds);
						computeDynamicWorldAABB(*bounds, *(reinterpret_cast<Scb::Shape*>(pp.data[0])), *(reinterpret_cast<Scb::Actor*>(pp.data[1])));
						nbBatchedObjects++;

						if(nbBatchedObjects==NB_BATCHED_OBJECTS)
						{
							mPrunerExt[PruningIndex::eDYNAMIC].invalidateTimestamp();
							pruner->updateObjects(batchedHandles, NULL, nbBatchedObjects);
							nbBatchedObjects = 0;
						}
					}
				}
			}
		}
		if(nbBatchedObjects)
		{
			mPrunerExt[PruningIndex::eDYNAMIC].invalidateTimestamp();
			pruner->updateObjects(batchedHandles, NULL, nbBatchedObjects);
		}
	}

	// flush user modified objects
	flushShapes();

	for(PxU32 i=0;i<PruningIndex::eCOUNT;i++)
	{
		if(mPrunerExt[i].pruner() && mPrunerExt[i].type() == PxPruningStructureType::eDYNAMIC_AABB_TREE)
			static_cast<AABBPruner*>(mPrunerExt[i].pruner())->buildStep();

		mPrunerExt[i].pruner()->commit();
	}
}