void TileNode::load(osg::NodeVisitor& nv) { // Access the context: EngineContext* context = static_cast<EngineContext*>( nv.getUserData() ); // Create a new load request on demand: if ( !_loadRequest.valid() ) { Threading::ScopedMutexLock lock(_mutex); if ( !_loadRequest.valid() ) { _loadRequest = new LoadTileData( this, context ); _loadRequest->setName( _key.str() ); _loadRequest->setTileKey( _key ); } } // Prioritize by LOD. (negated because lower order gets priority) float priority = - (float)getTileKey().getLOD(); if ( context->getOptions().highResolutionFirst() == true ) priority = -priority; // then sort by distance within each LOD. float distance = nv.getDistanceToViewPoint( getBound().center(), true ); priority = 10.0f*priority - log10(distance); // testing intermediate loading idea... //if ( getTileKey().getLOD() == 5 ) // priority += 100.0f; // Submit to the loader. context->getLoader()->load( _loadRequest.get(), priority, nv ); }
bool TileNode::shouldSubDivide(TerrainCuller* culler, const SelectionInfo& selectionInfo) { unsigned currLOD = _key.getLOD(); EngineContext* context = culler->getEngineContext(); if (context->getOptions().rangeMode() == osg::LOD::PIXEL_SIZE_ON_SCREEN) { float pixelSize = -1.0; if (context->getEngine()->getComputeRangeCallback()) { pixelSize = (*context->getEngine()->getComputeRangeCallback())(this, *culler->_cv); } if (pixelSize <= 0.0) { pixelSize = culler->clampedPixelSize(getBound()); } return (pixelSize > context->getOptions().tilePixelSize().get() * 4); } else { float range = (float)selectionInfo.visParameters(currLOD+1)._visibilityRange2; if (currLOD < selectionInfo.getNumLODs() && currLOD != selectionInfo.getNumLODs()-1) { return _surface->anyChildBoxIntersectsSphere( culler->getViewPointLocal(), range, culler->getLODScale()); } } return false; }
void TileNode::load(osg::NodeVisitor& nv) { // Access the context: EngineContext* context = VisitorData::fetch<EngineContext>(nv, ENGINE_CONTEXT_TAG); // Create a new load request on demand: if ( !_loadRequest.valid() ) { Threading::ScopedMutexLock lock(_mutex); if ( !_loadRequest.valid() ) { _loadRequest = new LoadTileData( this, context ); _loadRequest->setName( _key.str() ); _loadRequest->setTileKey( _key ); } } // Construct the load PRIORITY: 0=lowest, 1=highest. const SelectionInfo& si = context->getSelectionInfo(); int lod = getTileKey().getLOD(); int numLods = si.numLods(); // LOD priority is in the range [0..numLods] float lodPriority = (float)lod; if ( context->getOptions().highResolutionFirst() == false ) lodPriority = (float)(numLods - lod); float distance = nv.getDistanceToViewPoint(getBound().center(), true); // dist priority uis in the range [0..1] float distPriority = 1.0 - distance/si.visParameters(0)._visibilityRange; // add thenm together, and you get tiles sorted first by lodPriority (because of // the biggest range), and second by distance. float priority = lodPriority + distPriority; // normalize the composite priority to [0..1]. priority /= (float)(numLods+1); // Submit to the loader. context->getLoader()->load( _loadRequest.get(), priority, nv ); }
StaticDrawable::StaticDrawable(EngineContext& context, MvId texId, sf::IntRect texRectangle) { sf::Texture& texture = context.getTextureManager().getTexture(texId); mSprite.setTexture(texture); mSprite.setTextureRect(texRectangle); sf::FloatRect bounds = mSprite.getLocalBounds(); mSprite.setOrigin(std::floor(bounds.width / 2.f), std::floor(bounds.height / 2.f)); }
void TileNode::expireChildren(osg::NodeVisitor& nv) { OE_DEBUG << LC << "Expiring children of " << getTileKey().str() << "\n"; EngineContext* context = static_cast<EngineContext*>( nv.getUserData() ); if ( !_expireRequest.valid() ) { Threading::ScopedMutexLock lock(_mutex); if ( !_expireRequest.valid() ) { _expireRequest = new ExpireTiles(this, context); _expireRequest->setName( getTileKey().str() + " expire" ); _expireRequest->setTileKey( _key ); } } // Low priority for expiry requests. const float lowPriority = -100.0f; context->getLoader()->load( _expireRequest.get(), lowPriority, nv ); }
void TileNode::cull(osg::NodeVisitor& nv) { if ( nv.getFrameStamp() ) { _lastTraversalFrame.exchange( nv.getFrameStamp()->getFrameNumber() ); } unsigned currLOD = getTileKey().getLOD(); osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>( &nv ); EngineContext* context = static_cast<EngineContext*>( nv.getUserData() ); const SelectionInfo& selectionInfo = context->getSelectionInfo(); if ( context->progress() ) context->progress()->stats()["TileNode::cull"]++; // determine whether we can and should subdivide to a higher resolution: bool subdivide = shouldSubDivide(nv, selectionInfo, cv->getLODScale()); // whether it is OK to create child TileNodes is necessary. bool canCreateChildren = subdivide; // whether it is OK to load data if necessary. bool canLoadData = true; if ( _dirty && context->getOptions().progressive() == true ) { // Don't create children in progressive mode until content is in place canCreateChildren = false; } else { // If this is an inherit-viewpoint camera, we don't need it to invoke subdivision // because we want only the tiles loaded by the true viewpoint. const osg::Camera* cam = cv->getCurrentCamera(); if ( cam && cam->getReferenceFrame() == osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ) { canCreateChildren = false; canLoadData = false; } } optional<bool> surfaceVisible; // If *any* of the children are visible, subdivide. if (subdivide) { // We are in range of the child nodes. Either draw them or load them. // If the children don't exist, create them and inherit the parent's data. if ( getNumChildren() == 0 && canCreateChildren ) { Threading::ScopedMutexLock exclusive(_mutex); if ( getNumChildren() == 0 ) { createChildren( context ); } } // If all are ready, traverse them now. if ( getNumChildren() == 4 ) { for(int i=0; i<4; ++i) { _children[i]->accept( nv ); } } // If we don't traverse the children, traverse this node's payload. else if ( _surface.valid() ) { surfaceVisible = acceptSurface( cv, context ); } } // If children are outside camera range, draw the payload and expire the children. else if ( _surface.valid() ) { surfaceVisible = acceptSurface( cv, context ); if ( getNumChildren() >= 4 && context->maxLiveTilesExceeded() ) { if (getSubTile(0)->isDormant( nv ) && getSubTile(1)->isDormant( nv ) && getSubTile(2)->isDormant( nv ) && getSubTile(3)->isDormant( nv )) { expireChildren( nv ); } } } // Traverse land cover data at this LOD. int zoneIndex = context->_landCoverData->_currentZoneIndex; if ( zoneIndex < (int)context->_landCoverData->_zones.size() ) { unsigned clearMask = cv->getCurrentCamera()->getClearMask(); bool isDepthCamera = ((clearMask & GL_COLOR_BUFFER_BIT) == 0u) && ((clearMask & GL_DEPTH_BUFFER_BIT) != 0u); bool isShadowCamera = osgEarth::Shadowing::isShadowCamera(cv->getCurrentCamera()); // only consider land cover if we are capturing color OR shadow. if ( isShadowCamera || !isDepthCamera ) { const LandCoverZone& zone = context->_landCoverData->_zones.at(zoneIndex); for(int i=0; i<zone._bins.size(); ++i) { bool pushedPayloadSS = false; const LandCoverBin& bin = zone._bins.at(i); if ( bin._lod == _key.getLOD() && (!isShadowCamera || bin._castShadows) ) { if ( !pushedPayloadSS ) { cv->pushStateSet( _payloadStateSet.get() ); pushedPayloadSS = true; } cv->pushStateSet( bin._stateSet.get() ); // hopefully groups together for rendering. _landCover->accept( nv ); cv->popStateSet(); } if ( pushedPayloadSS ) { cv->popStateSet(); } } } } // If this tile is marked dirty, try loading data. if ( _dirty && canLoadData ) { // Only load data if the surface would be visible to the camera if ( !surfaceVisible.isSet() ) { surfaceVisible = _surface->isVisible(cv); } if ( surfaceVisible == true ) { load( nv ); } else { OE_DEBUG << LC << "load skipped for " << _key.str() << std::endl; } } }
bool TileNode::cull(TerrainCuller* culler) { EngineContext* context = culler->getEngineContext(); // Horizon check the surface first: if (!_surface->isVisibleFrom(culler->getViewPointLocal())) { return false; } // determine whether we can and should subdivide to a higher resolution: bool childrenInRange = shouldSubDivide(culler, context->getSelectionInfo()); // whether it is OK to create child TileNodes is necessary. bool canCreateChildren = childrenInRange; // whether it is OK to load data if necessary. bool canLoadData = true; // whether to accept the current surface node and not the children. bool canAcceptSurface = false; // Don't create children in progressive mode until content is in place if ( _dirty && context->getOptions().progressive() == true ) { canCreateChildren = false; } // If this is an inherit-viewpoint camera, we don't need it to invoke subdivision // because we want only the tiles loaded by the true viewpoint. const osg::Camera* cam = culler->getCamera(); if ( cam && cam->getReferenceFrame() == osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ) { canCreateChildren = false; canLoadData = false; } if (childrenInRange) { // We are in range of the child nodes. Either draw them or load them. // If the children don't exist, create them and inherit the parent's data. if ( !_childrenReady && canCreateChildren ) { _mutex.lock(); if ( !_childrenReady ) { OE_START_TIMER(createChildren); createChildren( context ); REPORT("TileNode::createChildren", createChildren); _childrenReady = true; // This means that you cannot start loading data immediately; must wait a frame. canLoadData = false; } _mutex.unlock(); } // If all are ready, traverse them now. if ( _childrenReady ) { for(int i=0; i<4; ++i) { getSubTile(i)->accept(*culler); } } // If we don't traverse the children, traverse this node's payload. else { canAcceptSurface = true; } } // If children are outside camera range, draw the payload and expire the children. else { canAcceptSurface = true; } // accept this surface if necessary. if ( canAcceptSurface ) { _surface->accept( *culler ); _lastAcceptSurfaceFrame.exchange( culler->getFrameStamp()->getFrameNumber() ); } // If this tile is marked dirty, try loading data. if ( _dirty && canLoadData ) { load( culler ); } return true; }
GameFinishedState::GameFinishedState(StateStack &stack, EngineContext &context) : GameState(stack, context) , mWindow(*context.getWindow()) { // NOOP }
void RexTerrainEngineNode::dirtyTerrain() { //TODO: scrub the geometry pool? // clear the loader: _loader->clear(); if ( _terrain ) { this->removeChild( _terrain ); } // New terrain _terrain = new osg::Group(); this->addChild( _terrain ); // are we LOD blending? bool setupParentData = _terrainOptions.morphImagery() == true || // gw: redundant? this->parentTexturesRequired(); // reserve GPU unit for the main color texture: if ( _renderBindings.empty() ) { setupRenderBindings(); } // Calculate the LOD morphing parameters: unsigned maxLOD = _terrainOptions.maxLOD().getOrUse(DEFAULT_MAX_LOD); _selectionInfo.initialize( 0u, // always zero, not the terrain options firstLOD std::min( _terrainOptions.maxLOD().get(), maxLOD ), _terrainOptions.tileSize().get(), _update_mapf->getMapInfo().getProfile(), _terrainOptions.minTileRangeFactor().get() ); // clear out the tile registry: if ( _liveTiles.valid() ) { _liveTiles->releaseAll(_releaser.get()); } // Factory to create the root keys: EngineContext* context = getEngineContext(); // Build the first level of the terrain. // Collect the tile keys comprising the root tiles of the terrain. std::vector<TileKey> keys; _update_mapf->getProfile()->getAllKeysAtLOD( *_terrainOptions.firstLOD(), keys ); // create a root node for each root tile key. OE_INFO << LC << "Creating " << keys.size() << " root keys.." << std::endl; unsigned child = 0; for( unsigned i=0; i<keys.size(); ++i ) { TileNode* tileNode = new TileNode(); if (context->getOptions().minExpiryFrames().isSet()) { tileNode->setMinimumExpirationFrames( *context->getOptions().minExpiryFrames() ); } if (context->getOptions().minExpiryTime().isSet()) { tileNode->setMinimumExpirationTime( *context->getOptions().minExpiryTime() ); } // Next, build the surface geometry for the node. tileNode->create( keys[i], 0L, context ); // Add it to the scene graph _terrain->addChild( tileNode ); // And load the tile's data synchronously (only for root tiles). tileNode->loadSync( context ); } updateState(); // Call the base class TerrainEngineNode::dirtyTerrain(); }
void RexTerrainEngineNode::dirtyTerrain() { //TODO: scrub the geometry pool? // clear the loader: _loader->clear(); if ( _terrain ) { this->removeChild( _terrain ); } // New terrain _terrain = new osg::Group(); this->addChild( _terrain ); // are we LOD blending? bool setupParentData = _terrainOptions.morphImagery() == true || // gw: redundant? this->parentTexturesRequired(); // reserve GPU unit for the main color texture: if ( _renderBindings.empty() ) { setupRenderBindings(); } // recalculate the LOD morphing parameters: //destroySelectionInfo(); //buildSelectionInfo(); // clear out the tile registry: if ( _liveTiles.valid() ) { _liveTiles->moveAll( _deadTiles.get() ); } // Factory to create the root keys: EngineContext* context = getEngineContext(); // Build the first level of the terrain. // Collect the tile keys comprising the root tiles of the terrain. std::vector<TileKey> keys; _update_mapf->getProfile()->getAllKeysAtLOD( *_terrainOptions.firstLOD(), keys ); // create a root node for each root tile key. OE_INFO << LC << "Creating " << keys.size() << " root keys.." << std::endl; unsigned child = 0; for( unsigned i=0; i<keys.size(); ++i ) { TileNode* tileNode = new TileNode(); if (context->getOptions().minExpiryFrames().isSet()) { tileNode->setMinimumExpiryFrames( *context->getOptions().minExpiryFrames() ); } if (context->getOptions().minExpiryTime().isSet()) { tileNode->setMinimumExpiryTime( *context->getOptions().minExpiryTime() ); } // Next, build the surface geometry for the node. tileNode->create( keys[i], context ); _terrain->addChild( tileNode ); } updateState(); // Call the base class TerrainEngineNode::dirtyTerrain(); }
void TileNode::cull(osg::NodeVisitor& nv) { osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>( &nv ); EngineContext* context = static_cast<EngineContext*>( nv.getUserData() ); const SelectionInfo& selectionInfo = context->getSelectionInfo(); // record the number of drawables before culling this node: unsigned before = RenderBinUtils::getTotalNumRenderLeaves( cv->getRenderStage() ); if ( context->progress() ) context->progress()->stats()["TileNode::cull"]++; // determine whether we can and should subdivide to a higher resolution: bool subdivide = shouldSubDivide(nv, selectionInfo, cv->getLODScale()); // whether it is OK to create child TileNodes is necessary. bool canCreateChildren = subdivide; // whether it is OK to load data if necessary. bool canLoadData = true; if ( _dirty && context->getOptions().progressive() == true ) { // Don't create children in progressive mode until content is in place canCreateChildren = false; } // If this is an inherit-viewpoint camera, we don't need it to invoke subdivision // because we want only the tiles loaded by the true viewpoint. const osg::Camera* cam = cv->getCurrentCamera(); if ( cam && cam->getReferenceFrame() == osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ) { canCreateChildren = false; canLoadData = false; } optional<bool> surfaceVisible( false ); if (subdivide) { // We are in range of the child nodes. Either draw them or load them. // If the children don't exist, create them and inherit the parent's data. if ( getNumChildren() == 0 && canCreateChildren ) { Threading::ScopedMutexLock exclusive(_mutex); if ( getNumChildren() == 0 ) { createChildren( context ); } } // If all are ready, traverse them now. if ( getNumChildren() == 4 ) { for(int i=0; i<4; ++i) { // pre-check each child for simple bounding sphere culling, and if the check // fails, unload it's children if them exist. This lets us unload dormant // tiles from memory as we go. If those children are visible from another // camera, no worries, the unload attempt will fail gracefully. if (!cv->isCulled(*_children[i].get())) { _children[i]->accept( nv ); } else { context->getUnloader()->unloadChildren(getSubTile(i)->getTileKey()); } } } // If we don't traverse the children, traverse this node's payload. else if ( _surface.valid() ) { surfaceVisible = acceptSurface( cv, context ); } } // If children are outside camera range, draw the payload and expire the children. else if ( _surface.valid() ) { surfaceVisible = acceptSurface( cv, context ); // if children exists, and are not in the process of loading, unload them now. if ( !_dirty && _children.size() > 0 ) { context->getUnloader()->unloadChildren( this->getTileKey() ); } } // See whether we actually added any drawables. unsigned after = RenderBinUtils::getTotalNumRenderLeaves( cv->getRenderStage() ); bool addedDrawables = (after > before); // Only continue if we accepted at least one surface drawable. if ( addedDrawables ) { // update the timestamp so this tile doesn't become dormant. _lastTraversalFrame.exchange( nv.getFrameStamp()->getFrameNumber() ); } context->invokeTilePatchCallbacks( cv, getTileKey(), _payloadStateSet.get(), _patch.get() ); // If this tile is marked dirty, try loading data. if ( addedDrawables && _dirty && canLoadData ) { // Only load data if the surface would be visible to the camera if ( !surfaceVisible.isSet() ) { surfaceVisible = _surface->isVisible(cv); } if ( surfaceVisible == true ) { load( nv ); } else { OE_DEBUG << LC << "load skipped for " << _key.str() << std::endl; } } }
void TileNode::cull(osg::NodeVisitor& nv) { if ( nv.getFrameStamp() ) { _lastTraversalFrame.exchange( nv.getFrameStamp()->getFrameNumber() ); } unsigned currLOD = getTileKey().getLOD(); #if OSGEARTH_REX_TILE_NODE_DEBUG_TRAVERSAL if (currLOD==0) { OE_INFO << LC <<"Traversing: "<<"\n"; } #endif osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>( &nv ); EngineContext* context = static_cast<EngineContext*>( nv.getUserData() ); const SelectionInfo& selectionInfo = context->getSelectionInfo(); // determine whether we can and should subdivide to a higher resolution: bool subdivide = shouldSubDivide(nv, selectionInfo, cv->getLODScale()); // If this is an inherit-viewpoint camera, we don't need it to invoke subdivision // because we want only the tiles loaded by the true viewpoint. bool canCreateChildren = subdivide; const osg::Camera* cam = cv->getCurrentCamera(); if ( cam && cam->getReferenceFrame() == osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ) { canCreateChildren = false; } // If *any* of the children are visible, subdivide. if (subdivide) { // We are in range of the child nodes. Either draw them or load them. // If the children don't exist, create them and inherit the parent's data. if ( getNumChildren() == 0 && canCreateChildren ) { Threading::ScopedMutexLock exclusive(_mutex); if ( getNumChildren() == 0 ) { createChildren( context ); } } // All 4 children must be ready before we can traverse any of them: unsigned numChildrenReady = 0; if ( getNumChildren() == 4 ) { for(unsigned i = 0; i < 4; ++i) { if ( getSubTile(i)->isReadyToTraverse() ) { ++numChildrenReady; } } } // If all are ready, traverse them now. if ( numChildrenReady == 4 ) { // TODO: // When we do this, we need to quite sure that all 4 children will be accepted into // the draw set. Perhaps isReadyToTraverse() needs to check that. _children[0]->accept( nv ); _children[1]->accept( nv ); _children[2]->accept( nv ); _children[3]->accept( nv ); } // If we don't traverse the children, traverse this node's payload. else if ( _surface.valid() ) { cullSurface( cv ); } } // If children are outside camera range, draw the payload and expire the children. else if ( _surface.valid() ) { cullSurface( cv ); if ( getNumChildren() >= 4 && context->maxLiveTilesExceeded() ) { if (getSubTile(0)->isDormant( nv ) && getSubTile(1)->isDormant( nv ) && getSubTile(2)->isDormant( nv ) && getSubTile(3)->isDormant( nv )) { expireChildren( nv ); } } } // Traverse land cover bins at this LOD. for(int i=0; i<context->landCoverBins()->size(); ++i) { bool first = true; const LandCoverBin& bin = context->landCoverBins()->at(i); if ( bin._lod == getTileKey().getLOD() ) { if ( first ) { cv->pushStateSet( _payloadStateSet.get() ); } cv->pushStateSet( bin._stateSet.get() ); _landCover->accept( nv ); cv->popStateSet(); if ( first ) { cv->popStateSet(); first = false; } } } // If this tile is marked dirty, try loading data. if ( _dirty ) { load( nv ); } }
bool TileNode::cull(osgUtil::CullVisitor* cv) { EngineContext* context = VisitorData::fetch<EngineContext>(*cv, ENGINE_CONTEXT_TAG); const SelectionInfo& selectionInfo = context->getSelectionInfo(); // Horizon check the surface first: if ( !_surface->isVisible(cv) ) { return false; } // determine whether we can and should subdivide to a higher resolution: bool childrenInRange = shouldSubDivide(cv, selectionInfo); // whether it is OK to create child TileNodes is necessary. bool canCreateChildren = childrenInRange; // whether it is OK to load data if necessary. bool canLoadData = true; // whether to accept the current surface node and not the children. bool canAcceptSurface = false; // Don't create children in progressive mode until content is in place if ( _dirty && context->getOptions().progressive() == true ) { canCreateChildren = false; } // If this is an inherit-viewpoint camera, we don't need it to invoke subdivision // because we want only the tiles loaded by the true viewpoint. const osg::Camera* cam = cv->getCurrentCamera(); if ( cam && cam->getReferenceFrame() == osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ) { canCreateChildren = false; canLoadData = false; } if (childrenInRange) { // We are in range of the child nodes. Either draw them or load them. // If the children don't exist, create them and inherit the parent's data. if ( !_childrenReady && canCreateChildren ) { _mutex.lock(); if ( !_childrenReady ) { OE_START_TIMER(createChildren); createChildren( context ); REPORT("TileNode::createChildren", createChildren); _childrenReady = true; // This means that you cannot start loading data immediately; must wait a frame. canLoadData = false; } _mutex.unlock(); } // If all are ready, traverse them now. if ( _childrenReady ) { for(int i=0; i<4; ++i) { getSubTile(i)->accept_cull(cv); } // if we traversed all children, but they all return "not visible", // that means it's a horizon-culled tile anyway and we don't need // to add any drawables. } // If we don't traverse the children, traverse this node's payload. else { canAcceptSurface = true; } } // If children are outside camera range, draw the payload and expire the children. else { canAcceptSurface = true; } // accept this surface if necessary. if ( canAcceptSurface ) { acceptSurface( cv, context ); _lastAcceptSurfaceFrame.exchange( cv->getFrameStamp()->getFrameNumber() ); } // Run any patch callbacks. context->invokeTilePatchCallbacks( cv, getTileKey(), _payloadStateSet.get(), _patch.get() ); // If this tile is marked dirty, try loading data. if ( _dirty && canLoadData ) { load( *cv ); } return true; }