//----------------------------------------------------------------------- void PagingLandScapePageManager::updateLoadedPages() { // Make any pending updates to the calculated frustum mCurrentcam->updateView(); const Vector3 pos(mCurrentcam->getDerivedPosition().x, 127.0f, mCurrentcam->getDerivedPosition().z); for (PagingLandScapePageList::iterator it = mLoadedPages.begin(); it != mLoadedPages.end(); ++it) { PagingLandScapePage* p = (*it); unsigned int x, z; p->getCoordinates(x, z); if ((z >= mCurrentcam->mIniZ) && (z <= mCurrentcam->mFinZ) && (x >= mCurrentcam->mIniX) && (x <= mCurrentcam->mFinX)) { // inform pages that they are near Camera on next render. if (p->notify(pos, mCurrentcam)) { // get pages that need modification and are visible.. PagingLandScapeTexture* tex = mTexture->getTexture(x, z); assert(tex); } } else { // hide page not visible by this Camera p->show(false); } } // reset state variable mOptions->lightmoved = false; }
//----------------------------------------------------------------------- void PagingLandScapePage::setNeighbors() { PagingLandScapePage* neighbor = 0; // south neighbor = mPageMgr.getPage(mTableX, mTableZ + 1, false); setNeighbor(SOUTH, neighbor); if (neighbor) { neighbor->setNeighbor(NORTH, this); } // north neighbor = mPageMgr.getPage(mTableX, mTableZ - 1, false); setNeighbor(NORTH, neighbor); if (neighbor) { neighbor->setNeighbor(SOUTH, this); } // east neighbor = mPageMgr.getPage(mTableX + 1, mTableZ, false); setNeighbor(EAST, neighbor); if (neighbor) { neighbor->setNeighbor(WEST, this); } // west neighbor = mPageMgr.getPage(mTableX - 1, mTableZ, false); setNeighbor(WEST, neighbor); if (neighbor) { neighbor->setNeighbor(EAST, this); } }
//------------------------------------------------------------------------- PagingLandScapeTile* PagingLandScapePageManager::getTilePage(unsigned int& posx, unsigned int& posz, unsigned int pagex, unsigned int pagez) { const Real tSize = mOptions->TileSize - 1; const Real inv_tSize = 1.0f / tSize; const int tilex = static_cast<int>(posx * inv_tSize); const int tilez = static_cast<int>(posz * inv_tSize); const int pSize = mOptions->PageSize - 1; const int tilesPerPage = static_cast<int>(mOptions->NumTiles - 1); unsigned int x; if (tilex > tilesPerPage) { x = static_cast<unsigned int>(tilesPerPage); } else if (tilex < 0) { x = 0; } else { x = static_cast<unsigned int>(tilex); } unsigned int z; if (tilez > tilesPerPage) { z = static_cast<unsigned int>(tilesPerPage); } else if (tilez < 0) { z = 0; } else { z = static_cast<unsigned int>(tilez); } posx = posx - static_cast<unsigned int>(x * tSize); posz = posz - static_cast<unsigned int>(z * tSize); PagingLandScapePage *p = getPage(pagex, pagez); if (p) return p->getTile(x, z); return 0; }
//----------------------------------------------------------------------- void PagingLandScapePageManager::processUnloadQueues() { // Check for pages that need to be unloaded. // if touched, that means they didn't have been touch by any cameras // for several frames and thus need to be unloaded. // LIST CHECKS for (PagingLandScapePageList::iterator itl = mLoadedPages.begin(); itl != mLoadedPages.end();) { if ((*itl)->unloadUntouched()) { releasePage(*itl); itl = mLoadedPages.erase(itl); } else { ++itl; } } // QUEUES CHECKS // check queues for page that need to be excluded from queues PagingLandScapePage* p = 0; for (PagingLandScapeQueue<PagingLandScapePage>::MsgQueType::iterator itq = mPageLoadQueue.begin(); itq != mPageLoadQueue.end();) { assert(!(*itq)->isLoaded()); assert((*itq)->isInLoadQueue()); if ((*itq)->unloadUntouched()) { p = *itq; // remove from queue p->setInQueue(PagingLandScapePage::QUEUE_NONE); itq = mPageLoadQueue.erase(itq); // remove from active pages //(must be removed from queue first) releasePage(p); } else { ++itq; } } }
//----------------------------------------------------------------------- PagingLandScapePage* PagingLandScapePageManager::getNewPage(unsigned int x, unsigned int z) { PagingLandScapePage* p = 0; // should we resize page pool if (mFreePages.empty()) { const size_t pool_size = mPagePool.size(); const size_t new_pool_size = (pool_size == 0) ? 9 : pool_size * 2; mPagePool.reserve(new_pool_size); mPagePool.resize(new_pool_size); // Create new pages for (size_t i = pool_size; i < new_pool_size; ++i) { p = new PagingLandScapePage(*this); mPagePool[i] = p; mFreePages.push_back(p); } } // Get a pre-allocated new page. p = mFreePages.front(); mFreePages.pop_front(); mActivePages.push_back(p); p->init(x, z); return p; }
//------------------------------------------------------------------------- void PagingLandScapePageManager::setWorldGeometryRenderQueue(uint8 qid) { PagingLandScapePageList::iterator l, lend = mLoadedPages.end(); for (l = mLoadedPages.begin(); l != lend; ++l) { PagingLandScapePage* p = (*l); p->setRenderQueue(qid); } }
//----------------------------------------------------------------------- // Set the current page. Must be called before Update(). void SetPage( const PagingLandScapePage* page ) { page_ = page; if( page_ && page_->isLoaded() ) { page_->getCoordinates( pageX_, pageZ_ ); pageData_ = dataMgr_->getData2D( pageX_, pageZ_, false ); } }
void EmberPagingLandScapeData2D_HeightField::eventTerrainPageLoaded() { S_LOG_VERBOSE("Terrain page at (" << mPageX << ", " << mPageZ << ") got TerrainPageLoaded event"); // notify that terrain data has been loaded PagingLandScapePage* page = mParent->getSceneManager()->getPageManager()->getPage(mPageX, mPageZ, false); if (page) { page->eventData2DLoaded(true); } }
//----------------------------------------------------------------------- void PagingLandScapePageManager::LoadFirstPage(PagingLandScapeCamera* cam) { const Vector3 CamPos = cam->getDerivedPosition(); //gets page indices (if outside Terrain gets nearest page) unsigned int i, j; getPageIndices(CamPos.x, CamPos.z, i, j, true); // update the camera page position // does modify mIniX, mFinX, mIniZ, mFinZ PagingLandScapePage* p = getPage(i, j, false); if (p) { mPageLoadQueue.push(p); p->setInQueue(PagingLandScapePage::QUEUE_LOAD); } }
//----------------------------------------------------------------------- // Returns true if the vertex is included, or false if it is removed // by LOD. Requires local page coordinates. bool GetWorldVertex( int localPageX, int localPageZ, Vector3& vertex ) { UpdateWithLocalPage( localPageX, localPageZ ); bool included = ( renderLevel_.Floor( localPageX ) == localPageX && renderLevel_.Floor( localPageZ ) == localPageZ ); if( page_ && page_->isLoaded() && pageData_ ) { // TODO: Do we really need to include the real data when the vertex // has been removed by lod? Or can we just stuff a dummy result in // here to fill out the array? vertex.y = pageData_->getHeight( localPageX, localPageZ ); page_->getCoordinates( pageX_, pageZ_ ); vertex.x = PageToWorld( pageX_, localPageX, scale_.x, maxUnScaledX_, pageSize_ ); vertex.z = PageToWorld( pageZ_, localPageZ, scale_.z, maxUnScaledZ_, pageSize_ ); } return included; }
//----------------------------------------------------------------------- // Update using page local tile coordinates. void UpdateTile( int tileX, int tileZ ) { PagingLandScapeTile* tile = page_->getTile( tileX, tileZ ); if( tile != tile_ ) { tile_ = tile; bool tileLoaded = tile_ && tile_->isLoaded() && tile_->getRenderable(); renderLevel_.SetRenderLevel( (tileLoaded) ? tile_->getRenderable()->getRenderLevel() : 0 ); } }
//----------------------------------------------------------------------- void PagingLandScapePageManager::queuePageNeighbors() { // Queue the rest // Loading must be done one by one to avoid FPS drop, so they are queued. // We must load the next visible LandScape pages, // check the LandScape boundaries for (unsigned int i = mCurrentcam->mPreIniX; i <= mCurrentcam->mPreFinX; i++) { for (unsigned int j = mCurrentcam->mPreIniZ; j <= mCurrentcam->mPreFinZ; j++) { // pages in this zone around camera, must be at // least preloading. that means they can be // loaded too. PagingLandScapePage* p = getPage(i, j, true); if (!(p->isInLoadQueue() || p->isLoaded())) { if ((j >= mCurrentcam->mIniZ) && (j <= mCurrentcam->mFinZ) && (i >= mCurrentcam->mIniX) && (i <= mCurrentcam->mFinX)) { // pages in this tighter zone // around camera must be Loading // or Loaded as they may be // below camera very soon. removeFromQueues(p); mPageLoadQueue.push(p); p->setInQueue(PagingLandScapePage::QUEUE_LOAD); } else { // must be at least preloading p->preloadInBackground(); } } p->touch(); } } }
//----------------------------------------------------------------------- void PagingLandScapePageManager::processLoadQueues() { SceneManager::CameraIterator camIt = mSceneManager->getCameraIterator(); while (camIt.hasMoreElements()) { const Camera* currentCamera = camIt.getNext(); const Vector3& cameraPos = currentCamera->getDerivedPosition(); if (!cameraPos.isNaN()) { const Vector3 pos(cameraPos.x, 127.0f, cameraPos.z); if (!mPageLoadQueue.empty()) { // We Load nearest page in non-empty queue PagingLandScapePage* p = mPageLoadQueue.find_nearest(pos); if (p) { assert(p && !p->isLoaded ()); assert(p->isInLoadQueue()); p->load(); } // rest of processing after eventPageLoaded received } } } }
//----------------------------------------------------------------------- void PagingLandScapePageManager::updatePaging(PagingLandScapeCamera* cam) { mCurrentcam = cam; // Here we have to look if we have to load, unload any of the LandScape Pages // Fix from Praetor, so the camera used gives you "world-relative" coordinates // make sure in the bounding box of LandScape const Vector3 pos(cam->getDerivedPosition().x, 127.0f, cam->getDerivedPosition().z); //updateStats(pos); bool need_touch = false; if (mWidth == 0 && mHeight == 0) { //just return if we haven't got any world yet return; } if (cam->mLastCameraPos != pos && (mOptions->cameraThreshold < fabs(cam->mLastCameraPos.x - pos.x) || mOptions->cameraThreshold < fabs(cam->mLastCameraPos.z - pos.z))) { // Update only if the camera was moved PagingLandScapePage * const oldPage = getPage(cam->mCurrentCameraPageX, cam->mCurrentCameraPageZ, false); PagingLandScapeTile * const oldTile = (oldPage && oldPage->isLoaded() ? oldPage->getTile(cam->mCurrentCameraTileX, cam->mCurrentCameraTileZ) : 0); unsigned int i, j; //gets page indices (if outside Terrain gets nearest page) getPageIndices(pos.x, pos.z, i, j, true); PagingLandScapePage* p = getPage(i, j); if (!p) { return; } // mPageLoadQueue.push(p); // p->setInQueue(PagingLandScapePage::QUEUE_LOAD); // update current Cam Page info if (oldPage != p) { // update the camera info : cam->updatePaging(i, j); // need to inform neighbors pages need_touch = true; } // Update current Cam Tile info. if (p->isPreLoaded()) { PagingLandScapeTile * const t = getTile(pos.x, pos.z, i, j, true); if (t && t != oldTile) { if (mOptions->MaxLodUnderCam) { // reset previous tile at normal LOD mechanism. if (oldTile && oldTile->isLoaded()) { assert(oldTile->getRenderable()); oldTile->getRenderable()->setMaxLod(false); } // set current tile at max LOD whatever complexity it is. if (t->isLoaded()) { assert(t->getRenderable()); t->getRenderable()->setMaxLod(true); } } PagingLandScapeTileInfo * const CurrentTileInfo = t->getInfo(); cam->mCurrentCameraTileX = CurrentTileInfo->mTileX; cam->mCurrentCameraTileZ = CurrentTileInfo->mTileZ; } } // Update the last camera position if (mOptions->cameraThreshold < fabs(cam->mLastCameraPos.x - pos.x)) cam->mLastCameraPos.x = pos.x; if (mOptions->cameraThreshold < fabs(cam->mLastCameraPos.z - pos.z)) cam->mLastCameraPos.z = pos.z; } if (need_touch) queuePageNeighbors(); updateLoadedPages(); mRenderablesMgr->executeRenderableLoading(pos); // This Frame has seen a Camera. mOnFrame = true; }