Example #1
0
void TileStack::drawAll(GWindow& window) const {
    TileNode* p = front;
    while (p!= NULL) {
        p->draw(window);
        p = p->next;
    }
}
Example #2
0
void
TilePagedLOD::traverse(osg::NodeVisitor& nv)
{
    // Only traverse the TileNode if our neighbors (the other members of
    // our group of four) are ready as well.
    if ( _children.size() > 0 )
    {
        _children[0]->setNodeMask( _familyReady ? ~0 : 0 );

        // find our tile node:
        TileNode* tilenode = dynamic_cast<TileGroup*>(_children[0].get()) ? 
            static_cast<TileGroup*>(_children[0].get())->getTileNode() :
            static_cast<TileNode*>(_children[0].get());

        // Check whether the TileNode is marked dirty. If so, install a new pager request 
        // to reload and replace the TileNode.
        if (nv.getVisitorType() == nv.CULL_VISITOR &&
            this->getNumFileNames() < 2 && 
            tilenode->isOutOfDate() )
        {
            // lock keeps multiple CullVisitors from doing the same thing
            Threading::ScopedMutexLock exclusive( _updateMutex );

            if ( this->getNumFileNames() < 2 ) // double-check pattern
            {
                //OE_WARN << LC << "Queuing request for replacement: " << _container->getTileNode()->getKey().str() << std::endl;
                this->setFileName( 1, Stringify() << _prefix << ".osgearth_engine_mp_standalone_tile" );
                this->setRange( 1, 0, FLT_MAX );
            }
        }
    }

    osg::PagedLOD::traverse( nv );
}
osg::Node*
SingleKeyNodeFactory::createTile(TileModel* model, bool setupChildrenIfNecessary)
{
    // compile the model into a node:
    TileNode* tileNode = _modelCompiler->compile( model, _frame );

    // see if this tile might have children.
    bool prepareForChildren =
        setupChildrenIfNecessary &&
        model->_tileKey.getLOD() < *_options.maxLOD();

    osg::Node* result = 0L;

    if ( prepareForChildren )
    {
        //Compute the min range based on the 2D size of the tile
        osg::BoundingSphere bs = tileNode->getBound();
        GeoExtent extent = model->_tileKey.getExtent();
        GeoPoint lowerLeft(extent.getSRS(), extent.xMin(), extent.yMin(), 0.0, ALTMODE_ABSOLUTE);
        GeoPoint upperRight(extent.getSRS(), extent.xMax(), extent.yMax(), 0.0, ALTMODE_ABSOLUTE);
        osg::Vec3d ll, ur;
        lowerLeft.toWorld( ll );
        upperRight.toWorld( ur );
        double radius = (ur - ll).length() / 2.0;
        float minRange = (float)(radius * _options.minTileRangeFactor().value());

        TilePagedLOD* plod = new TilePagedLOD( _engineUID, _liveTiles, _deadTiles );
        plod->setCenter  ( bs.center() );
        plod->addChild   ( tileNode );
        plod->setRange   ( 0, minRange, FLT_MAX );
        plod->setFileName( 1, Stringify() << tileNode->getKey().str() << "." << _engineUID << ".osgearth_engine_mp_tile" );
        plod->setRange   ( 1, 0, minRange );

#if USE_FILELOCATIONCALLBACK
        osgDB::Options* options = Registry::instance()->cloneOrCreateOptions();
        options->setFileLocationCallback( new FileLocationCallback() );
        plod->setDatabaseOptions( options );
#endif
        
        result = plod;

        // this one rejects back-facing tiles:
        if ( _frame.getMapInfo().isGeocentric() && _options.clusterCulling() == true )
        {
            osg::HeightField* hf =
                model->_elevationData.getHeightField();

            result->addCullCallback( HeightFieldUtils::createClusterCullingCallback(
                hf,
                tileNode->getKey().getProfile()->getSRS()->getEllipsoid(),
                *_options.verticalScale() ) );
        }
    }
    else
    {
        result = tileNode;
    }

    return result;
}
Example #4
0
void
TileNode::createChildren(EngineContext* context)
{
    // NOTE: Ensure that _mutex is locked before calling this function!
    //OE_WARN << "Creating children for " << _key.str() << std::endl;

    // Create the four child nodes.
    for(unsigned quadrant=0; quadrant<4; ++quadrant)
    {
        TileNode* node = new TileNode();
        if (context->getOptions().minExpiryFrames().isSet())
        {
            node->setMinimumExpirationFrames( *context->getOptions().minExpiryFrames() );
        }
        if (context->getOptions().minExpiryTime().isSet())
        {         
            node->setMinimumExpirationTime( *context->getOptions().minExpiryTime() );
        }

        // Build the surface geometry:
        node->create( getKey().createChildKey(quadrant), this, context );

        // Add to the scene graph.
        addChild( node );
    }
}
Example #5
0
void
TileNode::createChildren(EngineContext* context)
{
    // NOTE: Ensure that _mutex is locked before calling this fucntion!

    // Create the four child nodes.
    for(unsigned quadrant=0; quadrant<4; ++quadrant)
    {
        TileNode* node = new TileNode();
        if (context->getOptions().minExpiryFrames().isSet())
        {
            node->setMinimumExpiryFrames( *context->getOptions().minExpiryFrames() );
        }
        if (context->getOptions().minExpiryTime().isSet())
        {         
            node->setMinimumExpiryTime( *context->getOptions().minExpiryTime() );
        }

        // Build the surface geometry:
        node->create( getTileKey().createChildKey(quadrant), context );

        // Add to the scene graph.
        addChild( node );

        // Inherit the samplers with new scale/bias information.
        node->inheritState( context );
    }
}
Example #6
0
void TileNode::loadChildren()
{
    _mutex.lock();

    if ( !_childrenReady )
    {        
        // Create the children
        createChildren( _context.get() );        
        _childrenReady = true;        
        int numChildren = getNumChildren();
        if ( numChildren > 0 )
        {
            for(int i=0; i<numChildren; ++i)
            {
                TileNode* child = getSubTile(i);
                if (child)
                {
                    // Load the children's data.
                    child->loadSync();
                }
            }
        }
    }
    _mutex.unlock();    
}
// The osgDB::DatabasePager will call this method when merging a new child
// into the scene graph.
bool
TilePagedLOD::addChild(osg::Node* node)
{
    if ( node )
    {
        // if we see an invalid tile marker, disable the paged lod slot.
        if ( dynamic_cast<InvalidTileNode*>(node) )
        {
            this->setFileName( 1, "" );
            this->setRange( 1, 0, 0 );
            this->setRange( 0, 0.0f, FLT_MAX );
            return true;
        }

        // If it's a TileNode, this is the simple first addition of the 
        // static TileNode child (not from the pager).
        TileNode* tilenode = dynamic_cast<TileNode*>( node );
        if ( tilenode && _live.get() )
        {
            _live->add( tilenode );

            // Listen for out east and south neighbors.
            const TileKey& key = tilenode->getKey();
            _live->listenFor( key.createNeighborKey(1, 0), tilenode );
            _live->listenFor( key.createNeighborKey(0, 1), tilenode );
        }

        return osg::PagedLOD::addChild( node );
    }

    return false;
}
osg::Node*
SerialKeyNodeFactory::createTile(TileModel* model,
                                 bool       tileHasRealData)
{
    // compile the model into a node:
    TileNode* tileNode = _modelCompiler->compile( model );

    // see if this tile might have children.
    bool prepareForChildren =
        (tileHasRealData || (_options.minLOD().isSet() && model->_tileKey.getLOD() < *_options.minLOD())) &&
        model->_tileKey.getLOD() < *_options.maxLOD();

    osg::Node* result = 0L;

    if ( prepareForChildren )
    {
        //Compute the min range based on the 2D size of the tile
        osg::BoundingSphere bs = tileNode->getBound();
        GeoExtent extent = model->_tileKey.getExtent();
        GeoPoint lowerLeft(extent.getSRS(), extent.xMin(), extent.yMin(), 0.0, ALTMODE_ABSOLUTE);
        GeoPoint upperRight(extent.getSRS(), extent.xMax(), extent.yMax(), 0.0, ALTMODE_ABSOLUTE);
        osg::Vec3d ll, ur;
        lowerLeft.toWorld( ll );
        upperRight.toWorld( ur );
        double radius = (ur - ll).length() / 2.0;
        float minRange = (float)(radius * _options.minTileRangeFactor().value());

        osgDB::Options* dbOptions = Registry::instance()->cloneOrCreateOptions();

        TileGroup* plod = new TileGroup(tileNode, _engineUID, _liveTiles.get(), _deadTiles.get(), dbOptions);
        plod->setSubtileRange( minRange );


#if USE_FILELOCATIONCALLBACK
        dbOptions->setFileLocationCallback( new FileLocationCallback() );
#endif
        
        result = plod;
    }
    else
    {
        result = tileNode;
    }

    // this one rejects back-facing tiles:
    if ( _mapInfo.isGeocentric() && _options.clusterCulling() == true )
    {
        osg::HeightField* hf =
            model->_elevationData.getHeightField();

        result->addCullCallback( HeightFieldUtils::createClusterCullingCallback(
            hf,
            tileNode->getKey().getProfile()->getSRS()->getEllipsoid(),
            *_options.verticalScale() ) );
    }

    return result;
}
void PathGenerator::addToOpenNode(int x, int y, adjType adjtype,
                                  TileNode* parent) {
    if (x < 0 || y < 0) {
        return;
    }
    if (!canPass(x, y)) {
        return;
    }
    TileNode* node = _nodes[x][y];
    if (inPassedNodes(node)) {
        return;
    } else if (!inOpenNodes(node)) {
        _opened_nodes.push_back(node);
        int incf;
        if (adjtype == Straight)
            incf = 10;
        else
            incf = 14;
        
        node->setG(parent->getG() + incf);
        node->setH(descarteDistance(Point(node->getX(), node->getY()), _end) * 10);
        node->setF(node->getG() + node->getH());
        node->setParent(parent);
    }
}
Example #10
0
std::vector<Point>* PathGenerator::generatePath(Point start, Point end) {
    this->resetTileNodes();
    _start = start;
    _end = end;
    vector<Point>* path = new vector<Point>();
    TileNode* startNode = _nodes[int(start.x)][int(start.y)];
    startNode->setParent(NULL);
    _opened_nodes.push_back(startNode);
    TileNode* pathNode = NULL;
    while (true) {
        pathNode = getMinFNode();
        addAdjacentOpenNodes(pathNode);
        _passed_nodes.push_back(pathNode);
        deletePassedNode(pathNode);
        if (pathNode->getX() == int(end.x) && pathNode->getY() == int(end.y)) {
            break;
        }
    }
    while (pathNode) {
        path->push_back(convertCoordinate2Pixel(pathNode->getX(), pathNode->getY(),
                                                _map_height));
        pathNode = pathNode->getParent();
    }
    std::reverse(path->begin(), path->end());
    return path;
}
Example #11
0
// The osgDB::DatabasePager will call this automatically to purge expired
// tiles from the scene graph.
bool
TilePagedLOD::removeExpiredChildren(double         expiryTime, 
                                    unsigned       expiryFrame, 
                                    osg::NodeList& removedChildren)
{
    if (_children.size()>_numChildrenThatCannotBeExpired)
    {
        unsigned cindex = _children.size() - 1;

        double   minExpiryTime   = 0.0;
        unsigned minExpiryFrames = 0;

        // these were added in osg 3.1.0+
#if OSG_VERSION_GREATER_OR_EQUAL(3,1,0)
        minExpiryTime   = _perRangeDataList[cindex]._minExpiryTime;
        minExpiryFrames = _perRangeDataList[cindex]._minExpiryFrames;
#endif

        if (!_perRangeDataList[cindex]._filename.empty() &&
            _perRangeDataList[cindex]._timeStamp   + minExpiryTime   < expiryTime &&
            _perRangeDataList[cindex]._frameNumber + minExpiryFrames < expiryFrame)
        {
            osg::Node* nodeToRemove = _children[cindex].get();
            removedChildren.push_back(nodeToRemove);

            ExpirationCollector collector( _live.get() );
            nodeToRemove->accept( collector );
            _releaser->push( collector._toRelease );

            if ( _debug )
            {
                TileNode* tileNode = getTileNode();
                std::string key = tileNode ? tileNode->getKey().str() : "unk";
                OE_NOTICE 
                    << LC << "Tile " << key << " : expiring " << collector._count << " children; "
                    << "TS = " << _perRangeDataList[cindex]._timeStamp
                    << ", MET = " << minExpiryTime
                    << ", ET = " << expiryTime
                    << "; FN = " << _perRangeDataList[cindex]._frameNumber
                    << ", MEF = " << minExpiryFrames
                    << ", EF = " << expiryFrame
                    << "\n";
            }

            return Group::removeChildren(cindex,1);
        }
    }
    return false;
}
Example #12
0
void Level::FillInTiles(Vector2 a_levelSize, std::vector<int>* a_idMap)
{
	m_levelSize = a_levelSize;
	m_tiles.reserve(a_levelSize.x / TILE_WIDTH * a_levelSize.y / TILE_HEIGHT);

	for(int tileY = 0; tileY < a_levelSize.y / TILE_HEIGHT; tileY++)
	{
		for(int tileX = 0; tileX < a_levelSize.x / TILE_WIDTH; tileX++)
		{
			int index = tileX + tileY * (a_levelSize.x / TILE_WIDTH);
			TileNode* t = new TileNode(tileY, tileX, (*a_idMap)[index]);
			m_tiles.push_back(t);
			t->SetSurface(t->m_iTileId);
		}
	}
}
Example #13
0
void
TileNode::createChildren(EngineContext* context)
{
    // Create the four child nodes.
    for(unsigned quadrant=0; quadrant<4; ++quadrant)
    {
        TileNode* node = new TileNode();

        // Build the surface geometry:
        node->create( getTileKey().createChildKey(quadrant), context );

        // Add to the scene graph.
        addChild( node );

        // Inherit the samplers with new scale/bias information.
        node->inheritState( context );
    }
    
    OE_DEBUG << LC << "Creating children of: " << getTileKey().str() << "; count = " << (++_count) << "\n";
}
Example #14
0
void PathGenerator::resetTileNodes() {
    for (int i = 0; i < _map_width; i++) {
        for (int j = 0; j < _map_height; j++) {
            TileNode* node = _nodes[i][j];
            node->setF(0);
            node->setG(0);
            node->setH(0);
            node->setX(i);
            node->setY(j);
            node->setParent(NULL);
        }
    }
    _opened_nodes.clear();
    _passed_nodes.clear();
}
void
SerialKeyNodeFactory::addTile(TileModel* model, bool tileHasRealData, bool tileHasLodBlending, osg::Group* parent )
{
    // create a node:
    TileNode* tileNode = new TileNode( model->_tileKey, model->_tileLocator );

    // install the tile model and compile it:
    tileNode->setTileModel( model );
    tileNode->compile( _modelCompiler.get() );

    // assemble a URI for this tile's child group:
    std::string uri = Stringify() << model->_tileKey.str() << "." << _engineUID << ".osgearth_engine_mp_tile";

    osg::Node* result = 0L;

    // Only add the next tile if all the following are true:
    // 1. Either there's real tile data, or a minLOD is explicity set in the options;
    // 2. The tile isn't blacklisted; and
    // 3. We are still below the maximim LOD.
    bool wrapInPagedLOD =
        (tileHasRealData || (_options.minLOD().isSet() && model->_tileKey.getLOD() < *_options.minLOD())) &&
        !osgEarth::Registry::instance()->isBlacklisted( uri ) &&
        model->_tileKey.getLOD() < *_options.maxLOD();

    if ( wrapInPagedLOD )
    {
        osg::BoundingSphere bs = tileNode->getBound();
      
        float maxRange = FLT_MAX;
        
        //Compute the min range based on the 2D size of the tile
        GeoExtent extent = model->_tileKey.getExtent();
        GeoPoint lowerLeft(extent.getSRS(), extent.xMin(), extent.yMin(), 0.0, ALTMODE_ABSOLUTE);
        GeoPoint upperRight(extent.getSRS(), extent.xMax(), extent.yMax(), 0.0, ALTMODE_ABSOLUTE);
        osg::Vec3d ll, ur;
        lowerLeft.toWorld( ll );
        upperRight.toWorld( ur );
        double radius = (ur - ll).length() / 2.0;
        float minRange = (float)(radius * _options.minTileRangeFactor().value());

        
        // create a PLOD so we can keep subdividing:
        osg::PagedLOD* plod = new CustomPagedLOD( _liveTiles.get(), _deadTiles.get() );
        plod->setCenter( bs.center() );
        plod->addChild( tileNode );
        plod->setRangeMode( *_options.rangeMode() );
        plod->setFileName( 1, uri );
  

        if (plod->getRangeMode() == osg::LOD::PIXEL_SIZE_ON_SCREEN)
        {
            static const float sqrt2 = sqrt(2.0f);

            minRange = 0;
            maxRange = (*_options.tilePixelSize()) * sqrt2;
            plod->setRange( 0, minRange, maxRange  );
            plod->setRange( 1, maxRange, FLT_MAX );            
        }
        else
        {
            plod->setRange( 0, minRange, maxRange );                
            plod->setRange( 1, 0, minRange );        
        }        
                        

        plod->setUserData( new MapNode::TileRangeData(minRange, maxRange) );

#if USE_FILELOCATIONCALLBACK
        osgDB::Options* options = Registry::instance()->cloneOrCreateOptions();
        options->setFileLocationCallback( new FileLocationCallback() );
        plod->setDatabaseOptions( options );

#endif
        result = plod;
        
        if ( tileHasLodBlending )
        {
            // Make the LOD transition distance, and a measure of how
            // close the tile is to an LOD change, to shaders.
            result->addCullCallback(new LODFactorCallback);
        }
    }
    else
    {
        result = tileNode;
    }

    // this cull callback dynamically adjusts the LOD scale based on distance-to-camera:
    if ( _options.lodFallOff().isSet() && *_options.lodFallOff() > 0.0 )
    {
        result->addCullCallback( new DynamicLODScaleCallback(*_options.lodFallOff()) );
    }

    // this one rejects back-facing tiles:
    if ( _mapInfo.isGeocentric() && _options.clusterCulling() == true )
    {
        osg::HeightField* hf =
            model->_elevationData.getHFLayer()->getHeightField();

        result->addCullCallback( HeightFieldUtils::createClusterCullingCallback(
            hf,
            tileNode->getLocator()->getEllipsoidModel(),
            *_options.verticalScale() ) );
    }

    parent->addChild( result );
}
Example #16
0
void TileManager::ProcessTileMap(std::string a_sFileName)
{
	m_sCurrentLevel = a_sFileName;
	int rows = m_pBaseSprite[a_sFileName]->GetHeight() / TILE_HEIGHT;
	int columns = m_pBaseSprite[a_sFileName]->GetWidth() / TILE_WIDTH;
	int idCounter = 0;
	
	int id = 0;

	int counter = 0;
	
	for(int row = 0; row < rows; row++)
	{
		for(int col = 0; col < columns; col++)
		{
			Tmpl8::Surface* surface = new Tmpl8::Surface(TILE_WIDTH, TILE_HEIGHT);
			m_pBaseSprite[a_sFileName]->CopyPartTo(surface, 0, 0, col * TILE_WIDTH, row * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT);

			if(row == 0 && col == 0)
			{
				TileNode* tileNode = new TileNode(row, col, 0);
				m_pTiles[a_sFileName].push_back(tileNode);
				m_pTileSurfaces[a_sFileName].push_back(new TileSurface(idCounter,surface));
				tileNode->SetSurface(tileNode->m_iTileId);
				counter++;
				idCounter++;
				continue;
			}
			bool isUnique = true;
			for(std::vector<TileSurface*>::iterator iter = m_pTileSurfaces[a_sFileName].begin(); iter != m_pTileSurfaces[a_sFileName].end();)
			{
				if(!(*iter)->CompareSurfaces(surface))
				{
					isUnique = false;
					id = (*iter)->m_iTileId;
					iter = m_pTileSurfaces[a_sFileName].end();
				}
				else
				{
					iter++;
				}
			}

			if(isUnique)
			{
				m_pTileSurfaces[a_sFileName].push_back(new TileSurface(idCounter,surface));
				id = idCounter;
				idCounter++;
			}
			else
			{
				delete surface;
			}
			TileNode* tileNode = new TileNode(row, col, id);
			m_pTiles[a_sFileName].push_back(tileNode);
			tileNode->SetSurface(tileNode->m_iTileId);
			counter++;
		}
	}
	FIBITMAP* bitmap = FreeImage_Allocate(512, 1024, 24);
	int tilesInRow = 512 / TILE_WIDTH;
	int rowCounter = 0;
	int colCounter = 0;
	for(std::vector<TileSurface*>::iterator iter = m_pTileSurfaces[a_sFileName].begin(); iter != m_pTileSurfaces[a_sFileName].end(); iter++)
	{
		Tmpl8::Pixel* buffer = (*iter)->m_pTileSurface->GetBuffer();
		int pitch = (*iter)->m_pTileSurface->GetPitch();

		for(int x = 0; x < TILE_WIDTH; x++)
		{
			for(int y = 0; y < TILE_HEIGHT; y++)
			{
				RGBQUAD color;
				color.rgbRed = (buffer[x + y*pitch] & 0xFF0000) >> 16;
				color.rgbGreen = (buffer[x + y*pitch] & 0x00FF00) >> 8;
				color.rgbBlue = buffer[x + y*pitch] & 0x0000FF;
				FreeImage_SetPixelColor(bitmap, colCounter*TILE_WIDTH + x, 1023 - rowCounter*TILE_HEIGHT - y, &color);
			}
		}
		colCounter++;
		if(colCounter >= tilesInRow)
		{
			colCounter = 0;
			rowCounter++;
		}
	}
	FreeImage_Save(FIF_PNG, bitmap, std::string("assets/tilesets/"+a_sFileName+"_tilemap.png").c_str(), 0);

	std::string tileMap;
	std::stringstream ss;
			
	counter = 0;
	for(int row = 0; row < rows; row++)
	{
		for(int col = 0; col < columns; col++)
		{
			TileNode* currentNode = m_pTiles[a_sFileName][counter];
			counter++;

			ss.str("");
			ss << currentNode->m_iTileId;
			tileMap += ss.str();

			if(col+1 != columns)
				tileMap += ",";
		}
		
		if(row+1 != rows)
			tileMap += "\n";
	}
	std::ofstream tilemapFile;
	tilemapFile.open (std::string("assets/tilesets/"+a_sFileName+".dat").c_str());
	tilemapFile << tileMap;
	tilemapFile.close();
	std::ofstream metaFile;
	metaFile.open (std::string("assets/tilesets/"+a_sFileName+"_metadata.dat").c_str());
	ss.str("");
	ss << m_pTileSurfaces[a_sFileName].size() << "," << TILE_WIDTH << "," << TILE_HEIGHT << "," << m_pBaseSprite[a_sFileName]->GetWidth() << "," << m_pBaseSprite[a_sFileName]->GetHeight();
	metaFile << ss.str();
	metaFile.close();
	
	for(std::vector<TileSurface*>::iterator iter = m_pTileSurfaces[a_sFileName].begin(); iter != m_pTileSurfaces[a_sFileName].end(); iter++)
	{
		delete *iter;
	}
	m_pTileSurfaces[a_sFileName].clear();
	for(std::vector<TileNode*>::iterator iter = m_pTiles[a_sFileName].begin(); iter != m_pTiles[a_sFileName].end(); iter++)
	{
		delete *iter;
	}
	m_pTiles[a_sFileName].clear();
	delete m_pBaseSprite[a_sFileName];
}
Example #17
0
TileNode*
TileGroupFactory::createTileNode(TerrainTileModel* model,
                                 ProgressCallback* progress)
{
    TileNode* tileNode = new TileNode(model);
    
    for(TerrainTileImageLayerModelVector::const_iterator i = model->colorLayers().begin();
        i != model->colorLayers().end();
        ++i)
    {
        const TerrainTileLayerModel* layer = i->get();

        if ( layer->getTexture() )
        {
            osg::StateSet* stateSet = tileNode->getOrCreateStateSet();

            stateSet->setTextureAttribute(
                _renderBindings.color().unit(),
                layer->getTexture() );

            // (note: sampler uniform is set at the top level by the engine)
        }

        if ( layer->getMatrix() )
        {
            osg::StateSet* stateSet = tileNode->getOrCreateStateSet();

            stateSet->addUniform( new osg::Uniform(
                _renderBindings.color().matrixName().c_str(),
                *(layer->getMatrix())) );
        }
    }

    if ( model->elevationModel() )
    {
        const TerrainTileElevationModel* em = model->elevationModel();
        
        if ( em->getTexture() )
        {
            osg::StateSet* stateSet = tileNode->getOrCreateStateSet();

            stateSet->setTextureAttribute(
                _renderBindings.elevation().unit(),
                em->getTexture() );

            osg::Matrixf elevMatrix;
            if ( em->getMatrix() )
                elevMatrix = *(em->getMatrix());

            stateSet->addUniform( new osg::Uniform(
                _renderBindings.elevation().matrixName().c_str(),
                elevMatrix ));

            // (note: sampler uniform is set at the top level by the engine)
        }
    }
    
    for(TerrainTileImageLayerModelVector::const_iterator i = model->sharedLayers().begin();
        i != model->sharedLayers().end();
        ++i)
    {
        const TerrainTileImageLayerModel* layerModel = i->get();
        
        const ImageLayer* imageLayer = layerModel->getImageLayer();
        if ( imageLayer )
        {
            if ( layerModel->getTexture() )
            {
                osg::StateSet* stateSet = tileNode->getOrCreateStateSet();

                stateSet->setTextureAttribute(
                    imageLayer->shareImageUnit().get(),
                    layerModel->getTexture() );
                
                //TODO: don't really need this if we set it up in the Engine 
                //  once at the top level when adding the layer.
                stateSet->addUniform( new osg::Uniform(
                    imageLayer->shareSamplerName()->c_str(),
                    imageLayer->shareImageUnit().get() ));
            }

            if ( layerModel->getMatrix() )
            {
                osg::StateSet* stateSet = tileNode->getOrCreateStateSet();

                stateSet->addUniform( new osg::Uniform(
                    imageLayer->shareMatrixName()->c_str(),
                    *(layerModel->getMatrix())) );
            }
        }
    }

    return tileNode;
}
Example #18
0
void
TerrainCuller::apply(osg::Node& node)
{
    // push the node's state.
    osg::StateSet* node_state = node.getStateSet();

    TileNode* tileNode = dynamic_cast<TileNode*>(&node);
    if (tileNode)
    {
        _currentTileNode = tileNode;

        // reset the pointer to the first DrawTileCommand. We keep track of this so
        // we can set it's "order" member to zero at the end, so the rendering engine
        // knows to blend it with the terrain geometry color.
        _firstTileDrawCommandForTile = 0L;

        //_currentTileDrawCommands = 0u;
        
        if (!_terrain.patchLayers().empty())
        {
            // todo: check for patch/virtual
            const RenderBindings& bindings = _context->getRenderBindings();
            TileRenderModel& renderModel = _currentTileNode->renderModel();

            bool pushedMatrix = false;
            
            for (PatchLayerVector::const_iterator i = _terrain.patchLayers().begin(); i != _terrain.patchLayers().end(); ++i)
            {
                PatchLayer* layer = i->get();
                if (layer->getAcceptCallback() == 0L ||
                    layer->getAcceptCallback()->acceptKey(_currentTileNode->getKey()))
                {
                    // Push this tile's matrix if we haven't already done so:
                    if (!pushedMatrix)
                    {
                        SurfaceNode* surface = tileNode->getSurfaceNode();

                        // push the surface matrix:
                        osg::Matrix mvm = *getModelViewMatrix();
                        surface->computeLocalToWorldMatrix(mvm, this);
                        pushModelViewMatrix(createOrReuseMatrix(mvm), surface->getReferenceFrame());
                        pushedMatrix = true;
                    }

                    // Add the draw command:
                    DrawTileCommand* cmd = addDrawCommand(layer->getUID(), &renderModel, 0L, tileNode);
                    if (cmd)
                    {
                        cmd->_drawPatch = true;
                        cmd->_drawCallback = layer->getDrawCallback();
                    }
                }
            }

            if (pushedMatrix)
            {
                popModelViewMatrix();
            }
        }
    }

    else
    {
        SurfaceNode* surface = dynamic_cast<SurfaceNode*>(&node);
        if (surface)
        {
            TileRenderModel& renderModel = _currentTileNode->renderModel();

            // push the surface matrix:
            osg::Matrix mvm = *getModelViewMatrix();
            surface->computeLocalToWorldMatrix(mvm, this);
            pushModelViewMatrix(createOrReuseMatrix(mvm), surface->getReferenceFrame());

            int order = 0;

            // First go through any legit rendering pass data in the Tile and
            // and add a DrawCommand for each.
            for (unsigned p = 0; p < renderModel._passes.size(); ++p)
            {
                const RenderingPass& pass = renderModel._passes[p];
                DrawTileCommand* cmd = addDrawCommand(pass.sourceUID(), &renderModel, &pass, _currentTileNode);
                if (cmd)
                {
                    if (_firstTileDrawCommandForTile == 0L)
                    {
                        _firstTileDrawCommandForTile = cmd;
                    }
                    else if (cmd->_order < _firstTileDrawCommandForTile->_order)
                    {
                        //_firstTileDrawCommandForTile->_order = 1;
                        _firstTileDrawCommandForTile = cmd;
                    }
                }
            }

            // If the culler added no draw commands for this tile... we still need
            // to draw something or else there will be a hole! So draw a blank tile.
            // UID = -1 is the special UID code for a blank.
            if (_firstTileDrawCommandForTile == 0L)
            {
                //OE_INFO << LC << "Adding blank render for tile " << _currentTileNode->getKey().str() << std::endl;
                DrawTileCommand* cmd = addDrawCommand(-1, &renderModel, 0L, _currentTileNode);
                if (cmd)
                    cmd->_order = 0;
            }

            // Set the layer order of the first draw command for this tile to zero,
            // to support proper terrain blending.
            if (_firstTileDrawCommandForTile)
            {
                _firstTileDrawCommandForTile->_order = 0;
            }
                
            // pop the matrix from the cull stack
            popModelViewMatrix();

            // update our bounds
            _terrain._drawState->_bs.expandBy(surface->getBound());
            _terrain._drawState->_box.expandBy(_terrain._drawState->_bs);
        }
    }

    // Handle any CullCallbacks and traverse.
    osg::Callback* cullCallback = node.getCullCallback();
    if (cullCallback) cullCallback->run(&node, this);
    else traverse(node);
}
Example #19
0
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();
                
        // Next, build the surface geometry for the node.
        tileNode->create( keys[i], context );

        _terrain->addChild( tileNode );
    }

    updateState();

    // Call the base class
    TerrainEngineNode::dirtyTerrain();
}
Example #20
0
void
RexTerrainEngineNode::dirtyTerrain()
{
    if ( _terrain )
    {
        this->removeChild( _terrain );
    }

    // clear the loader:
    _loader->clear();

    // clear out the tile registry:
    if ( _liveTiles.valid() )
    {
        _liveTiles->releaseAll(_releaser.get());
    }
    
    // scrub the geometry pool:
    _geometryPool->clear();

    // New terrain
    _terrain = new osg::Group();
    this->addChild( _terrain );

    // Build the first level of the terrain.
    // Collect the tile keys comprising the root tiles of the terrain.
    std::vector<TileKey> keys;
    _mapFrame.getProfile()->getAllKeysAtLOD( *_terrainOptions.firstLOD(), keys );

    // create a root node for each root tile key.
    OE_DEBUG << LC << "Creating " << keys.size() << " root keys." << std::endl;

    // We need to take a self-ref here to ensure that the TileNode's data loader
    // can use its observer_ptr back to the terrain engine.
    this->ref();

    for( unsigned i=0; i<keys.size(); ++i )
    {
        TileNode* tileNode = new TileNode();

        if (_terrainOptions.minExpiryFrames().isSet())
        {
            tileNode->setMinimumExpirationFrames(_terrainOptions.minExpiryFrames().get());
        }
        if (_terrainOptions.minExpiryTime().isSet())
        {         
            tileNode->setMinimumExpirationTime(_terrainOptions.minExpiryTime().get());
        }
                
        // Next, build the surface geometry for the node.
        tileNode->create( keys[i], 0L, _engineContext.get() );

        // Add it to the scene graph
        _terrain->addChild( tileNode );

        // And load the tile's data synchronously (only for root tiles).
        tileNode->loadSync();
    }

    // release the self-ref.
    this->unref_nodelete();

    // Set up the state sets.
    updateState();

    // Call the base class
    TerrainEngineNode::dirtyTerrain();
}
std::vector<Vec2> TMXPathFinding::getPath(Vec2 startPos, Vec2 endPos, std::vector<int> walkableGIDs, std::vector<int> obstacleGIDs) {
	open.clear();
	close.clear();

	// inizialize a goal node
	goalNode = new TileNode();
	goalNode->setLocX(endPos.x);
	goalNode->setLocY(endPos.y);

	// inizialize a start node
	startNode = new TileNode();
	startNode->setLocX(startPos.x);
	startNode->setLocY(startPos.y);
	startNode->setCostFromStart(0);
	startNode->setParent(nullptr);

	int cost = getDistance(startNode, goalNode);

	startNode->setCostToGoal(cost);
	startNode->setTotalCost();

	open.emplace(startNode, startNode->getTotalCost());

	while (open.size() != 0) {
		// Fix a Cost to check the values
		min = 32767; // std::numeric_limits<int>::max()
		TileNode *minNode;

		// Find minNode from open QUEUE
		for (auto kv : open) {
			extractNode = kv.first;
			iCost = kv.second;
			if (iCost < min) {
				min = iCost;    // Change min to the New Cost got from the open QUEUE
				minNode = extractNode;
			}
		}
		extractNode = minNode;
		open.erase(minNode); // pop node from open

		// if it's a goal, we're done
		if (extractNode->getLocation() == goalNode->getLocation()) {
			// 1- retrieve all extractNode's parents
			// 2- save into Vec2 vector
			// 3- reverse Vec2 vector
			// 4- return Vec2 vector
			std::vector<Vec2> points;
			points.push_back(extractNode->getLocation());

			int size = extractNode->getCostFromStart();
			for (int i = 0; i < size; i++) {
				points.push_back(Vec2(extractNode->getParent()->getLocation().x, extractNode->getParent()->getLocation().y));
				extractNode = extractNode->getParent();
			}
			std::reverse(points.begin(), points.end());

			return points;
		}
		else {
			for (int i = 0; i < dir; i++) {
				costToOpen = 0;
				costToClose = 0;
				inOpen = false;
				inClose = false;
				newNode = new TileNode();
				newNode->setLocX(extractNode->getLocation().x);
				newNode->setLocY(extractNode->getLocation().y);

				switch (i) {
					case 0: // left
						newNode->setLocX(-1);
						newNode->setLocY(0);
						break;
					case 1: // right
						newNode->setLocX(1);
						newNode->setLocY(0);
						break;
					case 2: // up
						newNode->setLocX(0);
						newNode->setLocY(1);
						break;
					case 3: // down
						newNode->setLocX(0);
						newNode->setLocY(-1);
						break;
					case 4: // top-left
						newNode->setLocX(-1);
						newNode->setLocY(1);
						break;
					case 5: // bottom-left
						newNode->setLocX(-1);
						newNode->setLocY(-1);
						break;
					case 6: // bottom-right
						newNode->setLocX(1);
						newNode->setLocY(-1);
						break;
					case 7: // top-right
						newNode->setLocX(1);
						newNode->setLocY(1);
						break;

				}

				if (newNode->getLocation() != goalNode->getLocation()) {
					if (newNode->getLocation().x < 0 || newNode->getLocation().y < 0 ||
						newNode->getLocation().x >= tileMap->getMapSize().width ||
						newNode->getLocation().y >= tileMap->getMapSize().height) {
						// newNode is invalid, outside tileMap so ignore
						continue;
					}

					bool isNeedToContinue = false;
					// check newNode in given/all layers
					for (auto layer : tileLayers) {
						for (int gid : obstacleGIDs) {
							if (layer->getTileGIDAt(newNode->getLocation()) == gid) {
								// newNode is obstacle so ignore
								isNeedToContinue = true;
								break;
							}
						}
						if (isNeedToContinue)
							break;
						if (walkableGIDs.size() > 0) {
							isNeedToContinue = true;
							for (int gid : walkableGIDs) {
								if (layer->getTileGIDAt(newNode->getLocation()) == gid) {
									// newNode is walkable
									isNeedToContinue = false;
									break;
								}
							}
							if (isNeedToContinue) // newNode is not walkable so ignore
								break;
						}
					}
					if (isNeedToContinue)
						continue;
				}

				cost = getDistance(newNode, goalNode);
				newNode->setCostFromStart(extractNode->getCostFromStart() + 1);
				newNode->setCostToGoal(cost);
				newNode->setParent(extractNode);
				newNode->setTotalCost();
				inOpen = false;
				inClose = false;

				for (auto kv : open) {
					TileNode *node = kv.first;
					if (newNode->getLocation() == node->getLocation()) {
						costToOpen = node->getTotalCost();
						inOpen = true;
						break;
					}
				}
				for (auto kv : close) {
					TileNode *node = kv.first;
					if (newNode->getLocation() == node->getLocation()) {
						costToClose = node->getTotalCost();
						inClose = true;
						break;
					}
				}

				if ((inOpen && (newNode->getTotalCost() >= costToOpen)) || (inClose && (newNode->getTotalCost() >= costToClose))) {
					// newNode is already in open or close QUEUE with lower cost so ignore
					continue;
				}
				else {
					if (inClose) {
						close.erase(newNode);
						// reinsert newNode in open
						open.emplace(newNode, newNode->getTotalCost());
					}

					if (inOpen) {
						// adjust newNode's location in Open
						iCost = costToOpen;
						modifiedNode = newNode;
						// remove from open
						open.erase(newNode);

						modifiedNode->setTotalCost(newNode->getTotalCost());
						// updated node reinsert in open
						open.emplace(modifiedNode, modifiedNode->getTotalCost());
					}
					else {
						// if its neither in OPEN nor in CLOSE insert it in OPEN
						open.emplace(newNode, newNode->getTotalCost());
					}
				}
			}
		}
		close.emplace(extractNode, extractNode->getTotalCost());
	}

	std::vector<Vec2> dummy;
	return dummy;
}
osg::Node*
SingleKeyNodeFactory::createTile(TileModel*        model,
                                 bool              setupChildrenIfNecessary,
                                 ProgressCallback* progress)
{
#ifdef EXPERIMENTAL_TILE_NODE_CACHE
    osg::ref_ptr<TileNode> tileNode;
    TileNodeCache::Record rec;
    cache.get(model->_tileKey, rec);
    if ( rec.valid() )
    {
        tileNode = rec.value().get();
    }
    else
    {
        tileNode = _modelCompiler->compile( model, _frame );
        cache.insert(model->_tileKey, tileNode);
    }
#else
    // compile the model into a node:
    TileNode* tileNode = _modelCompiler->compile(model, _frame, progress);
    tileNode->setEngineUID( _engineUID );
#endif

    // see if this tile might have children.
    bool prepareForChildren =
        setupChildrenIfNecessary &&
        model->_tileKey.getLOD() < *_options.maxLOD();

    osg::Node* result = 0L;

    if ( prepareForChildren )
    {
        osg::BoundingSphere bs = tileNode->getBound();
        TilePagedLOD* plod = new TilePagedLOD( _engineUID, _liveTiles, _deadTiles );
        plod->setCenter  ( bs.center() );
        plod->addChild   ( tileNode );
        plod->setFileName( 1, Stringify() << tileNode->getKey().str() << "." << _engineUID << ".osgearth_engine_mp_tile" );
        plod->setDebug   ( _debug );

        if ( _options.rangeMode().value() == osg::LOD::DISTANCE_FROM_EYE_POINT )
        {
            //Compute the min range based on the 2D size of the tile
            GeoExtent extent = model->_tileKey.getExtent();
            double radius = 0.0;
            
#if 0
            // Test code to use the equitorial radius so that all of the tiles at the same level
            // have the same range.  This will make the poles page in more appropriately.
            if (_frame.getMapInfo().isGeocentric())
            {
                GeoExtent equatorialExtent(
                extent.getSRS(),
                extent.west(),
                -extent.height()/2.0,
                extent.east(),
                extent.height()/2.0 );
                radius = equatorialExtent.getBoundingGeoCircle().getRadius();
            }
            else
#endif
            {
                GeoPoint lowerLeft(extent.getSRS(), extent.xMin(), extent.yMin(), 0.0, ALTMODE_ABSOLUTE);
                GeoPoint upperRight(extent.getSRS(), extent.xMax(), extent.yMax(), 0.0, ALTMODE_ABSOLUTE);
                osg::Vec3d ll, ur;
                lowerLeft.toWorld( ll );
                upperRight.toWorld( ur );
                radius = (ur - ll).length() / 2.0;
            }
          
            float minRange = (float)(radius * _options.minTileRangeFactor().value());

            plod->setRange( 0, minRange, FLT_MAX );
            plod->setRange( 1, 0, minRange );
            plod->setRangeMode( osg::LOD::DISTANCE_FROM_EYE_POINT );
        }
        else
        {
            // the *2 is because we page in 4-tile sets, not individual tiles.
            float size = 2.0f * _options.tilePixelSize().value();
            plod->setRange( 0, 0.0f, size );
            plod->setRange( 1, size, FLT_MAX );
            plod->setRangeMode( osg::LOD::PIXEL_SIZE_ON_SCREEN );
        }
        
        // Install a tile-aligned bounding box in the pager node itself so we can do
        // visibility testing before paging in subtiles.
        plod->setChildBoundingBoxAndMatrix(
            1,
            tileNode->getTerrainBoundingBox(),
            tileNode->getMatrix() );

        // DBPager will set a priority based on the ratio range/maxRange.
        // This will offset that number with a full LOD #, giving LOD precedence.
        // Experimental.
        //plod->setPriorityScale( 1, model->_tileKey.getLOD()+1 );

#if USE_FILELOCATIONCALLBACK
        osgDB::Options* options = plod->getOrCreateDBOptions();
        options->setFileLocationCallback( new FileLocationCallback() );
#endif
        
        result = plod;

        // this one rejects back-facing tiles:
        if ( _frame.getMapInfo().isGeocentric() && _options.clusterCulling() == true )
        {

#if 1
            osg::HeightField* hf =
                model->_elevationData.getHeightField();

            result->addCullCallback( HeightFieldUtils::createClusterCullingCallback(
                hf,
                tileNode->getKey().getProfile()->getSRS()->getEllipsoid(),
                *_options.verticalScale() ) );
#else
            // This works, but isn't quite as tight at the cluster culler.
            // Re-evaluate down the road.
            result->addCullCallback( new HorizonTileCuller(
                _frame.getMapInfo().getSRS(),
                tileNode->getTerrainBoundingBox(),
                tileNode->getMatrix(), tileNode->getKey() ) );
#endif
        }
    }
    else
    {
        result = tileNode;
    }

    return result;
}
Example #23
0
bool operator<(const TileNode& a, const TileNode& b)
{
	return a.f() < b.f();
}
osg::Node*
SingleKeyNodeFactory::createTile(TileModel*        model,
                                 bool              setupChildrenIfNecessary,
                                 ProgressCallback* progress)
{
#ifdef EXPERIMENTAL_TILE_NODE_CACHE
    osg::ref_ptr<TileNode> tileNode;
    TileNodeCache::Record rec;
    cache.get(model->_tileKey, rec);
    if ( rec.valid() )
    {
        tileNode = rec.value().get();
    }
    else
    {
        tileNode = _modelCompiler->compile( model, _frame );
        cache.insert(model->_tileKey, tileNode);
    }
#else
    // compile the model into a node:
    TileNode* tileNode = _modelCompiler->compile(model, _frame, progress);
#endif

    // see if this tile might have children.
    bool prepareForChildren =
        setupChildrenIfNecessary &&
        model->_tileKey.getLOD() < *_options.maxLOD();

    osg::Node* result = 0L;

    if ( prepareForChildren )
    {
        osg::BoundingSphere bs = tileNode->getBound();
        TilePagedLOD* plod = new TilePagedLOD( _engineUID, _liveTiles, _deadTiles );
        plod->setCenter  ( bs.center() );
        plod->addChild   ( tileNode );
        plod->setFileName( 1, Stringify() << tileNode->getKey().str() << "." << _engineUID << ".osgearth_engine_mp_tile" );

        if ( _options.rangeMode().value() == osg::LOD::DISTANCE_FROM_EYE_POINT )
        {
            //Compute the min range based on the 2D size of the tile
            GeoExtent extent = model->_tileKey.getExtent();
            GeoPoint lowerLeft(extent.getSRS(), extent.xMin(), extent.yMin(), 0.0, ALTMODE_ABSOLUTE);
            GeoPoint upperRight(extent.getSRS(), extent.xMax(), extent.yMax(), 0.0, ALTMODE_ABSOLUTE);
            osg::Vec3d ll, ur;
            lowerLeft.toWorld( ll );
            upperRight.toWorld( ur );
            double radius = (ur - ll).length() / 2.0;
            float minRange = (float)(radius * _options.minTileRangeFactor().value());

            plod->setRange( 0, minRange, FLT_MAX );
            plod->setRange( 1, 0, minRange );
            plod->setRangeMode( osg::LOD::DISTANCE_FROM_EYE_POINT );
        }
        else
        {
            plod->setRange( 0, 0.0f, _options.tilePixelSize().value() );
            plod->setRange( 1, _options.tilePixelSize().value(), FLT_MAX );
            plod->setRangeMode( osg::LOD::PIXEL_SIZE_ON_SCREEN );
        }



        // DBPager will set a priority based on the ratio range/maxRange.
        // This will offset that number with a full LOD #, giving LOD precedence.
        // Experimental.
        //plod->setPriorityScale( 1, model->_tileKey.getLOD()+1 );

#if USE_FILELOCATIONCALLBACK
        osgDB::Options* options = plod->getOrCreateDBOptions();
        options->setFileLocationCallback( new FileLocationCallback() );
#endif
        
        result = plod;

        // this one rejects back-facing tiles:
        if ( _frame.getMapInfo().isGeocentric() && _options.clusterCulling() == true )
        {
            osg::HeightField* hf =
                model->_elevationData.getHeightField();

            result->addCullCallback( HeightFieldUtils::createClusterCullingCallback(
                hf,
                tileNode->getKey().getProfile()->getSRS()->getEllipsoid(),
                *_options.verticalScale() ) );
        }
    }
    else
    {
        result = tileNode;
    }

    return result;
}
Example #25
0
// The osgDB::DatabasePager will call this method when merging a new child
// into the scene graph.
bool
TilePagedLOD::addChild(osg::Node* node)
{
    // First check whether this is a new TileGroup (a group that contains a TileNode
    // and children paged LODs). If so, add it normally and inform our parent.
    TileGroup* subtilegroup = dynamic_cast<TileGroup*>(node);
    if ( subtilegroup )
    {
        TileNode* subtile = subtilegroup->getTileNode();
        _isUpsampled = !subtile->getTileModel()->hasRealData();
        _live->add( subtile );
        return osg::PagedLOD::addChild( node );
    }

    // If that fails, check whether this is a simple TileNode. This means that 
    // this is a leaf node in the graph (no children), or it's a replacement
    // tile for our existing tileNode, or possibly that it has no data at all 
    // (and we need to create an upsampled child to complete the required set of
    // four).
    TileNode* subtile = dynamic_cast<TileNode*>(node);
    if ( subtile )
    {
        if ( subtile->getTileModel()->getMapRevision() < _live->getMapRevision() )
        {
            //OE_NOTICE << LC << "Tile " << subtile->getKey().str() << " received data but it's already out of date...requeuing"
            //    << std::endl;
            return false;
        }

        // If it's a legit tile, add it normally and inform our parent.
        // TODO: "invalid" tiles are deprecated. Remove this.
        else
        if ( subtile->isValid() )
        {
            if ( _children.size() == 0 )
            {
                _isUpsampled = !subtile->getTileModel()->hasRealData();

                // The initial valid tile node we've been waiting for. Insert it.
                _live->add( subtile );
                return osg::PagedLOD::addChild( node );
            }
            else
            {
                // A replacement tile. Replace the tile node we have with this
                // new version and update the registry.
                _isUpsampled = !subtile->getTileModel()->hasRealData();
                //if ( _isUpsampled )
                //    OE_NOTICE << LC << "Replaced UPSAMPLED leaf at " << _prefix << std::endl;

                if ( dynamic_cast<TileGroup*>(_children[0].get()) )
                {
                    subtile->setCullCallback( 0L );
                    static_cast<TileGroup*>(_children[0].get())->setTileNode( subtile );
                }
                else // TileNode
                {
                    this->setChild(0, subtile);
                }

                // remove the tile-replacement filename.
                _rangeList.resize( 1 );
                _perRangeDataList.resize( 1 );

                // update the registry. don't need to remove the old entry since add() will
                // replace the existing entry (they have the same key)
                _live->add( subtile );

                return true;
            }
        }
    }
    
    // Getting here means the Tile dies somewhere in the pager while the pager was
    // trying to add it. From what I can tell, this is normal and just happens sometimes
    if ( !node )
    {
        OE_DEBUG << LC << "TilePagedLOD: got an addChild(NULL) on " << _prefix << std::endl;
        _isCanceled = true;
    }

    return false;
}
Example #26
0
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();
}
Example #27
0
TileNode*
TileGroupFactory::createTileNodeGraph(TerrainTileModel* model,
                                      bool              setupChildrenIfNecessary,
                                      ProgressCallback* progress)
{
    // TODO: fix this
    const unsigned tileSize = 17;

    // Build the surface node.
    SurfaceNodeFactory factory(model, _frame, _renderBindings, _geometryPool, tileSize, _options);
    SurfaceNode* surfaceNode = factory.createSurfaceNode();

    surfaceNode->setEngineUID( _terrainEngine->getUID() );

    // see if this tile might have children.
    bool prepareForChildren =
        setupChildrenIfNecessary &&
        model->getKey().getLOD() < *_options.maxLOD();
    
    // Build the Tile Node that will hold all the textures and texture matrices.
    TileNode* tileNode = createTileNode(
        model,
        progress );

    // Build the paging node that will load subtiles, if necessary:
    if ( prepareForChildren )
    {
        osg::BoundingSphere bs = surfaceNode->getBound();
        TilePagedLOD* plod = new TilePagedLOD( _terrainEngine->getUID(), _liveTiles, _deadTiles );
        plod->setCenter  ( bs.center() );
        plod->addChild   ( surfaceNode );
        plod->setFileName( 1, Stringify() 
            << model->getKey().str()
            << "." << _terrainEngine->getUID()
            << ".osgearth_engine_mp_tile" );

        if ( _options.rangeMode().value() == osg::LOD::DISTANCE_FROM_EYE_POINT )
        {
            //Compute the min range based on the 2D size of the tile
            GeoExtent extent = model->getKey().getExtent();
            GeoPoint lowerLeft(extent.getSRS(), extent.xMin(), extent.yMin(), 0.0, ALTMODE_ABSOLUTE);
            GeoPoint upperRight(extent.getSRS(), extent.xMax(), extent.yMax(), 0.0, ALTMODE_ABSOLUTE);
            osg::Vec3d ll, ur;
            lowerLeft.toWorld( ll );
            upperRight.toWorld( ur );
            double radius = (ur - ll).length() / 2.0;
            float minRange = (float)(radius * _options.minTileRangeFactor().value());

            plod->setRange( 0, minRange, FLT_MAX );
            plod->setRange( 1, 0, minRange );
            plod->setRangeMode( osg::LOD::DISTANCE_FROM_EYE_POINT );
        }
        else
        {
            plod->setRange( 0, 0.0f, _options.tilePixelSize().value() );
            plod->setRange( 1, _options.tilePixelSize().value(), FLT_MAX );
            plod->setRangeMode( osg::LOD::PIXEL_SIZE_ON_SCREEN );
        }
        
#if 0 // TODO: reinstate this!

        // Install a tile-aligned bounding box in the pager node itself so we can do
        // visibility testing before paging in subtiles.
        plod->setChildBoundingBoxAndMatrix(
            1,
            surfaceNode->getTerrainBoundingBox(),
            surfaceNode->getLocalToWorldMatrix() );
#endif

#if USE_FILELOCATIONCALLBACK
        osgDB::Options* options = plod->getOrCreateDBOptions();
        options->setFileLocationCallback( new FileLocationCallback() );
#endif
        
        tileNode->addChild( plod );

        // Install a callback to reject back-facing tiles.
        if ( _frame.getMapInfo().isGeocentric() && _options.clusterCulling() == true )
        {
            const osg::HeightField* heightField = model->elevationModel()->getHeightField();
            if ( heightField )
            {
                tileNode->addCullCallback( HeightFieldUtils::createClusterCullingCallback(
                    heightField,
                    tileNode->getKey().getProfile()->getSRS()->getEllipsoid(),
                    *_options.verticalScale() ) );
            }
        }
    }
    else
    {
        tileNode->addChild( surfaceNode );
    }

    return tileNode;
}
Example #28
0
bool
TileNode::inheritState(EngineContext* context)
{
    // Find the parent node. It will only be null if this is a "first LOD" tile.
    TileNode* parent = getNumParents() > 0 ? dynamic_cast<TileNode*>(getParent(0)) : 0L;

    bool changesMade = false;

    // which quadrant is this tile in?
    unsigned quadrant = getTileKey().getQuadrant();

    // default inheritance of the elevation data for bounding purposes:
    osg::ref_ptr<const osg::Image> elevRaster;
    osg::Matrixf                   elevMatrix;
    if ( parent )
    {
        elevRaster = parent->getElevationRaster();
        elevMatrix = parent->getElevationMatrix();
        elevMatrix.preMult( scaleBias[quadrant] );
    }

    // Find all the sampler matrix uniforms and scale/bias them to the current quadrant.
    // This will inherit textures and use the proper sub-quadrant until new data arrives (later).
    for( RenderBindings::const_iterator binding = context->getRenderBindings().begin(); binding != context->getRenderBindings().end(); ++binding )
    {
        if ( binding->usage().isSetTo(binding->COLOR) )
        {
            if ( parent && parent->getStateSet() )
            {
                MPTexture* parentMPTex = parent->getMPTexture();
                _mptex->inheritState( parentMPTex, scaleBias[quadrant] );
                changesMade = true;
            }
        }

        else if ( binding->usage().isSetTo(binding->COLOR_PARENT) )
        {
            //nop -- this is handled as part of the COLOR binding
        }

        else
        {
            osg::StateAttribute* sa = getStateSet()->getTextureAttribute(binding->unit(), osg::StateAttribute::TEXTURE);        

            // If the attribute isn't present, that means we are inheriting it from above.
            // So construct a new scale/bias matrix.
            if ( sa == 0L )
            {
                osg::Matrixf matrix;

                // Find the parent's matrix and scale/bias it to this quadrant:
                if ( parent && parent->getStateSet() )
                {
                    const osg::Uniform* matrixUniform = parent->getStateSet()->getUniform( binding->matrixName() );
                    if ( matrixUniform )
                    {
                        matrixUniform->get( matrix );
                        matrix.preMult( scaleBias[quadrant] );
                    }
                }

                // Add a new uniform with the scale/bias'd matrix:
                osg::StateSet* stateSet = getOrCreateStateSet();
                stateSet->removeUniform( binding->matrixName() );
                stateSet->addUniform( context->getOrCreateMatrixUniform(binding->matrixName(), matrix) );
                changesMade = true;
            }

            // If this is elevation data, record the new raster so we can apply it to the node.
            else if ( binding->usage().isSetTo(binding->ELEVATION) )
            {
                osg::Texture* t = static_cast<osg::Texture*>(sa);
                elevRaster = t->getImage(0);
                elevMatrix = osg::Matrixf::identity();
            }
        }
    }

    // If we found one, communicate it to the node and its children.
    if (elevRaster.valid())
    {
        if (elevRaster.get() != getElevationRaster() || elevMatrix != getElevationMatrix() )
        {
            setElevationRaster( elevRaster.get(), elevMatrix );
            changesMade = true;
        }
    }

    // finally, update the uniforms for terrain morphing
    updateTileUniforms( context->getSelectionInfo() );

    if ( !changesMade )
    {
        OE_INFO << LC << _key.str() << ", good, no changes :)\n";
    }
    else
    {
        dirtyBound();
    }

    return changesMade;
}
Example #29
0
void
TerrainCuller::apply(osg::Node& node)
{
    // push the node's state.
    osg::StateSet* node_state = node.getStateSet();

    TileNode* tileNode = dynamic_cast<TileNode*>(&node);
    if (tileNode)
    {
        _currentTileNode = tileNode;
        _currentTileDrawCommands = 0u;
        
        if (!_terrain.patchLayers().empty())
        {
            // todo: check for patch/virtual
            const RenderBindings&  bindings    = _context->getRenderBindings();
            TileRenderModel& renderModel = _currentTileNode->renderModel();

            bool pushedMatrix = false;
            
            for (PatchLayerVector::const_iterator i = _terrain.patchLayers().begin(); i != _terrain.patchLayers().end(); ++i)
            {
                PatchLayer* layer = i->get();
                if (layer->getAcceptCallback() == 0L ||
                    layer->getAcceptCallback()->acceptKey(_currentTileNode->getKey()))
                {
                    // Push this tile's matrix if we haven't already done so:
                    if (!pushedMatrix)
                    {
                        SurfaceNode* surface = tileNode->getSurfaceNode();

                        // push the surface matrix:
                        osg::Matrix mvm = *getModelViewMatrix();
                        surface->computeLocalToWorldMatrix(mvm, this);
                        pushModelViewMatrix(createOrReuseMatrix(mvm), surface->getReferenceFrame());
                        pushedMatrix = true;
                    }

                    // Add the draw command:
                    DrawTileCommand* cmd = addDrawCommand(layer->getUID(), &renderModel, 0L, tileNode);
                    if (cmd)
                    {
                        cmd->_drawPatch = true;
                        cmd->_drawCallback = layer->getDrawCallback();
                        ++_currentTileDrawCommands;
                    }
                }
            }

            if (pushedMatrix)
            {
                popModelViewMatrix();
            }
        }
    }

    else
    {
        SurfaceNode* surface = dynamic_cast<SurfaceNode*>(&node);
        if (surface)
        {
            TileRenderModel& renderModel = _currentTileNode->renderModel();

            // push the surface matrix:
            osg::Matrix mvm = *getModelViewMatrix();
            surface->computeLocalToWorldMatrix(mvm, this);
            pushModelViewMatrix(createOrReuseMatrix(mvm), surface->getReferenceFrame());
                        
            // First go through any legit rendering pass data in the Tile and
            // and add a DrawCommand for each.
            for (unsigned p = 0; p < renderModel._passes.size(); ++p)
            {
                const RenderingPass& pass = renderModel._passes[p];
                
                if (pass._layer.valid() && pass._layer->getRenderType() == Layer::RENDERTYPE_TILE)
                {
                    if (addDrawCommand(pass._sourceUID, &renderModel, &pass, _currentTileNode))
                    {
                        ++_currentTileDrawCommands;
                    }
                }
            }

            // Next, add a DrawCommand for each tile layer not represented in the TerrainTileModel
            // as a rendering pass.
            for (LayerVector::const_iterator i = _terrain.tileLayers().begin(); i != _terrain.tileLayers().end(); ++i)
            {
                Layer* layer = i->get();
                if (addDrawCommand(layer->getUID(), &renderModel, 0L, _currentTileNode))
                {
                    ++_currentTileDrawCommands;
                }
            }

            // If the culler added no draw commands for this tile... do something!
            if (_currentTileDrawCommands == 0)
            {
                //OE_INFO << LC << "Adding blank render.\n";
                addDrawCommand(-1, &renderModel, 0L, _currentTileNode);
            }

            popModelViewMatrix();

            _terrain._drawState->_bs.expandBy(surface->getBound());
            _terrain._drawState->_box.expandBy(_terrain._drawState->_bs);
        }
    }

    traverse(node);
}