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