//-----------------------------------------------------------------------
void DefaultExtRaySceneQuery::execute( ExtRaySceneQueryListener* _listener )
{
    mOgreQuery->setQueryMask( getQueryMask() );
    mOgreQuery->setQueryTypeMask( getQueryTypeMask() );
    mOgreQuery->setWorldFragmentType( getWorldFragmentType() );
    mOgreQuery->setRay( getRay() );

    BridgeQueryListener bql( _listener );
    mOgreQuery->execute( &bql );
}
//---------------------------------------------------------------------
// Well return via callbacks a set of rectangular tile sub-sections.
// All fragments returned via callback use a WFT_CUSTOM_GEOMETRY type.
// The CustomQueryResult structure defined above is what is passed
// in the void* geometry field.  The type_ field of the CustomQuery
// result determins what is being sent in the fragment as follows:
//
// QUERY_EXTENTS_TYPE:  Sent as the first result, this gives the width
// and height (in tile subsections) of the entire query result.  The
// render level in this case is not defined.
//
// SUBSECTION_EXTENTS_TYPE:  Sent before each sub-section's vertex
// data.  This contains the height, width, and render level of the
// subsequent vertex data.
//
// VERTEX_TYPE:  This is the actual vertex data, and whether the vertex
// is included when displayed at the tile's current render level.
//
// The seemingly complex way of returning the data is so that the same
// stitching algorithm used by PLSM can be used by the client in
// creating a mesh out of the data.
//---------------------------------------------------------------------
void PagingLandScapeAxisAlignedBoxSceneQuery::execute(SceneQueryListener* listener)
{
	if( !( getQueryTypeMask() & SceneManager::WORLD_GEOMETRY_TYPE_MASK ) )
	{
        OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, 
					 "PagingLandScapeSceneManager only supports WORLD_GEOMETRY_TYPE_MASK for AxisAlignedBoxSceneQueries", 
					 "PagingLandScapeAxisAlignedBoxSceneQuery::execute");
	}
	PagingLandScapeSceneManager* mgr = static_cast< PagingLandScapeSceneManager* >(mParentSceneMgr);

	// Currently we ignore the y coords of the bounding box and assume they
	// want all the vertices in the xz square.
	
	// Determine page that each corner of AABB is on.
	Vector3 min = mAABB.getMinimum();
	Vector3 max = mAABB.getMaximum();

	// Pre-gather some constants.
	const PagingLandScapeOptions* options = mgr->getOptions();
	const Vector3& scale = options->scale;
	const Real maxUnScaledX = options->maxUnScaledX;
	const Real maxUnScaledZ = options->maxUnScaledZ;
	const uint pageSize = options->PageSize - 1;
	const Real invPageSize = 1.0f / pageSize;
	const uint tileSize = options->TileSize - 1;
    const Real invTileSize = 1.0f / tileSize;
	const uint maxNumTiles = options->NumTiles;
	const uint worldWidth = options->world_width;
	const uint worldHeight = options->world_height;
	// Note that for efficiency here, I'm not allocating a new WorldFragment 
	// every time, so clients will have to use the subscribtion mechanism to
	// get the results, as the execute() that returns the SceneQueryResult
	// will contain a collection of only the last result.  TODO:  The ogre
	// RegionSceneQuery could be modified to only do heap allocation when
	// the subscription mechanism isn't being used by the client.
	WorldFragment worldFragment;
	worldFragment.fragmentType = SceneQuery::WFT_CUSTOM_GEOMETRY;
	CustomQueryResult result;
	worldFragment.geometry = &result;

	// Calculate page min/max.
	uint minPageX;
	Real localPageMinXReal;
	bool minXInWorld;
	uint minPageZ;
	Real localPageMinZReal;
	bool minZInWorld;
	uint maxPageX;
	Real localPageMaxXReal;
	bool maxXInWorld;
	uint maxPageZ;
	Real localPageMaxZReal;
	bool maxZInWorld;

	minXInWorld = WorldToPage( min.x, scale.x, maxUnScaledX, pageSize, invPageSize, worldWidth, minPageX, localPageMinXReal );
	minZInWorld = WorldToPage( min.z, scale.z, maxUnScaledZ, pageSize, invPageSize, worldHeight, minPageZ, localPageMinZReal );
	maxXInWorld = WorldToPage( max.x, scale.x, maxUnScaledX, pageSize, invPageSize, worldWidth, maxPageX, localPageMaxXReal );
	maxZInWorld = WorldToPage( max.z, scale.z, maxUnScaledZ, pageSize, invPageSize, worldHeight, maxPageZ, localPageMaxZReal );

	// At least one corner of the bounding box must be inside the world, or
	// we return no results.
	if( !( minXInWorld && minZInWorld ) || !( maxXInWorld && maxZInWorld ) ||
		!( minXInWorld && maxZInWorld ) || !( maxXInWorld && minZInWorld ) )
		return;

	// Determine the width and height of the query in terms of tile sub-sections.
	// We need to make sure we return enough vertices so the entire bounding box
	// fits within.  That means for lodded tiles we may need to move to the 
	// next valid vertex, however, satisfying this requirement should never change
	// the query extents because every tile has valid vertices at its edges.
	int localPageMinX = static_cast<int>( localPageMinXReal );
	int localPageMinZ = static_cast<int>( localPageMinZReal );
	int localPageMaxX = static_cast<int>( Math::Ceil( localPageMaxXReal ) );
	int localPageMaxZ = static_cast<int>( Math::Ceil( localPageMaxZReal ) );

	LodTracker lodTracker( scale, 
						   maxUnScaledX,
						   maxUnScaledZ,
						   pageSize,
						   tileSize,
						   maxNumTiles,
						   mgr->getPageManager(),
						   mgr->getData2DManager() );

	// TODO:  Expensive routine.  Can we do away with it or optimze it somehow?
	AdjustEdgesForLod( lodTracker, 
					   minPageX, minPageZ, maxPageX, maxPageZ,
					   localPageMinX, localPageMinZ, localPageMaxX, localPageMaxZ );

	// Pre-calculate the width and height of the whole query in terms of how many
	// tile sub-sections we'll have.
	int middleTiles = ( static_cast<int>( maxPageX ) - static_cast<int>( minPageX ) - 1 ) * 
					  ( pageSize / tileSize );							// Get the contribution from the middle pages.
	int leftTiles = ( maxNumTiles - PageToTile( localPageMinX, 
												invTileSize, 
												maxNumTiles ) );		// Get contribution from the left side.
	int rightTiles = PageToTile( localPageMaxX - 1, 
								 invTileSize, 
								 maxNumTiles ) + 1;						// Get contribution from the right side.
	int calcWidth = leftTiles + middleTiles + rightTiles;

	middleTiles = ( static_cast<int>( maxPageZ ) - static_cast<int>( minPageZ ) - 1 ) * 
				  ( pageSize / tileSize );								// Get the contribution from the middle pages.
	leftTiles = ( maxNumTiles - PageToTile( localPageMinZ, 
											invTileSize, 
											maxNumTiles ) );			// Get contribution from the left side.
	rightTiles = PageToTile( localPageMaxZ - 1, 
							 invTileSize,
							 maxNumTiles ) + 1;							// Get contribution from the right side.
	int calcHeight = leftTiles + middleTiles + rightTiles;

	//Real calcWidth = ( maxPageX == minPageX ) ? localPageMaxX - localPageMinX + 1 :
	//										    ( pageSize - localPageMinX ) + localPageMaxX + 1 +
	//										    ( maxPageX - minPageX - 1 ) * pageSize;
	//Real calcHeight = ( maxPageZ == minPageZ ) ? localPageMaxZ - localPageMinZ + 1 :
	//										     ( pageSize - localPageMinZ ) + localPageMaxZ + 1 +
	//											 ( maxPageZ - minPageZ - 1 ) * pageSize;
	// Notify our caller about the width and height, using custom geometry type.
	result.SetQueryExtents( calcWidth, calcHeight );
	listener->queryResult( &worldFragment );

	uint subZ = 0;
	for( uint pageZ = minPageZ; pageZ <= maxPageZ; ++pageZ )
	{
		// Determine Z tile range on this page.
		uint tileBeginZ = ( pageZ == minPageZ ) ?
									PageToTile( localPageMinZ, invTileSize, maxNumTiles ) : 0;
		uint tileEndZ = ( pageZ == maxPageZ ) ? 
									PageToTile( localPageMaxZ - 1, invTileSize, maxNumTiles ) : maxNumTiles - 1;
		for( uint tileZ = tileBeginZ; tileZ <= tileEndZ; ++tileZ, ++subZ )
		{
			uint subX = 0;
			for( uint pageX = minPageX; pageX <= maxPageX; ++pageX )
			{
				lodTracker.SetPage( pageX, pageZ );
			
				// Determine X tile range on this page.
				uint tileBeginX = ( pageX == minPageX ) ? PageToTile( localPageMinX, invTileSize, maxNumTiles ) : 0;
				uint tileEndX = ( pageX == maxPageX ) ? PageToTile( localPageMaxX - 1, invTileSize, maxNumTiles ) : maxNumTiles - 1;

				for( uint tileX = tileBeginX; tileX <= tileEndX; ++tileX, ++subX )
				{
					// Determine the Z local page coord range for this tile.
					uint localPageBeginZ = ( pageZ == minPageZ ) && ( tileZ == tileBeginZ ) ? 
													localPageMinZ : tileZ * tileSize;
					uint localPageEndZ = ( pageZ == maxPageZ ) && ( tileZ == tileEndZ ) ? 
													localPageMaxZ : ( tileZ + 1 ) * tileSize;

					// Determine the X local page coord range for this tile.
					uint localPageBeginX = ( pageX == minPageX ) && ( tileX == tileBeginX ) ? 
													localPageMinX : tileX * tileSize;
					uint localPageEndX = ( pageX == maxPageX ) && ( tileX == tileEndX ) ? 
													localPageMaxX : ( tileX + 1 ) * tileSize;

					DoTileSubSection( lodTracker, worldFragment, result, listener,
									  localPageBeginX, localPageBeginZ, localPageEndX, localPageEndZ,
									  subX, subZ );
				}
			}
		}
	}
}