//----------------------------------------------------------------------- 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 ); } } } } }