void TerrainTileModelFactory::addColorLayers(TerrainTileModel* model, const Map* map, const TerrainEngineRequirements* reqs, const TileKey& key, const CreateTileModelFilter& filter, ProgressCallback* progress) { OE_START_TIMER(fetch_image_layers); int order = 0; LayerVector layers; map->getLayers(layers); for (LayerVector::const_iterator i = layers.begin(); i != layers.end(); ++i) { Layer* layer = i->get(); if (layer->getRenderType() != layer->RENDERTYPE_TERRAIN_SURFACE) continue; if (!layer->getEnabled()) continue; if (!filter.accept(layer)) continue; ImageLayer* imageLayer = dynamic_cast<ImageLayer*>(layer); if (imageLayer) { osg::Texture* tex = 0L; osg::Matrixf textureMatrix; if (imageLayer->isKeyInLegalRange(key) && imageLayer->mayHaveDataInExtent(key.getExtent())) { if (imageLayer->createTextureSupported()) { tex = imageLayer->createTexture( key, progress, textureMatrix ); } else { GeoImage geoImage = imageLayer->createImage( key, progress ); if ( geoImage.valid() ) { if ( imageLayer->isCoverage() ) tex = createCoverageTexture(geoImage.getImage(), imageLayer); else tex = createImageTexture(geoImage.getImage(), imageLayer); } } } // if this is the first LOD, and the engine requires that the first LOD // be populated, make an empty texture if we didn't get one. if (tex == 0L && _options.firstLOD() == key.getLOD() && reqs && reqs->fullDataAtFirstLodRequired()) { tex = _emptyTexture.get(); } if (tex) { tex->setName(model->getKey().str()); TerrainTileImageLayerModel* layerModel = new TerrainTileImageLayerModel(); layerModel->setImageLayer(imageLayer); layerModel->setTexture(tex); layerModel->setMatrix(new osg::RefMatrixf(textureMatrix)); model->colorLayers().push_back(layerModel); if (imageLayer->isShared()) { model->sharedLayers().push_back(layerModel); } if (imageLayer->isDynamic()) { model->setRequiresUpdateTraverse(true); } } } else // non-image kind of TILE layer: { TerrainTileColorLayerModel* colorModel = new TerrainTileColorLayerModel(); colorModel->setLayer(layer); model->colorLayers().push_back(colorModel); } } if (progress) progress->stats()["fetch_imagery_time"] += OE_STOP_TIMER(fetch_image_layers); }
osg::Image* CompositeTileSource::createImage(const TileKey& key, ProgressCallback* progress ) { ImageMixVector images; images.reserve(_imageLayers.size()); // Try to get an image from each of the layers for the given key. for (ImageLayerVector::const_iterator itr = _imageLayers.begin(); itr != _imageLayers.end(); ++itr) { ImageLayer* layer = itr->get(); ImageInfo imageInfo; imageInfo.dataInExtents = layer->getTileSource()->hasDataInExtent( key.getExtent() ); imageInfo.opacity = layer->getOpacity(); if (imageInfo.dataInExtents) { GeoImage image = layer->createImage(key, progress); if (image.valid()) { imageInfo.image = image.getImage(); } // If the progress got cancelled or it needs a retry then return NULL to prevent this tile from being built and cached with incomplete or partial data. if (progress && (progress->isCanceled() || progress->needsRetry())) { OE_DEBUG << LC << " createImage was cancelled or needs retry for " << key.str() << std::endl; return 0L; } } images.push_back(imageInfo); } // Determine the output texture size to use based on the image that were creatd. unsigned numValidImages = 0; osg::Vec2s textureSize; for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& info = images[i]; if (info.image.valid()) { if (numValidImages == 0) { textureSize.set( info.image->s(), info.image->t()); } numValidImages++; } } // Create fallback images if we have some valid data but not for all the layers if (numValidImages > 0 && numValidImages < images.size()) { for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& info = images[i]; ImageLayer* layer = _imageLayers[i].get(); if (!info.image.valid() && info.dataInExtents) { TileKey parentKey = key.createParentKey(); GeoImage image; while (!image.valid() && parentKey.valid()) { image = layer->createImage(parentKey, progress); if (image.valid()) { break; } // If the progress got cancelled or it needs a retry then return NULL to prevent this tile from being built and cached with incomplete or partial data. if (progress && (progress->isCanceled() || progress->needsRetry())) { OE_DEBUG << LC << " createImage was cancelled or needs retry for " << key.str() << std::endl; return 0L; } parentKey = parentKey.createParentKey(); } if (image.valid()) { // TODO: Bilinear options? bool bilinear = layer->isCoverage() ? false : true; GeoImage cropped = image.crop( key.getExtent(), true, textureSize.x(), textureSize.y(), bilinear); info.image = cropped.getImage(); } } } } // Now finally create the output image. //Recompute the number of valid images numValidImages = 0; for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& info = images[i]; if (info.image.valid()) numValidImages++; } if ( progress && progress->isCanceled() ) { return 0L; } else if ( numValidImages == 0 ) { return 0L; } else if ( numValidImages == 1 ) { //We only have one valid image, so just return it and don't bother with compositing for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& info = images[i]; if (info.image.valid()) return info.image.release(); } return 0L; } else { osg::Image* result = 0; for (unsigned int i = 0; i < images.size(); i++) { ImageInfo& imageInfo = images[i]; if (!result) { if (imageInfo.image.valid()) { result = new osg::Image( *imageInfo.image.get()); } } else { if (imageInfo.image.valid()) { ImageUtils::mix( result, imageInfo.image.get(), imageInfo.opacity ); } } } return result; } }
void addLayerItem( Grid* grid, int layerIndex, int numLayers, Layer* layer, bool isActive ) { int gridCol = 0; int gridRow = grid->getNumRows(); VisibleLayer* visibleLayer = dynamic_cast<VisibleLayer*>(layer); // only show layers that derive from VisibleLayer if (!visibleLayer) return; ImageLayer* imageLayer = dynamic_cast<ImageLayer*>(layer); // don't show hidden coverage layers if (imageLayer && imageLayer->isCoverage() && !imageLayer->getVisible()) return; ElevationLayer* elevationLayer = dynamic_cast<ElevationLayer*>(layer); // a checkbox to toggle the layer's visibility: if (visibleLayer && layer->getEnabled() && !(imageLayer && imageLayer->isCoverage())) { CheckBoxControl* visibility = new CheckBoxControl( visibleLayer->getVisible() ); visibility->addEventHandler( new ToggleLayerVisibility(visibleLayer) ); grid->setControl( gridCol, gridRow, visibility ); } gridCol++; // the layer name LabelControl* name = new LabelControl( layer->getName() ); if (!layer->getEnabled()) name->setForeColor(osg::Vec4f(1,1,1,0.35)); grid->setControl( gridCol, gridRow, name ); gridCol++; // layer type std::string typeName = typeid(*layer).name(); typeName = typeName.substr(typeName.find_last_of(":")+1); LabelControl* typeLabel = new LabelControl(typeName, osg::Vec4(.5,.7,.5,1)); grid->setControl( gridCol, gridRow, typeLabel ); gridCol++; // status indicator LabelControl* statusLabel = layer->getStatus().isError() ? new LabelControl("[error]", osg::Vec4(1,0,0,1)) : !layer->getEnabled()? new LabelControl("[disabled]", osg::Vec4(1,1,1,0.35)) : new LabelControl("[ok]", osg::Vec4(0,1,0,1)) ; grid->setControl( gridCol, gridRow, statusLabel ); gridCol++; if (visibleLayer && !elevationLayer && visibleLayer->getEnabled()) { // an opacity slider HSliderControl* opacity = new HSliderControl( 0.0f, 1.0f, visibleLayer->getOpacity() ); opacity->setWidth( 125 ); opacity->setHeight( 12 ); opacity->addEventHandler( new LayerOpacityHandler(visibleLayer) ); grid->setControl( gridCol, gridRow, opacity ); } gridCol++; // zoom button if (layer->getExtent().isValid()) { LabelControl* zoomButton = new LabelControl("GO", 14); zoomButton->setBackColor( .4,.4,.4,1 ); zoomButton->setActiveColor( .8,0,0,1 ); zoomButton->addEventHandler( new ZoomLayerHandler(layer) ); grid->setControl( gridCol, gridRow, zoomButton ); } gridCol++; // move buttons if ( layerIndex < numLayers-1 && isActive ) { LabelControl* upButton = new LabelControl( "UP", 14 ); upButton->setBackColor( .4,.4,.4,1 ); upButton->setActiveColor( .8,0,0,1 ); upButton->addEventHandler( new MoveLayerHandler( layer, layerIndex+1 ) ); grid->setControl( gridCol, gridRow, upButton ); } gridCol++; if ( layerIndex > 0 && isActive) { LabelControl* upButton = new LabelControl( "DOWN", 14 ); upButton->setBackColor( .4,.4,.4,1 ); upButton->setActiveColor( .8,0,0,1 ); upButton->addEventHandler( new MoveLayerHandler( layer, layerIndex-1 ) ); grid->setControl( gridCol, gridRow, upButton ); } gridCol++; // add/remove button: LabelControl* addRemove = new LabelControl( isActive? "REMOVE" : "ADD", 14 ); addRemove->setHorizAlign( Control::ALIGN_CENTER ); addRemove->setBackColor( .4,.4,.4,1 ); addRemove->setActiveColor( .8,0,0,1 ); addRemove->addEventHandler( new RemoveLayerHandler(layer) ); grid->setControl( gridCol, gridRow, addRemove ); gridCol++; // enable/disable button LabelControl* enableDisable = new LabelControl(layer->getEnabled() ? "DISABLE" : "ENABLE", 14); enableDisable->setHorizAlign( Control::ALIGN_CENTER ); enableDisable->setBackColor( .4,.4,.4,1 ); enableDisable->setActiveColor( .8,0,0,1 ); enableDisable->addEventHandler( new EnableDisableHandler(layer) ); grid->setControl( gridCol, gridRow, enableDisable ); gridCol++; if (layer->getStatus().isError()) { grid->setControl(gridCol, gridRow, new LabelControl(layer->getStatus().message(), osg::Vec4(1,.2,.2,1))); } }