void RexTerrainEngineNode::addTileLayer(Layer* tileLayer) { if ( tileLayer && tileLayer->getEnabled() ) { ImageLayer* imageLayer = dynamic_cast<ImageLayer*>(tileLayer); if (imageLayer) { // for a shared layer, allocate a shared image unit if necessary. if ( imageLayer->isShared() ) { if (!imageLayer->shareImageUnit().isSet()) { int temp; if ( getResources()->reserveTextureImageUnit(temp, imageLayer->getName().c_str()) ) { imageLayer->shareImageUnit() = temp; //OE_INFO << LC << "Image unit " << temp << " assigned to shared layer " << imageLayer->getName() << std::endl; } else { OE_WARN << LC << "Insufficient GPU image units to share layer " << imageLayer->getName() << std::endl; } } // Build a sampler binding for the shared layer. if ( imageLayer->shareImageUnit().isSet() ) { // Find the next empty SHARED slot: unsigned newIndex = SamplerBinding::SHARED; while (_renderBindings[newIndex].isActive()) ++newIndex; // Put the new binding there: SamplerBinding& newBinding = _renderBindings[newIndex]; newBinding.usage() = SamplerBinding::SHARED; newBinding.sourceUID() = imageLayer->getUID(); newBinding.unit() = imageLayer->shareImageUnit().get(); newBinding.samplerName() = imageLayer->shareTexUniformName().get(); newBinding.matrixName() = imageLayer->shareTexMatUniformName().get(); OE_INFO << LC << "Shared Layer \"" << imageLayer->getName() << "\" : sampler=\"" << newBinding.samplerName() << "\", " << "matrix=\"" << newBinding.matrixName() << "\", " << "unit=" << newBinding.unit() << "\n"; } } } else { // non-image tile layer. Keep track of these.. } if (_terrain) { // Update the existing render models, and trigger a data reload. // Later we can limit the reload to an update of only the new data. UpdateRenderModels updateModels(_mapFrame); #if 0 // This uses the loaddata filter approach which will only request // data for one layer. It mostly works but not 100%; see hires-insets // as an example. Removing the world layer and re-adding it while // zoomed in doesn't result in all tiles reloading. Possibly a // synchronization issue. ImageLayerVector imageLayers; _mapFrame.getLayers(imageLayers); if (imageLayers.size() == 1) updateModels.setReloadData(true); else updateModels.layersToLoad().insert(tileLayer->getUID()); #else updateModels.setReloadData(true); #endif _terrain->accept(updateModels); } } }
Config EarthFileSerializer2::serialize(const MapNode* input, const std::string& referrer) const { Config mapConf("map"); mapConf.set("version", "2"); if ( !input || !input->getMap() ) return mapConf; const Map* map = input->getMap(); MapFrame mapf( map, Map::ENTIRE_MODEL ); // the map and node options: Config optionsConf = map->getInitialMapOptions().getConfig(); optionsConf.merge( input->getMapNodeOptions().getConfig() ); mapConf.add( "options", optionsConf ); // the layers for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); //Config layerConf = layer->getInitialOptions().getConfig(); Config layerConf = layer->getImageLayerOptions().getConfig(); layerConf.set("name", layer->getName()); layerConf.set("driver", layer->getInitialOptions().driver()->getDriver()); mapConf.add( "image", layerConf ); } for( ElevationLayerVector::const_iterator i = mapf.elevationLayers().begin(); i != mapf.elevationLayers().end(); ++i ) { ElevationLayer* layer = i->get(); //Config layerConf = layer->getInitialOptions().getConfig(); Config layerConf = layer->getElevationLayerOptions().getConfig(); layerConf.set("name", layer->getName()); layerConf.set("driver", layer->getInitialOptions().driver()->getDriver()); mapConf.add( "elevation", layerConf ); } for( ModelLayerVector::const_iterator i = mapf.modelLayers().begin(); i != mapf.modelLayers().end(); ++i ) { ModelLayer* layer = i->get(); Config layerConf = layer->getModelLayerOptions().getConfig(); layerConf.set("name", layer->getName()); layerConf.set("driver", layer->getModelLayerOptions().driver()->getDriver()); mapConf.add( "model", layerConf ); } Config ext = input->externalConfig(); if ( !ext.empty() ) { ext.key() = "extensions"; mapConf.add( ext ); } #if 0 // removed until it can be debugged. // Re-write pathnames in the Config so they are relative to the new referrer. if ( _rewritePaths && !referrer.empty() ) { RewritePaths rewritePaths( referrer ); rewritePaths.setRewriteAbsolutePaths( _rewriteAbsolutePaths ); rewritePaths.apply( mapConf ); } #endif return mapConf; }
// Generates the main shader code for rendering the terrain. void RexTerrainEngineNode::updateState() { if ( _batchUpdateInProgress ) { _stateUpdateRequired = true; } else { osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); // everything osg::StateSet* surfaceStateSet = getSurfaceStateSet(); // just the surface //terrainStateSet->setRenderBinDetails(0, "SORT_FRONT_TO_BACK"); // required for multipass tile rendering to work surfaceStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); surfaceStateSet->setAttributeAndModes( new osg::CullFace(), osg::StateAttribute::ON); // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); // install patch param if we are tessellation on the GPU. if ( _terrainOptions.gpuTessellation() == true ) { #ifdef HAVE_PATCH_PARAMETER terrainStateSet->setAttributeAndModes( new osg::PatchParameter(3) ); #endif } // install shaders, if we're using them. if ( Registry::capabilities().supportsGLSL() ) { Shaders package; VirtualProgram* terrainVP = VirtualProgram::getOrCreate(terrainStateSet); terrainVP->setName( "Rex Terrain" ); package.load(terrainVP, package.ENGINE_VERT_MODEL); surfaceStateSet->addUniform(new osg::Uniform("oe_terrain_color", _terrainOptions.color().get())); if (_terrainOptions.enableBlending() == true) { surfaceStateSet->setDefine("OE_TERRAIN_BLEND_IMAGERY"); } // Funtions that affect only the terrain surface: VirtualProgram* surfaceVP = VirtualProgram::getOrCreate(surfaceStateSet); surfaceVP->setName("Rex Surface"); // Functions that affect the terrain surface only: package.load(surfaceVP, package.ENGINE_VERT_VIEW); package.load(surfaceVP, package.ENGINE_FRAG); // Elevation? if (this->elevationTexturesRequired()) { surfaceStateSet->setDefine("OE_TERRAIN_RENDER_ELEVATION"); } // Normal mapping shaders: if ( this->normalTexturesRequired() ) { package.load(surfaceVP, package.NORMAL_MAP_VERT); package.load(surfaceVP, package.NORMAL_MAP_FRAG); surfaceStateSet->setDefine("OE_TERRAIN_RENDER_NORMAL_MAP"); } // Morphing? if (_terrainOptions.morphTerrain() == true || _terrainOptions.morphImagery() == true) { package.load(surfaceVP, package.MORPHING_VERT); if (_terrainOptions.morphImagery() == true) { surfaceStateSet->setDefine("OE_TERRAIN_MORPH_IMAGERY"); } if (_terrainOptions.morphTerrain() == true) { surfaceStateSet->setDefine("OE_TERRAIN_MORPH_GEOMETRY"); } } // assemble color filter code snippets. bool haveColorFilters = false; { // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "$COLOR_FILTER_HEAD" "void oe_rexEngine_applyFilters(inout vec4 color) \n" "{ \n" "$COLOR_FILTER_BODY" "} \n"; std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; ImageLayerVector imageLayers; _update_mapf->getLayers(imageLayers); for( int i=0; i<imageLayers.size(); ++i ) { ImageLayer* layer = imageLayers.at(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( surfaceStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "$COLOR_FILTER_HEAD", cf_head_str ); replaceIn( fs_colorfilters, "$COLOR_FILTER_BODY", cf_body_str ); surfaceVP->setFunction( "oe_rexEngine_applyFilters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.6 ); } } // Apply uniforms for sampler bindings: OE_DEBUG << LC << "Render Bindings:\n"; osg::ref_ptr<osg::Texture> tex = new osg::Texture2D(ImageUtils::createEmptyImage(1,1)); for (unsigned i = 0; i < _renderBindings.size(); ++i) { SamplerBinding& b = _renderBindings[i]; if (b.isActive()) { osg::Uniform* u = new osg::Uniform(b.samplerName().c_str(), b.unit()); terrainStateSet->addUniform( u ); OE_DEBUG << LC << " > Bound \"" << b.samplerName() << "\" to unit " << b.unit() << "\n"; terrainStateSet->setTextureAttribute(b.unit(), tex.get()); } } // uniform that controls per-layer opacity terrainStateSet->addUniform( new osg::Uniform("oe_layer_opacity", 1.0f) ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->addUniform( new osg::Uniform("oe_layer_uid", (int)-1 ) ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->addUniform( new osg::Uniform("oe_layer_order", (int)0) ); // default min/max range uniforms. (max < min means ranges are disabled) terrainStateSet->addUniform( new osg::Uniform("oe_layer_minRange", 0.0f) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_maxRange", -1.0f) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_attenuationRange", _terrainOptions.attentuationDistance().get()) ); terrainStateSet->getOrCreateUniform( "oe_min_tile_range_factor", osg::Uniform::FLOAT)->set( *_terrainOptions.minTileRangeFactor() ); terrainStateSet->addUniform(new osg::Uniform("oe_tile_size", (float)_terrainOptions.tileSize().get())); // special object ID that denotes the terrain surface. surfaceStateSet->addUniform( new osg::Uniform( Registry::objectIndex()->getObjectIDUniformName().c_str(), OSGEARTH_OBJECTID_TERRAIN) ); } _stateUpdateRequired = false; } }
void Map::ParseText(const string &text) { // Create a tiny xml document and use it to parse the text. tinyxml2::XMLDocument doc; doc.Parse(text.c_str()); // Check for parsing errors. if (doc.Error()) { has_error = true; error_code = TMX_PARSING_ERROR; error_text = doc.GetErrorStr1(); return; } tinyxml2::XMLNode *mapNode = doc.FirstChildElement("map"); tinyxml2::XMLElement* mapElem = mapNode->ToElement(); // Read the map attributes. version = mapElem->IntAttribute("version"); width = mapElem->IntAttribute("width"); height = mapElem->IntAttribute("height"); tile_width = mapElem->IntAttribute("tilewidth"); tile_height = mapElem->IntAttribute("tileheight"); next_object_id = mapElem->IntAttribute("nextobjectid"); if (mapElem->Attribute("backgroundcolor")) { background_color = mapElem->Attribute("backgroundcolor"); } // Read the orientation std::string orientationStr = mapElem->Attribute("orientation"); if (!orientationStr.compare("orthogonal")) { orientation = TMX_MO_ORTHOGONAL; } else if (!orientationStr.compare("isometric")) { orientation = TMX_MO_ISOMETRIC; } else if (!orientationStr.compare("staggered")) { orientation = TMX_MO_STAGGERED; } // Read the render order if (mapElem->Attribute("renderorder")) { std::string renderorderStr = mapElem->Attribute("renderorder"); if (!renderorderStr.compare("right-down")) { render_order = TMX_RIGHT_DOWN; } else if (!renderorderStr.compare("right-up")) { render_order = TMX_RIGHT_UP; } else if (!renderorderStr.compare("left-down")) { render_order = TMX_LEFT_DOWN; } else if (!renderorderStr.compare("left-down")) { render_order = TMX_LEFT_UP; } } const tinyxml2::XMLNode *node = mapElem->FirstChild(); while( node ) { // Read the map properties. if( strcmp( node->Value(), "properties" ) == 0 ) { properties.Parse(node); } // Iterate through all of the tileset elements. if( strcmp( node->Value(), "tileset" ) == 0 ) { // Allocate a new tileset and parse it. Tileset *tileset = new Tileset(); tileset->Parse(node->ToElement()); // Add the tileset to the list. tilesets.push_back(tileset); } // Iterate through all of the "layer" (tile layer) elements. if( strcmp( node->Value(), "layer" ) == 0 ) { // Allocate a new tile layer and parse it. TileLayer *tileLayer = new TileLayer(this); tileLayer->Parse(node); // Add the tile layer to the lists. tile_layers.push_back(tileLayer); layers.push_back(tileLayer); } // Iterate through all of the "imagelayer" (image layer) elements. if( strcmp( node->Value(), "imagelayer" ) == 0 ) { // Allocate a new image layer and parse it. ImageLayer *imageLayer = new ImageLayer(this); imageLayer->Parse(node); // Add the image layer to the lists. image_layers.push_back(imageLayer); layers.push_back(imageLayer); } // Iterate through all of the "objectgroup" (object layer) elements. if( strcmp( node->Value(), "objectgroup" ) == 0 ) { // Allocate a new object group and parse it. ObjectGroup *objectGroup = new ObjectGroup(this); objectGroup->Parse(node); // Add the object group to the lists. object_groups.push_back(objectGroup); layers.push_back(objectGroup); } node = node->NextSibling(); } }
// Generates the main shader code for rendering the terrain. void MPTerrainEngineNode::updateState() { if ( _batchUpdateInProgress ) { _stateUpdateRequired = true; } else { osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); // required for multipass tile rendering to work terrainStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); // install shaders, if we're using them. if ( Registry::capabilities().supportsGLSL() ) { VirtualProgram* vp = new VirtualProgram(); vp->setName( "osgEarth.engine_mp.TerrainNode" ); terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // bind the vertex attributes generated by the tile compiler. vp->addBindAttribLocation( "oe_terrain_attr", osg::Drawable::ATTRIBUTE_6 ); vp->addBindAttribLocation( "oe_terrain_attr2", osg::Drawable::ATTRIBUTE_7 ); // Vertex shader: std::string vs = Stringify() << "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc;\n" "varying vec4 oe_layer_tilec;\n" "void oe_mp_setup_coloring(inout vec4 VertexModel) \n" "{ \n" " oe_layer_texc = gl_MultiTexCoord" << _primaryUnit << ";\n" " oe_layer_tilec = gl_MultiTexCoord" << _secondaryUnit << ";\n" "}\n"; bool useTerrainColor = _terrainOptions.color().isSet(); bool useBlending = _terrainOptions.enableBlending() == true; // Fragment Shader for normal blending: std::string fs = Stringify() << "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc; \n" "uniform sampler2D oe_layer_tex; \n" "uniform int oe_layer_uid; \n" "uniform int oe_layer_order; \n" "uniform float oe_layer_opacity; \n" << (useTerrainColor ? "uniform vec4 oe_terrain_color; \n" : "" ) << "void oe_mp_apply_coloring(inout vec4 color) \n" "{ \n" << (useTerrainColor ? " color = oe_terrain_color; \n" : "" ) << " vec4 texel; \n" " if ( oe_layer_uid >= 0 ) { \n" " texel = texture2D(oe_layer_tex, oe_layer_texc.st); \n" " texel.a *= oe_layer_opacity; \n" " } \n" " else { \n" " texel = color; \n" " }\n" << (useBlending ? " if ( oe_layer_order == 0 ) { \n" " color = texel*texel.a + color*(1.0-texel.a); \n" // simulate src_alpha, 1-src_alpha blens " } \n" " else \n" : "" ) << " color = texel; \n" "} \n"; // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "__COLOR_FILTER_HEAD__" "void oe_mp_apply_filters(inout vec4 color) \n" "{ \n" "__COLOR_FILTER_BODY__" "} \n"; vp->setFunction( "oe_mp_setup_coloring", vs, ShaderComp::LOCATION_VERTEX_MODEL, 0.0 ); vp->setFunction( "oe_mp_apply_coloring", fs, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); // assemble color filter code snippets. bool haveColorFilters = false; { std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; int numImageLayers = _update_mapf->imageLayers().size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = _update_mapf->getImageLayerAt(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( terrainStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "__COLOR_FILTER_HEAD__", cf_head_str ); replaceIn( fs_colorfilters, "__COLOR_FILTER_BODY__", cf_body_str ); vp->setFunction( "oe_mp_apply_filters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); } } // binding for the terrain texture terrainStateSet->getOrCreateUniform( "oe_layer_tex", osg::Uniform::SAMPLER_2D )->set( _primaryUnit ); // binding for the secondary texture (for LOD blending) terrainStateSet->getOrCreateUniform( "oe_layer_tex_parent", osg::Uniform::SAMPLER_2D )->set( _secondaryUnit ); // binding for the default secondary texture matrix osg::Matrixf parent_mat; parent_mat(0,0) = 0.0f; terrainStateSet->getOrCreateUniform( "oe_layer_parent_matrix", osg::Uniform::FLOAT_MAT4 )->set( parent_mat ); // uniform that controls per-layer opacity terrainStateSet->getOrCreateUniform( "oe_layer_opacity", osg::Uniform::FLOAT )->set( 1.0f ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->getOrCreateUniform( "oe_layer_uid", osg::Uniform::INT )->set( -1 ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->getOrCreateUniform( "oe_layer_order", osg::Uniform::INT )->set( 0 ); // base terrain color. if ( useTerrainColor ) { terrainStateSet->getOrCreateUniform( "oe_terrain_color", osg::Uniform::FLOAT_VEC4 )->set( *_terrainOptions.color() ); } } _stateUpdateRequired = false; } }
// Generates the main shader code for rendering the terrain. void MPTerrainEngineNode::updateShaders() { if ( _batchUpdateInProgress ) { _shaderUpdateRequired = true; } else { osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); VirtualProgram* vp = new VirtualProgram(); vp->setName( "engine_mp:TerrainNode" ); terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); // bind the vertex attributes generated by the tile compiler. vp->addBindAttribLocation( "oe_terrain_attr", osg::Drawable::ATTRIBUTE_6 ); vp->addBindAttribLocation( "oe_terrain_attr2", osg::Drawable::ATTRIBUTE_7 ); // Vertex shader template: std::string vs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc;\n" "varying vec4 oe_layer_tilec;\n" "void oe_mp_setup_coloring(inout vec4 VertexModel) \n" "{ \n" " oe_layer_texc = __GL_MULTITEXCOORD1__;\n" " oe_layer_tilec = __GL_MULTITEXCOORD2__;\n" "}\n"; // Fragment shader for normal blending: std::string fs = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc; \n" "uniform sampler2D oe_layer_tex; \n" "uniform int oe_layer_uid; \n" "uniform int oe_layer_order; \n" "uniform float oe_layer_opacity; \n" "void oe_mp_apply_coloring( inout vec4 color ) \n" "{ \n" " vec4 texel; \n" " if ( oe_layer_uid >= 0 ) { \n" " texel = texture2D(oe_layer_tex, oe_layer_texc.st); \n" " texel.a *= oe_layer_opacity; \n" " } \n" " else \n" " texel = color; \n" " if (oe_layer_order == 0 ) \n" " color = texel*texel.a + color*(1.0-texel.a); \n" // simulate src_alpha, 1-src_alpha blens " else \n" " color = texel; \n" "} \n"; // Fragment shader with pre-multiplied alpha blending: std::string fs_pma = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "varying vec4 oe_layer_texc; \n" "uniform sampler2D oe_layer_tex; \n" "uniform int oe_layer_uid; \n" "uniform int oe_layer_order; \n" "uniform float oe_layer_opacity; \n" "void oe_mp_apply_coloring_pma( inout vec4 color ) \n" "{ \n" " vec4 texelpma; \n" // a UID < 0 means no texture. " if ( oe_layer_uid >= 0 ) \n" " texelpma = texture2D(oe_layer_tex, oe_layer_texc.st) * oe_layer_opacity; \n" " else \n" " texelpma = color * color.a * oe_layer_opacity; \n" // to PMA. // first layer must PMA-blend with the globe color. " if (oe_layer_order == 0) { \n" " color.rgb *= color.a; \n" " color = texelpma + color*(1.0-texelpma.a); \n" // simulate one, 1-src_alpha blend " } \n" " else { \n" " color = texelpma; \n" " } \n" "} \n"; // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "__COLOR_FILTER_HEAD__" "void oe_mp_apply_filters(inout vec4 color) \n" "{ \n" "__COLOR_FILTER_BODY__" "} \n"; // install the gl_MultiTexCoord* variable that uses the proper texture // image unit: replaceIn( vs, "__GL_MULTITEXCOORD1__", Stringify() << "gl_MultiTexCoord" << _primaryUnit ); replaceIn( vs, "__GL_MULTITEXCOORD2__", Stringify() << "gl_MultiTexCoord" << _secondaryUnit ); vp->setFunction( "oe_mp_setup_coloring", vs, ShaderComp::LOCATION_VERTEX_MODEL, 0.0 ); if ( _terrainOptions.premultipliedAlpha() == true ) vp->setFunction( "oe_mp_apply_coloring_pma", fs_pma, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); else vp->setFunction( "oe_mp_apply_coloring", fs, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); // assemble color filter code snippets. bool haveColorFilters = false; { std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; if ( _terrainOptions.premultipliedAlpha() == true ) { // un-PMA the color before passing it to the color filters. cf_body << I << "if (color.a > 0.0) color.rgb /= color.a; \n"; } // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; int numImageLayers = _update_mapf->imageLayers().size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = _update_mapf->getImageLayerAt(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( terrainStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( _terrainOptions.premultipliedAlpha() == true ) { // re-PMA the color after it passes through the color filters. cf_body << I << "color.rgb *= color.a; \n"; } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "__COLOR_FILTER_HEAD__", cf_head_str ); replaceIn( fs_colorfilters, "__COLOR_FILTER_BODY__", cf_body_str ); vp->setFunction( "oe_mp_apply_filters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); } } if ( _terrainOptions.premultipliedAlpha() == true ) { // activate PMA blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); } else { // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); } // required for multipass tile rendering to work terrainStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // binding for the terrain texture terrainStateSet->getOrCreateUniform( "oe_layer_tex", osg::Uniform::SAMPLER_2D )->set( _primaryUnit ); // binding for the secondary texture (for LOD blending) terrainStateSet->getOrCreateUniform( "oe_layer_tex_parent", osg::Uniform::SAMPLER_2D )->set( _secondaryUnit ); // uniform that controls per-layer opacity terrainStateSet->getOrCreateUniform( "oe_layer_opacity", osg::Uniform::FLOAT )->set( 1.0f ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->getOrCreateUniform( "oe_layer_uid", osg::Uniform::INT )->set( -1 ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->getOrCreateUniform( "oe_layer_order", osg::Uniform::INT )->set( 0 ); _shaderUpdateRequired = false; } }
void Map::calculateProfile() { if ( !_profile.valid() ) { osg::ref_ptr<const Profile> userProfile; if ( _mapOptions.profile().isSet() ) { userProfile = Profile::create( _mapOptions.profile().value() ); } if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC ) { if ( userProfile.valid() ) { if ( userProfile->isOK() && userProfile->getSRS()->isGeographic() ) { _profile = userProfile.get(); } else { OE_WARN << LC << "Map is geocentric, but the configured profile SRS (" << userProfile->getSRS()->getName() << ") is not geographic; " << "it will be ignored." << std::endl; } } } else if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC_CUBE ) { if ( userProfile.valid() ) { if ( userProfile->isOK() && userProfile->getSRS()->isCube() ) { _profile = userProfile.get(); } else { OE_WARN << LC << "Map is geocentric cube, but the configured profile SRS (" << userProfile->getSRS()->getName() << ") is not geocentric cube; " << "it will be ignored." << std::endl; } } } else // CSTYPE_PROJECTED { if ( userProfile.valid() ) { if ( userProfile->isOK() && userProfile->getSRS()->isProjected() ) { _profile = userProfile.get(); } else { OE_WARN << LC << "Map is projected, but the configured profile SRS (" << userProfile->getSRS()->getName() << ") is not projected; " << "it will be ignored." << std::endl; } } } // At this point, if we don't have a profile we need to search tile sources until we find one. if ( !_profile.valid() ) { Threading::ScopedReadLock lock( _mapDataMutex ); for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end() && !_profile.valid(); i++ ) { ImageLayer* layer = i->get(); if ( layer->getTileSource() ) { _profile = layer->getTileSource()->getProfile(); } } for( ElevationLayerVector::iterator i = _elevationLayers.begin(); i != _elevationLayers.end() && !_profile.valid(); i++ ) { ElevationLayer* layer = i->get(); if ( layer->getTileSource() ) { _profile = layer->getTileSource()->getProfile(); } } } // ensure that the profile we found is the correct kind // convert a geographic profile to Plate Carre if necessary if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC && !( _profile.valid() && _profile->getSRS()->isGeographic() ) ) { // by default, set a geocentric map to use global-geodetic WGS84. _profile = osgEarth::Registry::instance()->getGlobalGeodeticProfile(); } else if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC_CUBE && !( _profile.valid() && _profile->getSRS()->isCube() ) ) { //If the map type is a Geocentric Cube, set the profile to the cube profile. _profile = osgEarth::Registry::instance()->getCubeProfile(); } else if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_PROJECTED && _profile.valid() && _profile->getSRS()->isGeographic() ) { OE_INFO << LC << "Projected map with geographic SRS; activating EQC profile" << std::endl; unsigned u, v; _profile->getNumTiles(0, u, v); const osgEarth::SpatialReference* eqc = _profile->getSRS()->createEquirectangularSRS(); osgEarth::GeoExtent e = _profile->getExtent().transform( eqc ); _profile = osgEarth::Profile::create( eqc, e.xMin(), e.yMin(), e.xMax(), e.yMax(), u, v); } else if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_PROJECTED && !( _profile.valid() && _profile->getSRS()->isProjected() ) ) { // TODO: should there be a default projected profile? _profile = 0; } // finally, fire an event if the profile has been set. if ( _profile.valid() ) { OE_INFO << LC << "Map profile is: " << _profile->toString() << std::endl; for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapInfoEstablished( MapInfo(this) ); } } else { OE_WARN << LC << "Warning, not yet able to establish a map profile!" << std::endl; } } if ( _profile.valid() ) { // tell all the loaded layers what the profile is, as a hint { Threading::ScopedWriteLock lock( _mapDataMutex ); for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end(); i++ ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() == true ) { layer->setTargetProfileHint( _profile.get() ); } } for( ElevationLayerVector::iterator i = _elevationLayers.begin(); i != _elevationLayers.end(); i++ ) { ElevationLayer* layer = i->get(); if ( layer->getEnabled() ) { layer->setTargetProfileHint( _profile.get() ); } } } // create a "proxy" profile to use when querying elevation layers with a vertical datum if ( _profile->getSRS()->getVerticalDatum() != 0L ) { ProfileOptions po = _profile->toProfileOptions(); po.vsrsString().unset(); _profileNoVDatum = Profile::create(po); } else { _profileNoVDatum = _profile; } } }
// Generates the main shader code for rendering the terrain. void MPTerrainEngineNode::updateState() { if ( _batchUpdateInProgress ) { _stateUpdateRequired = true; } else { if ( _elevationTextureUnit < 0 && elevationTexturesRequired() ) { getResources()->reserveTextureImageUnit( _elevationTextureUnit, "MP Engine Elevation" ); } osg::StateSet* terrainStateSet = getTerrainStateSet(); if ( !terrainStateSet ) return; // required for multipass tile rendering to work terrainStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); // install shaders, if we're using them. if ( Registry::capabilities().supportsGLSL() ) { VirtualProgram* vp = new VirtualProgram(); vp->setName( "osgEarth.engine_mp.TerrainNode" ); terrainStateSet->setAttributeAndModes( vp, osg::StateAttribute::ON ); Shaders package; package.replace( "$MP_PRIMARY_UNIT", Stringify() << _primaryUnit ); package.replace( "$MP_SECONDARY_UNIT", Stringify() << (_secondaryUnit>=0?_secondaryUnit:0) ); package.define( "MP_USE_BLENDING", (_terrainOptions.enableBlending() == true) ); package.load( vp, package.EngineVertexModel ); package.load( vp, package.EngineVertexView ); package.load( vp, package.EngineFragment ); if ( this->normalTexturesRequired() ) { package.load( vp, package.NormalMapVertex ); package.load( vp, package.NormalMapFragment ); terrainStateSet->addUniform( new osg::Uniform("oe_tile_normalTex", _normalMapUnit) ); } // terrain background color; negative means use the vertex color. Color terrainColor = _terrainOptions.color().getOrUse( Color(1,1,1,-1) ); terrainStateSet->addUniform(new osg::Uniform("oe_terrain_color", terrainColor)); if ( _update_mapf ) { // assemble color filter code snippets. bool haveColorFilters = false; { // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "$COLOR_FILTER_HEAD" "void oe_mp_apply_filters(inout vec4 color) \n" "{ \n" "$COLOR_FILTER_BODY" "} \n"; std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; // second, install the per-layer color filter functions AND shared layer bindings. ImageLayerVector imageLayers; _update_mapf->getLayers(imageLayers); bool ifStarted = false; int numImageLayers = imageLayers.size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = imageLayers[i].get(); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( terrainStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "$COLOR_FILTER_HEAD", cf_head_str ); replaceIn( fs_colorfilters, "$COLOR_FILTER_BODY", cf_body_str ); vp->setFunction( "oe_mp_apply_filters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.5f ); } } } // binding for the terrain texture terrainStateSet->getOrCreateUniform( "oe_layer_tex", osg::Uniform::SAMPLER_2D )->set( _primaryUnit ); // binding for the secondary texture (for LOD blending) if ( parentTexturesRequired() ) { terrainStateSet->getOrCreateUniform( "oe_layer_tex_parent", osg::Uniform::SAMPLER_2D )->set( _secondaryUnit ); // binding for the default secondary texture matrix osg::Matrixf parent_mat; parent_mat(0,0) = 0.0f; terrainStateSet->getOrCreateUniform( "oe_layer_parent_matrix", osg::Uniform::FLOAT_MAT4 )->set( parent_mat ); } // uniform for accessing the elevation texture sampler. if ( elevationTexturesRequired() ) { terrainStateSet->getOrCreateUniform( "oe_terrain_tex", osg::Uniform::SAMPLER_2D)->set( _elevationTextureUnit ); } // uniform that controls per-layer opacity terrainStateSet->getOrCreateUniform( "oe_layer_opacity", osg::Uniform::FLOAT )->set( 1.0f ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->getOrCreateUniform( "oe_layer_uid", osg::Uniform::INT )->set( -1 ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->getOrCreateUniform( "oe_layer_order", osg::Uniform::INT )->set( 0 ); // default min/max range uniforms. (max < min means ranges are disabled) terrainStateSet->addUniform( new osg::Uniform("oe_layer_minRange", 0.0f) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_maxRange", FLT_MAX) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_attenuationRange", _terrainOptions.attentuationDistance().get()) ); terrainStateSet->getOrCreateUniform( "oe_min_tile_range_factor", osg::Uniform::FLOAT)->set( *_terrainOptions.minTileRangeFactor() ); // special object ID that denotes the terrain surface. terrainStateSet->addUniform( new osg::Uniform( Registry::objectIndex()->getObjectIDUniformName().c_str(), OSGEARTH_OBJECTID_TERRAIN) ); // assign the uniforms for each shared layer. if ( _update_mapf ) { ImageLayerVector imageLayers; _update_mapf->getLayers(imageLayers); int numImageLayers = imageLayers.size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = imageLayers[i].get(); if ( layer->getEnabled() && layer->isShared() ) { terrainStateSet->addUniform( new osg::Uniform( layer->shareTexUniformName()->c_str(), layer->shareImageUnit().get() ) ); } } } } _stateUpdateRequired = false; } }
void Map::calculateProfile() { if ( !_profile.valid() ) { osg::ref_ptr<const Profile> userProfile; if ( _mapOptions.profile().isSet() ) { userProfile = Profile::create( _mapOptions.profile().value() ); } if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC ) { if ( userProfile.valid() ) { if ( userProfile->isOK() && userProfile->getSRS()->isGeographic() ) { _profile = userProfile.get(); } else { OE_WARN << LC << "Map is geocentric, but the configured profile does not " << "have a geographic SRS. Falling back on default.." << std::endl; } } if ( !_profile.valid() ) { // by default, set a geocentric map to use global-geodetic WGS84. _profile = osgEarth::Registry::instance()->getGlobalGeodeticProfile(); } } else if ( _mapOptions.coordSysType() == MapOptions::CSTYPE_GEOCENTRIC_CUBE ) { //If the map type is a Geocentric Cube, set the profile to the cube profile. _profile = osgEarth::Registry::instance()->getCubeProfile(); } else // CSTYPE_PROJECTED { if ( userProfile.valid() ) { _profile = userProfile.get(); } } // At this point, if we don't have a profile we need to search tile sources until we find one. if ( !_profile.valid() ) { Threading::ScopedReadLock lock( _mapDataMutex ); for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end() && !_profile.valid(); i++ ) { ImageLayer* layer = i->get(); if ( layer->getTileSource() ) { _profile = layer->getTileSource()->getProfile(); } } for( ElevationLayerVector::iterator i = _elevationLayers.begin(); i != _elevationLayers.end() && !_profile.valid(); i++ ) { ElevationLayer* layer = i->get(); if ( layer->getTileSource() ) { _profile = layer->getTileSource()->getProfile(); } } } // finally, fire an event if the profile has been set. if ( _profile.valid() ) { OE_INFO << LC << "Map profile is: " << _profile->toString() << std::endl; for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ ) { i->get()->onMapInfoEstablished( MapInfo(this) ); } } else { OE_WARN << LC << "Warning, not yet able to establish a map profile!" << std::endl; } } if ( _profile.valid() ) { // tell all the loaded layers what the profile is, as a hint { Threading::ScopedWriteLock lock( _mapDataMutex ); for( ImageLayerVector::iterator i = _imageLayers.begin(); i != _imageLayers.end(); i++ ) { ImageLayer* layer = i->get(); layer->setTargetProfileHint( _profile.get() ); } for( ElevationLayerVector::iterator i = _elevationLayers.begin(); i != _elevationLayers.end(); i++ ) { ElevationLayer* layer = i->get(); layer->setTargetProfileHint( _profile.get() ); } } // create a "proxy" profile to use when querying elevation layers with a vertical datum if ( _profile->getSRS()->getVerticalDatum() != 0L ) { ProfileOptions po = _profile->toProfileOptions(); po.vsrsString().unset(); _profileNoVDatum = Profile::create(po); } else { _profileNoVDatum = _profile; } // finally, if the map is flat but the SRS is geographic, mark it as "plate carre" if (_profile->getSRS()->isGeographic() && getMapOptions().coordSysType() == MapOptions::CSTYPE_PROJECTED) { OE_INFO << LC << "Projected display with geographic SRS; activating Plate Carre mode" << std::endl; const_cast<Profile*>(_profile.get())->overrideSRS( _profile->getSRS()->createPlateCarreGeographicSRS() ); } } }
// Generates the main shader code for rendering the terrain. void RexTerrainEngineNode::updateState() { if ( _batchUpdateInProgress ) { _stateUpdateRequired = true; } else { osg::StateSet* terrainStateSet = _terrain->getOrCreateStateSet(); // everything osg::StateSet* surfaceStateSet = getSurfaceStateSet(); // just the surface // required for multipass tile rendering to work surfaceStateSet->setAttributeAndModes( new osg::Depth(osg::Depth::LEQUAL, 0, 1, true) ); // activate standard mix blending. terrainStateSet->setAttributeAndModes( new osg::BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA), osg::StateAttribute::ON ); // install patch param if we are tessellation on the GPU. if ( _terrainOptions.gpuTessellation() == true ) { terrainStateSet->setAttributeAndModes( new osg::PatchParameter(3) ); } // install shaders, if we're using them. if ( Registry::capabilities().supportsGLSL() ) { Shaders package; VirtualProgram* terrainVP = VirtualProgram::getOrCreate(terrainStateSet); terrainVP->setName( "Rex Terrain" ); package.load(terrainVP, package.ENGINE_VERT_MODEL); bool useTerrainColor = _terrainOptions.color().isSet(); package.define("OE_REX_USE_TERRAIN_COLOR", useTerrainColor); if ( useTerrainColor ) { surfaceStateSet->addUniform(new osg::Uniform("oe_terrain_color", _terrainOptions.color().get())); } bool useBlending = _terrainOptions.enableBlending().get(); package.define("OE_REX_USE_BLENDING", useBlending); // Funtions that affect only the terrain surface: VirtualProgram* surfaceVP = VirtualProgram::getOrCreate(surfaceStateSet); surfaceVP->setName("Rex Surface"); // Functions that affect the terrain surface only: package.load(surfaceVP, package.ENGINE_VERT_VIEW); package.load(surfaceVP, package.ENGINE_FRAG); // Normal mapping shaders: if ( this->normalTexturesRequired() ) { package.load(surfaceVP, package.NORMAL_MAP_VERT); package.load(surfaceVP, package.NORMAL_MAP_FRAG); } // Morphing? if (_terrainOptions.morphTerrain() == true || _terrainOptions.morphImagery() == true) { package.define("OE_REX_VERTEX_MORPHING", (_terrainOptions.morphTerrain() == true)); package.load(surfaceVP, package.MORPHING_VERT); } for(LandCoverBins::iterator i = _landCoverBins.begin(); i != _landCoverBins.end(); ++i) { osg::StateSet* landCoverStateSet = i->_binProto->getStateSet(); // enable alpha-to-coverage multisampling for vegetation. landCoverStateSet->setMode(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, 1); // uniform that communicates the availability of multisampling. landCoverStateSet->addUniform( new osg::Uniform( "oe_terrain_hasMultiSamples", osg::DisplaySettings::instance()->getMultiSamples()) ); landCoverStateSet->setAttributeAndModes( new osg::BlendFunc(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO), osg::StateAttribute::OVERRIDE ); landCoverStateSet->setAttributeAndModes( new osg::PatchParameter(3) ); } // assemble color filter code snippets. bool haveColorFilters = false; { // Color filter frag function: std::string fs_colorfilters = "#version " GLSL_VERSION_STR "\n" GLSL_DEFAULT_PRECISION_FLOAT "\n" "uniform int oe_layer_uid; \n" "$COLOR_FILTER_HEAD" "void oe_rexEngine_applyFilters(inout vec4 color) \n" "{ \n" "$COLOR_FILTER_BODY" "} \n"; std::stringstream cf_head; std::stringstream cf_body; const char* I = " "; // second, install the per-layer color filter functions AND shared layer bindings. bool ifStarted = false; int numImageLayers = _update_mapf->imageLayers().size(); for( int i=0; i<numImageLayers; ++i ) { ImageLayer* layer = _update_mapf->getImageLayerAt(i); if ( layer->getEnabled() ) { // install Color Filter function calls: const ColorFilterChain& chain = layer->getColorFilters(); if ( chain.size() > 0 ) { haveColorFilters = true; if ( ifStarted ) cf_body << I << "else if "; else cf_body << I << "if "; cf_body << "(oe_layer_uid == " << layer->getUID() << ") {\n"; for( ColorFilterChain::const_iterator j = chain.begin(); j != chain.end(); ++j ) { const ColorFilter* filter = j->get(); cf_head << "void " << filter->getEntryPointFunctionName() << "(inout vec4 color);\n"; cf_body << I << I << filter->getEntryPointFunctionName() << "(color);\n"; filter->install( surfaceStateSet ); } cf_body << I << "}\n"; ifStarted = true; } } } if ( haveColorFilters ) { std::string cf_head_str, cf_body_str; cf_head_str = cf_head.str(); cf_body_str = cf_body.str(); replaceIn( fs_colorfilters, "$COLOR_FILTER_HEAD", cf_head_str ); replaceIn( fs_colorfilters, "$COLOR_FILTER_BODY", cf_body_str ); surfaceVP->setFunction( "oe_rexEngine_applyFilters", fs_colorfilters, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.0 ); } } // Apply uniforms for sampler bindings: OE_DEBUG << LC << "Render Bindings:\n"; for(RenderBindings::const_iterator b = _renderBindings.begin(); b != _renderBindings.end(); ++b) { if ( b->isActive() ) { terrainStateSet->addUniform( new osg::Uniform(b->samplerName().c_str(), b->unit()) ); OE_DEBUG << LC << " > Bound \"" << b->samplerName() << "\" to unit " << b->unit() << "\n"; // Not needed I think //terrainStateSet->addUniform( new osg::Uniform(b->matrixName().c_str(), osg::Matrixf()) ); } } // uniform that controls per-layer opacity terrainStateSet->addUniform( new osg::Uniform("oe_layer_opacity", 1.0f) ); // uniform that conveys the layer UID to the shaders; necessary // for per-layer branching (like color filters) // UID -1 => no image layer (no texture) terrainStateSet->addUniform( new osg::Uniform("oe_layer_uid", (int)-1 ) ); // uniform that conveys the render order, since the shaders // need to know which is the first layer in order to blend properly terrainStateSet->addUniform( new osg::Uniform("oe_layer_order", (int)0) ); // default min/max range uniforms. (max < min means ranges are disabled) terrainStateSet->addUniform( new osg::Uniform("oe_layer_minRange", 0.0f) ); terrainStateSet->addUniform( new osg::Uniform("oe_layer_maxRange", -1.0f) ); terrainStateSet->getOrCreateUniform( "oe_min_tile_range_factor", osg::Uniform::FLOAT)->set( *_terrainOptions.minTileRangeFactor() ); // special object ID that denotes the terrain surface. surfaceStateSet->addUniform( new osg::Uniform( Registry::objectIndex()->getObjectIDUniformName().c_str(), OSGEARTH_OBJECTID_TERRAIN) ); } _stateUpdateRequired = false; } }
void Map::ParseText(const string &text) { // Create a tiny xml document and use it to parse the text. TiXmlDocument doc; doc.Parse(text.c_str()); // Check for parsing errors. if (doc.Error()) { has_error = true; error_code = TMX_PARSING_ERROR; error_text = doc.ErrorDesc(); return; } TiXmlNode *mapNode = doc.FirstChild("map"); TiXmlElement* mapElem = mapNode->ToElement(); // Read the map attributes. mapElem->Attribute("version", &version); mapElem->Attribute("width", &width); mapElem->Attribute("height", &height); mapElem->Attribute("tilewidth", &tile_width); mapElem->Attribute("tileheight", &tile_height); // Read the orientation std::string orientationStr = mapElem->Attribute("orientation"); if (!orientationStr.compare("orthogonal")) { orientation = TMX_MO_ORTHOGONAL; } else if (!orientationStr.compare("isometric")) { orientation = TMX_MO_ISOMETRIC; } else if (!orientationStr.compare("staggered")) { orientation = TMX_MO_STAGGERED; } const TiXmlNode *node = mapElem->FirstChild(); int zOrder = 0; while( node ) { // Read the map properties. if( strcmp( node->Value(), "properties" ) == 0 ) { properties.Parse(node); } // Iterate through all of the tileset elements. if( strcmp( node->Value(), "tileset" ) == 0 ) { // Allocate a new tileset and parse it. Tileset *tileset = new Tileset(); tileset->Parse(node->ToElement()); // Add the tileset to the list. tilesets.push_back(tileset); } // Iterate through all of the layer elements. if( strcmp( node->Value(), "layer" ) == 0 ) { // Allocate a new layer and parse it. Layer *layer = new Layer(this); layer->Parse(node); layer->SetZOrder( zOrder ); ++zOrder; // Add the layer to the list. layers.push_back(layer); } // Iterate through all of the imagen layer elements. if( strcmp( node->Value(), "imagelayer" ) == 0 ) { // Allocate a new layer and parse it. ImageLayer *imageLayer = new ImageLayer(this); imageLayer->Parse(node); imageLayer->SetZOrder( zOrder ); ++zOrder; // Add the layer to the list. image_layers.push_back(imageLayer); } // Iterate through all of the objectgroup elements. if( strcmp( node->Value(), "objectgroup" ) == 0 ) { // Allocate a new object group and parse it. ObjectGroup *objectGroup = new ObjectGroup(); objectGroup->Parse(node); objectGroup->SetZOrder( zOrder ); ++zOrder; // Add the object group to the list. object_groups.push_back(objectGroup); } node = node->NextSibling(); } }
dimension_t cols(const ImageLayer& img) { return img.num_cols(); }
dimension_t rows(const ImageLayer& img) { return img.num_rows(); }
bool LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset, const TargetConfig& targetConfig, const bool& isFirstPaint, InfallibleTArray<EditReply>* reply) { #ifdef COMPOSITOR_PERFORMANCE_WARNING TimeStamp updateStart = TimeStamp::Now(); #endif MOZ_LAYERS_LOG(("[ParentSide] received txn with %d edits", cset.Length())); if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) { return true; } EditReplyVector replyv; layer_manager()->BeginTransactionWithTarget(NULL); for (EditArray::index_type i = 0; i < cset.Length(); ++i) { const Edit& edit = cset[i]; switch (edit.type()) { // Create* ops case Edit::TOpCreateThebesLayer: { MOZ_LAYERS_LOG(("[ParentSide] CreateThebesLayer")); nsRefPtr<ThebesLayerComposite> layer = layer_manager()->CreateThebesLayerComposite(); AsLayerComposite(edit.get_OpCreateThebesLayer())->Bind(layer); break; } case Edit::TOpCreateContainerLayer: { MOZ_LAYERS_LOG(("[ParentSide] CreateContainerLayer")); nsRefPtr<ContainerLayer> layer = layer_manager()->CreateContainerLayerComposite(); AsLayerComposite(edit.get_OpCreateContainerLayer())->Bind(layer); break; } case Edit::TOpCreateImageLayer: { MOZ_LAYERS_LOG(("[ParentSide] CreateImageLayer")); nsRefPtr<ImageLayerComposite> layer = layer_manager()->CreateImageLayerComposite(); AsLayerComposite(edit.get_OpCreateImageLayer())->Bind(layer); break; } case Edit::TOpCreateColorLayer: { MOZ_LAYERS_LOG(("[ParentSide] CreateColorLayer")); nsRefPtr<ColorLayerComposite> layer = layer_manager()->CreateColorLayerComposite(); AsLayerComposite(edit.get_OpCreateColorLayer())->Bind(layer); break; } case Edit::TOpCreateCanvasLayer: { MOZ_LAYERS_LOG(("[ParentSide] CreateCanvasLayer")); nsRefPtr<CanvasLayerComposite> layer = layer_manager()->CreateCanvasLayerComposite(); AsLayerComposite(edit.get_OpCreateCanvasLayer())->Bind(layer); break; } case Edit::TOpCreateRefLayer: { MOZ_LAYERS_LOG(("[ParentSide] CreateRefLayer")); nsRefPtr<RefLayerComposite> layer = layer_manager()->CreateRefLayerComposite(); AsLayerComposite(edit.get_OpCreateRefLayer())->Bind(layer); break; } // Attributes case Edit::TOpSetLayerAttributes: { MOZ_LAYERS_LOG(("[ParentSide] SetLayerAttributes")); const OpSetLayerAttributes& osla = edit.get_OpSetLayerAttributes(); Layer* layer = AsLayerComposite(osla)->AsLayer(); const LayerAttributes& attrs = osla.attrs(); const CommonLayerAttributes& common = attrs.common(); layer->SetVisibleRegion(common.visibleRegion()); layer->SetContentFlags(common.contentFlags()); layer->SetOpacity(common.opacity()); layer->SetClipRect(common.useClipRect() ? &common.clipRect() : NULL); layer->SetBaseTransform(common.transform().value()); layer->SetPostScale(common.postXScale(), common.postYScale()); layer->SetIsFixedPosition(common.isFixedPosition()); layer->SetFixedPositionAnchor(common.fixedPositionAnchor()); layer->SetFixedPositionMargins(common.fixedPositionMargin()); if (PLayerParent* maskLayer = common.maskLayerParent()) { layer->SetMaskLayer(cast(maskLayer)->AsLayer()); } else { layer->SetMaskLayer(NULL); } layer->SetAnimations(common.animations()); typedef SpecificLayerAttributes Specific; const SpecificLayerAttributes& specific = attrs.specific(); switch (specific.type()) { case Specific::Tnull_t: break; case Specific::TThebesLayerAttributes: { MOZ_LAYERS_LOG(("[ParentSide] thebes layer")); ThebesLayerComposite* thebesLayer = static_cast<ThebesLayerComposite*>(layer); const ThebesLayerAttributes& attrs = specific.get_ThebesLayerAttributes(); thebesLayer->SetValidRegion(attrs.validRegion()); break; } case Specific::TContainerLayerAttributes: { MOZ_LAYERS_LOG(("[ParentSide] container layer")); ContainerLayer* containerLayer = static_cast<ContainerLayer*>(layer); const ContainerLayerAttributes& attrs = specific.get_ContainerLayerAttributes(); containerLayer->SetFrameMetrics(attrs.metrics()); containerLayer->SetPreScale(attrs.preXScale(), attrs.preYScale()); containerLayer->SetInheritedScale(attrs.inheritedXScale(), attrs.inheritedYScale()); break; } case Specific::TColorLayerAttributes: MOZ_LAYERS_LOG(("[ParentSide] color layer")); static_cast<ColorLayer*>(layer)->SetColor( specific.get_ColorLayerAttributes().color().value()); break; case Specific::TCanvasLayerAttributes: MOZ_LAYERS_LOG(("[ParentSide] canvas layer")); static_cast<CanvasLayer*>(layer)->SetFilter( specific.get_CanvasLayerAttributes().filter()); static_cast<CanvasLayerComposite*>(layer)->SetBounds( specific.get_CanvasLayerAttributes().bounds()); break; case Specific::TRefLayerAttributes: MOZ_LAYERS_LOG(("[ParentSide] ref layer")); static_cast<RefLayer*>(layer)->SetReferentId( specific.get_RefLayerAttributes().id()); break; case Specific::TImageLayerAttributes: { MOZ_LAYERS_LOG(("[ParentSide] image layer")); ImageLayer* imageLayer = static_cast<ImageLayer*>(layer); const ImageLayerAttributes& attrs = specific.get_ImageLayerAttributes(); imageLayer->SetFilter(attrs.filter()); imageLayer->SetScaleToSize(attrs.scaleToSize(), attrs.scaleMode()); break; } default: NS_RUNTIMEABORT("not reached"); } break; } case Edit::TOpSetColoredBorders: { if (edit.get_OpSetColoredBorders().enabled()) { mLayerManager->GetCompositor()->EnableColoredBorders(); } else { mLayerManager->GetCompositor()->DisableColoredBorders(); } break; } // Tree ops case Edit::TOpSetRoot: { MOZ_LAYERS_LOG(("[ParentSide] SetRoot")); mRoot = AsLayerComposite(edit.get_OpSetRoot())->AsContainer(); break; } case Edit::TOpInsertAfter: { MOZ_LAYERS_LOG(("[ParentSide] InsertAfter")); const OpInsertAfter& oia = edit.get_OpInsertAfter(); ShadowContainer(oia)->AsContainer()->InsertAfter( ShadowChild(oia)->AsLayer(), ShadowAfter(oia)->AsLayer()); break; } case Edit::TOpAppendChild: { MOZ_LAYERS_LOG(("[ParentSide] AppendChild")); const OpAppendChild& oac = edit.get_OpAppendChild(); ShadowContainer(oac)->AsContainer()->InsertAfter( ShadowChild(oac)->AsLayer(), NULL); break; } case Edit::TOpRemoveChild: { MOZ_LAYERS_LOG(("[ParentSide] RemoveChild")); const OpRemoveChild& orc = edit.get_OpRemoveChild(); Layer* childLayer = ShadowChild(orc)->AsLayer(); ShadowContainer(orc)->AsContainer()->RemoveChild(childLayer); break; } case Edit::TOpRepositionChild: { MOZ_LAYERS_LOG(("[ParentSide] RepositionChild")); const OpRepositionChild& orc = edit.get_OpRepositionChild(); ShadowContainer(orc)->AsContainer()->RepositionChild( ShadowChild(orc)->AsLayer(), ShadowAfter(orc)->AsLayer()); break; } case Edit::TOpRaiseToTopChild: { MOZ_LAYERS_LOG(("[ParentSide] RaiseToTopChild")); const OpRaiseToTopChild& rtc = edit.get_OpRaiseToTopChild(); ShadowContainer(rtc)->AsContainer()->RepositionChild( ShadowChild(rtc)->AsLayer(), NULL); break; } case Edit::TCompositableOperation: { ReceiveCompositableUpdate(edit.get_CompositableOperation(), replyv); break; } case Edit::TOpAttachCompositable: { const OpAttachCompositable& op = edit.get_OpAttachCompositable(); Attach(cast(op.layerParent()), cast(op.compositableParent())); break; } case Edit::TOpAttachAsyncCompositable: { const OpAttachAsyncCompositable& op = edit.get_OpAttachAsyncCompositable(); CompositableParent* compositableParent = CompositableMap::Get(op.containerID()); MOZ_ASSERT(compositableParent, "CompositableParent not found in the map"); Attach(cast(op.layerParent()), compositableParent); compositableParent->SetCompositorID(mLayerManager->GetCompositor()->GetCompositorID()); break; } default: NS_RUNTIMEABORT("not reached"); } } layer_manager()->EndTransaction(NULL, NULL, LayerManager::END_NO_IMMEDIATE_REDRAW); if (reply) { reply->SetCapacity(replyv.size()); if (replyv.size() > 0) { reply->AppendElements(&replyv.front(), replyv.size()); } } // Ensure that any pending operations involving back and front // buffers have completed, so that neither process stomps on the // other's buffer contents. LayerManagerComposite::PlatformSyncBeforeReplyUpdate(); mShadowLayersManager->ShadowLayersUpdated(this, targetConfig, isFirstPaint); #ifdef COMPOSITOR_PERFORMANCE_WARNING int compositeTime = (int)(mozilla::TimeStamp::Now() - updateStart).ToMilliseconds(); if (compositeTime > 15) { printf_stderr("Compositor: Layers update took %i ms (blocking gecko).\n", compositeTime); } #endif return true; }
void TileBuilder::createTile(const TileKey& key, bool parallelize, osg::ref_ptr<Tile>& out_tile, bool& out_hasRealData, bool& out_hasLodBlendedLayers ) { MapFrame mapf( _map, Map::MASKED_TERRAIN_LAYERS ); SourceRepo repo; // init this to false, then search for real data. "Real data" is data corresponding // directly to the key, as opposed to fallback data, which is derived from a lower // LOD key. out_hasRealData = false; out_hasLodBlendedLayers = false; const MapInfo& mapInfo = mapf.getMapInfo(); // If we need more than one layer, fetch them in parallel. // TODO: change the test based on isKeyValid total. if ( parallelize && (mapf.imageLayers().size() + mapf.elevationLayers().size() > 1) ) { // count the valid layers. int jobCount = 0; for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { if ( i->get()->isKeyValid( key ) ) ++jobCount; if ( i->get()->getImageLayerOptions().lodBlending() == true ) out_hasLodBlendedLayers = true; } if ( mapf.elevationLayers().size() > 0 ) ++jobCount; // A thread job monitoring event: Threading::MultiEvent semaphore( jobCount ); // Start the image layer jobs: for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->isKeyValid(key) ) { ParallelTask<BuildColorLayer>* j = new ParallelTask<BuildColorLayer>( &semaphore ); j->init( key, layer, mapInfo, _terrainOptions, repo ); j->setPriority( -(float)key.getLevelOfDetail() ); _service->add( j ); } } // If we have elevation layers, start an elevation job as well. Otherwise just create an // empty one while we're waiting for the images to load. if ( mapf.elevationLayers().size() > 0 ) { ParallelTask<BuildElevLayer>* ej = new ParallelTask<BuildElevLayer>( &semaphore ); ej->init( key, mapf, _terrainOptions, repo ); ej->setPriority( -(float)key.getLevelOfDetail() ); _service->add( ej ); } else { BuildElevLayer build; build.init( key, mapf, _terrainOptions, repo ); build.execute(); } // Wait for all the jobs to finish. semaphore.wait(); } // Fetch the image data serially: else { // gather all the image layers serially. for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->isKeyValid(key) ) { BuildColorLayer build; build.init( key, layer, mapInfo, _terrainOptions, repo ); build.execute(); } if ( layer->getImageLayerOptions().lodBlending() == true ) out_hasLodBlendedLayers = true; } // make an elevation layer. BuildElevLayer build; build.init( key, mapf, _terrainOptions, repo ); build.execute(); } // Bail out now if there's no data to be had. if ( repo._colorLayers.size() == 0 && !repo._elevLayer.getHFLayer() ) { return; } // OK we are making a tile, so if there's no heightfield yet, make an empty one. if ( !repo._elevLayer.getHFLayer() ) { osg::HeightField* hf = key.getProfile()->getVerticalSRS()->createReferenceHeightField( key.getExtent(), 8, 8 ); osgTerrain::HeightFieldLayer* hfLayer = new osgTerrain::HeightFieldLayer( hf ); hfLayer->setLocator( GeoLocator::createForKey(key, mapInfo) ); repo._elevLayer = CustomElevLayer( hfLayer, true ); } // Now, if there are any color layers that did not get built, create them with an empty // image so the shaders have something to draw. osg::ref_ptr<osg::Image> emptyImage; osgTerrain::Locator* locator = repo._elevLayer.getHFLayer()->getLocator(); for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { if ( !i->get()->isKeyValid(key) ) { if ( !emptyImage.valid() ) emptyImage = ImageUtils::createEmptyImage(); repo.add( CustomColorLayer( i->get(), emptyImage.get(), locator, key.getLevelOfDetail(), key, true ) ); } } //osg::Vec3dArray* maskBounds = 0L; //osgEarth::MaskLayer* mask = mapf.getTerrainMaskLayer(); //if (mask) // maskBounds = mask->getOrCreateBoundary(); // Ready to create the actual tile. AssembleTile assemble; assemble.init( key, mapInfo, _terrainOptions, repo, mapf.terrainMaskLayers() ); assemble.execute(); if (!out_hasRealData) { // Check the results and see if we have any real data. for( ColorLayersByUID::const_iterator i = repo._colorLayers.begin(); i != repo._colorLayers.end(); ++i ) { if ( !i->second.isFallbackData() ) { out_hasRealData = true; break; } } } if ( !out_hasRealData && !repo._elevLayer.isFallbackData() ) { out_hasRealData = true; } out_tile = assemble._tile; }
// called from the UPDATE TRAVERSAL, because this method can potentially alter // the scene graph. bool StreamingTile::serviceCompletedRequests( const MapFrame& mapf, bool tileTableLocked ) { //Don't do anything until we have been added to the scene graph if (!_hasBeenTraversed) return false; bool tileModified = false; if ( !_requestsInstalled ) return false; // First service the tile generator: if ( _tileGenRequest.valid() && _tileGenRequest->isCompleted() ) { CustomTerrainTechnique* tech = dynamic_cast<CustomTerrainTechnique*>( getTerrainTechnique() ); if ( tech ) { //TODO: consider waiting to apply if there are still more tile updates in the queue. if ( _tileUpdates.size() == 0 ) { tileModified = tech->applyTileUpdates(); } } _tileGenRequest = 0L; } // now deal with imagery. const LoadingPolicy& lp = getStreamingTerrain()->getLoadingPolicy(); StreamingTerrainNode* terrain = getStreamingTerrain(); //Check each layer independently. for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* imageLayer = i->get(); bool checkForFinalImagery = false; CustomColorLayer colorLayer; if ( getCustomColorLayer( imageLayer->getUID(), colorLayer ) ) { if ( lp.mode() == LoadingPolicy::MODE_PREEMPTIVE ) { // in preemptive mode, always check for the final imagery - there are no intermediate // placeholders. checkForFinalImagery = true; } else if (lp.mode() == LoadingPolicy::MODE_SEQUENTIAL && readyForNewImagery(imageLayer, colorLayer.getLevelOfDetail()) ) { // in sequential mode, we have to incrementally increase imagery resolution by // creating placeholders based of parent tiles, one LOD at a time. if ( colorLayer.getLevelOfDetail() + 1 < (int)_key.getLevelOfDetail() ) { // if the parent's image LOD is higher than ours, replace ours with the parent's // since it is a higher-resolution placeholder: if ( _family[Relative::PARENT].getImageLOD(colorLayer.getUID()) > colorLayer.getLevelOfDetail() ) { osg::ref_ptr<Tile> parentTile; getStreamingTerrain()->getTile( _family[Relative::PARENT].tileID, parentTile, !tileTableLocked ); // Set the color layer to the parent color layer as a placeholder. CustomColorLayer parentColorLayer; if ( parentTile->getCustomColorLayer( colorLayer.getUID(), parentColorLayer ) ) { this->setCustomColorLayer( parentColorLayer ); } // ... and queue up an update request. queueTileUpdate( TileUpdate::UPDATE_IMAGE_LAYER, colorLayer.getUID() ); } } else { // we've gone as far as we can with placeholders; time to check for the // final imagery tile. checkForFinalImagery = true; } } } if ( checkForFinalImagery ) { // Then the image requests: for( TaskRequestList::iterator itr = _requests.begin(); itr != _requests.end(); ) { bool increment = true; TileColorLayerRequest* r = static_cast<TileColorLayerRequest*>( itr->get() ); //We only care about the current layer we are checking if ( r->_layerUID == imageLayer->getUID() ) { if ( itr->get()->isCompleted() ) { if ( r->wasCanceled() ) { //Reset the cancelled task to IDLE and give it a new progress callback. r->setState( TaskRequest::STATE_IDLE ); r->setProgressCallback( new StampedProgressCallback( r, terrain->getImageryTaskService( r->_layerUID ))); r->reset(); } else // success.. { //See if we even care about the request if ( !mapf.getImageLayerByUID( r->_layerUID ) ) { //The maplayer was probably deleted OE_DEBUG << "Layer uid=" << r->_layerUID << " no longer exists, ignoring TileColorLayerRequest " << std::endl; itr = _requests.erase(itr); increment = false; } else { CustomColorLayerRef* result = static_cast<CustomColorLayerRef*>( r->getResult() ); if ( result ) { this->setCustomColorLayer( result->_layer ); queueTileUpdate( TileUpdate::UPDATE_IMAGE_LAYER, r->_layerUID ); //OE_NOTICE << "Complete IR (" << _key.str() << ") layer=" << r->_layerId << std::endl; // remove from the list (don't reference "r" after this!) itr = _requests.erase( itr ); increment = false; } else { if (r->_numTries > r->_maxTries) { CustomColorLayer oldLayer; if ( this->getCustomColorLayer( r->_layerUID, oldLayer ) ) { // apply the old color layer but with a new LOD. this->setCustomColorLayer( CustomColorLayer( oldLayer.getMapLayer(), oldLayer.getImage(), oldLayer.getLocator(), _key.getLevelOfDetail(), _key )); itr = _requests.erase( itr ); increment = false; OE_DEBUG << "Tried (" << _key.str() << ") (layer uid=" << r->_layerUID << "), too many times, moving on...." << std::endl; } } else { OE_DEBUG << "IReq error (" << _key.str() << ") (layer uid=" << r->_layerUID << "), retrying" << std::endl; //The color layer request failed, probably due to a server error. Reset it. r->setState( TaskRequest::STATE_IDLE ); r->reset(); } } } } } } if ( increment ) ++itr; } } } // Finally, the elevation requests: if ( _hasElevation && !_elevationLayerUpToDate && _elevRequest.valid() && _elevPlaceholderRequest.valid() ) { // First, check is the Main elevation request is done. If so, we will now have the final HF data // and can shut down the elevation requests for this tile. if ( _elevRequest->isCompleted() ) { if ( _elevRequest->wasCanceled() ) { // If the request was canceled, reset it to IDLE and reset the callback. On the next _elevRequest->setState( TaskRequest::STATE_IDLE ); _elevRequest->setProgressCallback( new ProgressCallback() ); _elevRequest->reset(); } else // success: { // if the elevation request succeeded, install the new elevation layer! TileElevationLayerRequest* r = static_cast<TileElevationLayerRequest*>( _elevRequest.get() ); osg::ref_ptr<osgTerrain::HeightFieldLayer> newHFLayer = static_cast<osgTerrain::HeightFieldLayer*>( r->getResult() ); if ( newHFLayer.valid() && newHFLayer->getHeightField() != NULL ) { newHFLayer->getHeightField()->setSkirtHeight( terrain->getTileFactory()->getTerrainOptions().heightFieldSkirtRatio().get() * this->getBound().radius() ); // need to write-lock the layer data since we'll be changing it: { Threading::ScopedWriteLock lock( _tileLayersMutex ); this->setElevationLayer( newHFLayer.get() ); this->dirtyBound(); } // the tile needs rebuilding. This will kick off a TileGenRequest. queueTileUpdate( TileUpdate::UPDATE_ELEVATION ); // finalize the LOD marker for this tile, so other tiles can see where we are. _elevationLOD = _key.getLevelOfDetail(); #ifdef PREEMPTIVE_DEBUG OE_NOTICE << "Tile (" << _key.str() << ") final HF, LOD (" << _elevationLOD << ")" << std::endl; #endif // this was the final elev request, so mark elevation as DONE. _elevationLayerUpToDate = true; // GW- just reset these and leave them alone and let cancelRequests() take care of cleanup later. // done with our Elevation requests! //_elevRequest = 0L; //_elevPlaceholderRequest = 0L; } else { //We've tried to get the tile's elevation but couldn't. Just mark the elevation layer as up to date and move on. _elevationLOD = _key.getLevelOfDetail(); _elevationLayerUpToDate = true; //This code will retry indefinitely. We need to have a way to limit the number of retries since //it will block neighbor tiles from loading. //_elevRequest->setState( TaskRequest::STATE_IDLE ); //_elevRequest->reset(); } } } else if ( _elevPlaceholderRequest->isCompleted() ) { TileElevationPlaceholderLayerRequest* r = static_cast<TileElevationPlaceholderLayerRequest*>(_elevPlaceholderRequest.get()); if ( r->wasCanceled() ) { r->setState( TaskRequest::STATE_IDLE ); r->setProgressCallback( new ProgressCallback() ); r->reset(); } else // success: { osg::ref_ptr<osgTerrain::HeightFieldLayer> newPhLayer = static_cast<osgTerrain::HeightFieldLayer*>( r->getResult() ); if ( newPhLayer.valid() && newPhLayer->getHeightField() != NULL ) { // install the new elevation layer. { Threading::ScopedWriteLock lock( _tileLayersMutex ); this->setElevationLayer( newPhLayer.get() ); this->dirtyBound(); } // tile needs to be recompiled. queueTileUpdate( TileUpdate::UPDATE_ELEVATION ); // update the elevation LOD for this tile, now that the new HF data is installed. This will // allow other tiles to see where this tile's HF data is. _elevationLOD = r->_nextLOD; #ifdef PREEMPTIVE_DEBUG OE_NOTICE << "..tile (" << _key.str() << ") is now at (" << _elevationLOD << ")" << std::endl; #endif } _elevPlaceholderRequest->setState( TaskRequest::STATE_IDLE ); _elevPlaceholderRequest->reset(); } } } // if we have a new TileGenRequest, queue it up now. if ( _tileUpdates.size() > 0 && !_tileGenRequest.valid() ) // _tileGenNeeded && !_tileGenRequest.valid()) { _tileGenRequest = new TileGenRequest( this, _tileUpdates.front() ); _tileUpdates.pop(); //OE_NOTICE << "tile (" << _key.str() << ") queuing new tile gen" << std::endl; getStreamingTerrain()->getTileGenerationTaskService()->add( _tileGenRequest.get() ); } return tileModified; }
void TileModelFactory::createTileModel(const TileKey& key, osg::ref_ptr<TileModel>& out_model, bool& out_hasRealData, bool& out_hasLodBlendedLayers ) { MapFrame mapf( _map, Map::MASKED_TERRAIN_LAYERS ); const MapInfo& mapInfo = mapf.getMapInfo(); osg::ref_ptr<TileModel> model = new TileModel(); model->_tileKey = key; model->_tileLocator = GeoLocator::createForKey(key, mapInfo); // init this to false, then search for real data. "Real data" is data corresponding // directly to the key, as opposed to fallback data, which is derived from a lower // LOD key. out_hasRealData = false; out_hasLodBlendedLayers = false; // Fetch the image data and make color layers. for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() ) { BuildColorData build; build.init( key, layer, mapInfo, _terrainOptions, model.get() ); build.execute(); if ( layer->getImageLayerOptions().lodBlending() == true ) { out_hasLodBlendedLayers = true; } } } // make an elevation layer. BuildElevationData build; build.init( key, mapf, _terrainOptions, model.get(), _hfCache ); build.execute(); // Bail out now if there's no data to be had. if ( model->_colorData.size() == 0 && !model->_elevationData.getHFLayer() ) { return; } // OK we are making a tile, so if there's no heightfield yet, make an empty one. if ( !model->_elevationData.getHFLayer() ) { osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 8, 8 ); osgTerrain::HeightFieldLayer* hfLayer = new osgTerrain::HeightFieldLayer( hf ); hfLayer->setLocator( GeoLocator::createForKey(key, mapInfo) ); model->_elevationData = TileModel::ElevationData( hfLayer, true ); } // Now, if there are any color layers that did not get built, create them with an empty // image so the shaders have something to draw. osg::ref_ptr<osg::Image> emptyImage; osgTerrain::Locator* locator = model->_elevationData.getHFLayer()->getLocator(); for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() && !layer->isKeyValid(key) ) { if ( !emptyImage.valid() ) emptyImage = ImageUtils::createEmptyImage(); model->_colorData[i->get()->getUID()] = TileModel::ColorData( layer, emptyImage.get(), locator, key.getLevelOfDetail(), key, true ); } } // Ready to create the actual tile. //AssembleTile assemble; //assemble.init( key, mapInfo, _terrainOptions, model.get(), mapf.terrainMaskLayers() ); //assemble.execute(); // if we're using LOD blending, find and add the parent's state set. if ( out_hasLodBlendedLayers && key.getLevelOfDetail() > 0 && _liveTiles.valid() ) { osg::ref_ptr<TileNode> parent; if ( _liveTiles->get( key.createParentKey(), parent ) ) { model->_parentStateSet = parent->getPublicStateSet(); } } if (!out_hasRealData) { // Check the results and see if we have any real data. for( TileModel::ColorDataByUID::const_iterator i = model->_colorData.begin(); i != model->_colorData.end(); ++i ) { if ( !i->second.isFallbackData() ) { out_hasRealData = true; break; } } } if ( !out_hasRealData && !model->_elevationData.isFallbackData() ) { out_hasRealData = true; } out_model = model.release(); //out_tile = assemble._node; }
void TileModelFactory::createTileModel(const TileKey& key, const MapFrame& frame, osg::ref_ptr<TileModel>& out_model, ProgressCallback* progress) { osg::ref_ptr<TileModel> model = new TileModel( frame.getRevision(), frame.getMapInfo() ); model->_tileKey = key; model->_tileLocator = GeoLocator::createForKey(key, frame.getMapInfo()); OE_START_TIMER(fetch_imagery); // Fetch the image data and make color layers. unsigned index = 0; unsigned order = 0; for( ImageLayerVector::const_iterator i = frame.imageLayers().begin(); i != frame.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() ) { BuildColorData build; build.init( key, layer, order, frame.getMapInfo(), _terrainOptions, _liveTiles.get(), model.get() ); bool addedToModel = build.execute(progress); if ( addedToModel ) { // only bump the order if we added something to the data model. order++; } } } if (progress) progress->stats()["fetch_imagery_time"] += OE_STOP_TIMER(fetch_imagery); OE_START_TIMER(fetch_elevation); // make an elevation layer. BuildElevationData build; build.init( key, frame, _terrainOptions, _liveTiles.get(), model.get(), _hfCache.get() ); build.execute(progress); if (progress) progress->stats()["fetch_elevation_time"] += OE_STOP_TIMER(fetch_elevation); // If nothing was added, not even a fallback heightfield, something went // horribly wrong. Leave without a tile model. Chances are that a parent tile // not not found in the live-tile registry. if ( model->_colorData.size() == 0 && !model->_elevationData.getHeightField() ) { return; } // OK we are making a tile, so if there's no heightfield yet, make an empty one (and mark it // as fallback data of course) if ( !model->_elevationData.getHeightField() ) { osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 15, 15 ); model->_elevationData = TileModel::ElevationData( hf, GeoLocator::createForKey(key, frame.getMapInfo()), true ); } // look up the parent model and cache it. osg::ref_ptr<TileNode> parentTile; if ( _liveTiles->get(key.createParentKey(), parentTile) ) model->_parentModel = parentTile->getTileModel(); out_model = model.release(); }
bool HwcComposer2D::PrepareLayerList(Layer* aLayer, const nsIntRect& aClip, const Matrix& aParentTransform, bool aFindSidebandStreams) { // NB: we fall off this path whenever there are container layers // that require intermediate surfaces. That means all the // GetEffective*() coordinates are relative to the framebuffer. bool fillColor = false; const nsIntRegion visibleRegion = aLayer->GetLocalVisibleRegion().ToUnknownRegion(); if (visibleRegion.IsEmpty()) { return true; } uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0)); if (opacity == 0) { LOGD("%s Layer has zero opacity; skipping", aLayer->Name()); return true; } if (!mHal->SupportTransparency() && opacity < 0xFF && !aFindSidebandStreams) { LOGD("%s Layer has planar semitransparency which is unsupported by hwcomposer", aLayer->Name()); return false; } if (aLayer->GetMaskLayer() && !aFindSidebandStreams) { LOGD("%s Layer has MaskLayer which is unsupported by hwcomposer", aLayer->Name()); return false; } nsIntRect clip; nsIntRect layerClip = aLayer->GetLocalClipRect().valueOr(ParentLayerIntRect()).ToUnknownRect(); nsIntRect* layerClipPtr = aLayer->GetLocalClipRect() ? &layerClip : nullptr; if (!HwcUtils::CalculateClipRect(aParentTransform, layerClipPtr, aClip, &clip)) { LOGD("%s Clip rect is empty. Skip layer", aLayer->Name()); return true; } // HWC supports only the following 2D transformations: // // Scaling via the sourceCrop and displayFrame in HwcLayer // Translation via the sourceCrop and displayFrame in HwcLayer // Rotation (in square angles only) via the HWC_TRANSFORM_ROT_* flags // Reflection (horizontal and vertical) via the HWC_TRANSFORM_FLIP_* flags // // A 2D transform with PreservesAxisAlignedRectangles() has all the attributes // above Matrix layerTransform; if (!aLayer->GetEffectiveTransform().Is2D(&layerTransform) || !layerTransform.PreservesAxisAlignedRectangles()) { LOGD("Layer EffectiveTransform has a 3D transform or a non-square angle rotation"); return false; } Matrix layerBufferTransform; if (!aLayer->GetEffectiveTransformForBuffer().Is2D(&layerBufferTransform) || !layerBufferTransform.PreservesAxisAlignedRectangles()) { LOGD("Layer EffectiveTransformForBuffer has a 3D transform or a non-square angle rotation"); return false; } if (ContainerLayer* container = aLayer->AsContainerLayer()) { if (container->UseIntermediateSurface() && !aFindSidebandStreams) { LOGD("Container layer needs intermediate surface"); return false; } AutoTArray<Layer*, 12> children; container->SortChildrenBy3DZOrder(children); for (uint32_t i = 0; i < children.Length(); i++) { if (!PrepareLayerList(children[i], clip, layerTransform, aFindSidebandStreams) && !aFindSidebandStreams) { return false; } } return true; } LayerRenderState state = aLayer->GetRenderState(); #if ANDROID_VERSION >= 21 if (!state.GetGrallocBuffer() && !state.GetSidebandStream().IsValid()) { #else if (!state.GetGrallocBuffer()) { #endif if (aLayer->AsColorLayer() && mColorFill) { fillColor = true; } else { LOGD("%s Layer doesn't have a gralloc buffer", aLayer->Name()); return false; } } nsIntRect visibleRect = visibleRegion.GetBounds(); nsIntRect bufferRect; if (fillColor) { bufferRect = nsIntRect(visibleRect); } else { nsIntRect layerRect; if (state.mHasOwnOffset) { bufferRect = nsIntRect(state.mOffset.x, state.mOffset.y, state.mSize.width, state.mSize.height); layerRect = bufferRect; } else { //Since the buffer doesn't have its own offset, assign the whole //surface size as its buffer bounds bufferRect = nsIntRect(0, 0, state.mSize.width, state.mSize.height); layerRect = bufferRect; if (aLayer->GetType() == Layer::TYPE_IMAGE) { ImageLayer* imageLayer = static_cast<ImageLayer*>(aLayer); if(imageLayer->GetScaleMode() != ScaleMode::SCALE_NONE) { layerRect = nsIntRect(0, 0, imageLayer->GetScaleToSize().width, imageLayer->GetScaleToSize().height); } } } // In some cases the visible rect assigned to the layer can be larger // than the layer's surface, e.g., an ImageLayer with a small Image // in it. visibleRect.IntersectRect(visibleRect, layerRect); } // Buffer rotation is not to be confused with the angled rotation done by a transform matrix // It's a fancy PaintedLayer feature used for scrolling if (state.BufferRotated()) { LOGD("%s Layer has a rotated buffer", aLayer->Name()); return false; } const bool needsYFlip = state.OriginBottomLeft() ? true : false; hwc_rect_t sourceCrop, displayFrame; if(!HwcUtils::PrepareLayerRects(visibleRect, layerTransform, layerBufferTransform, clip, bufferRect, needsYFlip, &(sourceCrop), &(displayFrame))) { return true; } // OK! We can compose this layer with hwc. int current = mList ? mList->numHwLayers : 0; // Do not compose any layer below full-screen Opaque layer // Note: It can be generalized to non-fullscreen Opaque layers. bool isOpaque = opacity == 0xFF && (state.mFlags & LayerRenderStateFlags::OPAQUE); // Currently we perform opacity calculation using the *bounds* of the layer. // We can only make this assumption if we're not dealing with a complex visible region. bool isSimpleVisibleRegion = visibleRegion.Contains(visibleRect); if (current && isOpaque && isSimpleVisibleRegion) { nsIntRect displayRect = nsIntRect(displayFrame.left, displayFrame.top, displayFrame.right - displayFrame.left, displayFrame.bottom - displayFrame.top); if (displayRect.Contains(mScreenRect)) { // In z-order, all previous layers are below // the current layer. We can ignore them now. mList->numHwLayers = current = 0; mHwcLayerMap.Clear(); } } if (!mList || current >= mMaxLayerCount) { if (!ReallocLayerList() || current >= mMaxLayerCount) { LOGE("PrepareLayerList failed! Could not increase the maximum layer count"); return false; } } HwcLayer& hwcLayer = mList->hwLayers[current]; hwcLayer.displayFrame = displayFrame; mHal->SetCrop(hwcLayer, sourceCrop); buffer_handle_t handle = nullptr; #if ANDROID_VERSION >= 21 if (state.GetSidebandStream().IsValid()) { handle = state.GetSidebandStream().GetRawNativeHandle(); } else if (state.GetGrallocBuffer()) { handle = state.GetGrallocBuffer()->getNativeBuffer()->handle; } #else if (state.GetGrallocBuffer()) { handle = state.GetGrallocBuffer()->getNativeBuffer()->handle; } #endif hwcLayer.handle = handle; hwcLayer.flags = 0; hwcLayer.hints = 0; hwcLayer.blending = isOpaque ? HWC_BLENDING_NONE : HWC_BLENDING_PREMULT; #if ANDROID_VERSION >= 17 hwcLayer.compositionType = HWC_FRAMEBUFFER; #if ANDROID_VERSION >= 21 if (state.GetSidebandStream().IsValid()) { hwcLayer.compositionType = HWC_SIDEBAND; } #endif hwcLayer.acquireFenceFd = -1; hwcLayer.releaseFenceFd = -1; #if ANDROID_VERSION >= 18 hwcLayer.planeAlpha = opacity; #endif #else hwcLayer.compositionType = HwcUtils::HWC_USE_COPYBIT; #endif if (!fillColor) { if (state.FormatRBSwapped()) { if (!mRBSwapSupport) { LOGD("No R/B swap support in H/W Composer"); return false; } hwcLayer.flags |= HwcUtils::HWC_FORMAT_RB_SWAP; } // Translation and scaling have been addressed in PrepareLayerRects(). // Given the above and that we checked for PreservesAxisAlignedRectangles() // the only possible transformations left to address are // square angle rotation and horizontal/vertical reflection. // // The rotation and reflection permutations total 16 but can be // reduced to 8 transformations after eliminating redundancies. // // All matrices represented here are in the form // // | xx xy | // | yx yy | // // And ignore scaling. // // Reflection is applied before rotation gfx::Matrix rotation = layerTransform; // Compute fuzzy zero like PreservesAxisAlignedRectangles() if (fabs(rotation._11) < 1e-6) { if (rotation._21 < 0) { if (rotation._12 > 0) { // 90 degree rotation // // | 0 -1 | // | 1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_90; LOGD("Layer rotated 90 degrees"); } else { // Horizontal reflection then 90 degree rotation // // | 0 -1 | | -1 0 | = | 0 -1 | // | 1 0 | | 0 1 | | -1 0 | // // same as vertical reflection then 270 degree rotation // // | 0 1 | | 1 0 | = | 0 -1 | // | -1 0 | | 0 -1 | | -1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_H; LOGD("Layer vertically reflected then rotated 270 degrees"); } } else { if (rotation._12 < 0) { // 270 degree rotation // // | 0 1 | // | -1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_270; LOGD("Layer rotated 270 degrees"); } else { // Vertical reflection then 90 degree rotation // // | 0 1 | | -1 0 | = | 0 1 | // | -1 0 | | 0 1 | | 1 0 | // // Same as horizontal reflection then 270 degree rotation // // | 0 -1 | | 1 0 | = | 0 1 | // | 1 0 | | 0 -1 | | 1 0 | // hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_V; LOGD("Layer horizontally reflected then rotated 270 degrees"); } } } else if (rotation._11 < 0) { if (rotation._22 > 0) { // Horizontal reflection // // | -1 0 | // | 0 1 | // hwcLayer.transform = HWC_TRANSFORM_FLIP_H; LOGD("Layer rotated 180 degrees"); } else { // 180 degree rotation // // | -1 0 | // | 0 -1 | // // Same as horizontal and vertical reflection // // | -1 0 | | 1 0 | = | -1 0 | // | 0 1 | | 0 -1 | | 0 -1 | // hwcLayer.transform = HWC_TRANSFORM_ROT_180; LOGD("Layer rotated 180 degrees"); } } else { if (rotation._22 < 0) { // Vertical reflection // // | 1 0 | // | 0 -1 | // hwcLayer.transform = HWC_TRANSFORM_FLIP_V; LOGD("Layer rotated 180 degrees"); } else { // No rotation or reflection // // | 1 0 | // | 0 1 | // hwcLayer.transform = 0; } } const bool needsYFlip = state.OriginBottomLeft() ? true : false; if (needsYFlip) { // Invert vertical reflection flag if it was already set hwcLayer.transform ^= HWC_TRANSFORM_FLIP_V; } hwc_region_t region; if (visibleRegion.GetNumRects() > 1) { mVisibleRegions.push_back(HwcUtils::RectVector()); HwcUtils::RectVector* visibleRects = &(mVisibleRegions.back()); bool isVisible = false; if(!HwcUtils::PrepareVisibleRegion(visibleRegion, layerTransform, layerBufferTransform, clip, bufferRect, visibleRects, isVisible)) { LOGD("A region of layer is too small to be rendered by HWC"); return false; } if (!isVisible) { // Layer is not visible, no need to render it return true; } region.numRects = visibleRects->size(); region.rects = &((*visibleRects)[0]); } else { region.numRects = 1; region.rects = &(hwcLayer.displayFrame); } hwcLayer.visibleRegionScreen = region; } else { hwcLayer.flags |= HwcUtils::HWC_COLOR_FILL; ColorLayer* colorLayer = aLayer->AsColorLayer(); if (colorLayer->GetColor().a < 1.0) { LOGD("Color layer has semitransparency which is unsupported"); return false; } hwcLayer.transform = colorLayer->GetColor().ToABGR(); } #if ANDROID_VERSION >= 21 if (aFindSidebandStreams && hwcLayer.compositionType == HWC_SIDEBAND) { mCachedSidebandLayers.AppendElement(hwcLayer); } #endif mHwcLayerMap.AppendElement(static_cast<LayerComposite*>(aLayer->ImplData())); mList->numHwLayers++; return true; } #if ANDROID_VERSION >= 17 bool HwcComposer2D::TryHwComposition(nsScreenGonk* aScreen) { DisplaySurface* dispSurface = aScreen->GetDisplaySurface(); if (!(dispSurface && dispSurface->lastHandle)) { LOGD("H/W Composition failed. DispSurface not initialized."); return false; } // Add FB layer int idx = mList->numHwLayers++; if (idx >= mMaxLayerCount) { if (!ReallocLayerList() || idx >= mMaxLayerCount) { LOGE("TryHwComposition failed! Could not add FB layer"); return false; } } Prepare(dispSurface->lastHandle, -1, aScreen); /* Possible composition paths, after hwc prepare: 1. GPU Composition 2. BLIT Composition 3. Full OVERLAY Composition 4. Partial OVERLAY Composition (GPU + OVERLAY) */ bool gpuComposite = false; bool blitComposite = false; bool overlayComposite = true; for (int j=0; j < idx; j++) { if (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER || mList->hwLayers[j].compositionType == HWC_BLIT) { // Full OVERLAY composition is not possible on this frame // It is either GPU / BLIT / partial OVERLAY composition. overlayComposite = false; break; } } if (!overlayComposite) { for (int k=0; k < idx; k++) { switch (mList->hwLayers[k].compositionType) { case HWC_FRAMEBUFFER: gpuComposite = true; break; case HWC_BLIT: blitComposite = true; break; #if ANDROID_VERSION >= 21 case HWC_SIDEBAND: #endif case HWC_OVERLAY: { // HWC will compose HWC_OVERLAY layers in partial // Overlay Composition, set layer composition flag // on mapped LayerComposite to skip GPU composition mHwcLayerMap[k]->SetLayerComposited(true); uint8_t opacity = std::min(0xFF, (int)(mHwcLayerMap[k]->GetLayer()->GetEffectiveOpacity() * 256.0)); if ((mList->hwLayers[k].hints & HWC_HINT_CLEAR_FB) && (opacity == 0xFF)) { // Clear visible rect on FB with transparent pixels. hwc_rect_t r = mList->hwLayers[k].displayFrame; mHwcLayerMap[k]->SetClearRect(nsIntRect(r.left, r.top, r.right - r.left, r.bottom - r.top)); } break; } default: break; } } if (gpuComposite) { // GPU or partial OVERLAY Composition return false; } else if (blitComposite) { // BLIT Composition, flip DispSurface target GetGonkDisplay()->UpdateDispSurface(aScreen->GetEGLDisplay(), aScreen->GetEGLSurface()); DisplaySurface* dispSurface = aScreen->GetDisplaySurface(); if (!dispSurface) { LOGE("H/W Composition failed. NULL DispSurface."); return false; } mList->hwLayers[idx].handle = dispSurface->lastHandle; mList->hwLayers[idx].acquireFenceFd = dispSurface->GetPrevDispAcquireFd(); } } // BLIT or full OVERLAY Composition return Commit(aScreen); }
/** Packages an image layer as a TMS folder. */ int makeTMS( osg::ArgumentParser& args ) { // see if the user wants to override the type extension (imagery only) std::string extension = "png"; args.read( "--ext", extension ); // verbosity? bool verbose = !args.read( "--quiet" ); // find a .earth file on the command line std::string earthFile = findArgumentWithExtension(args, ".earth"); if ( earthFile.empty() ) return usage( "Missing required .earth file" ); // folder to which to write the TMS archive. std::string rootFolder; if ( !args.read( "--out", rootFolder ) ) rootFolder = Stringify() << earthFile << ".tms_repo"; // max level to which to generate unsigned maxLevel = ~0; args.read( "--max-level", maxLevel ); // load up the map osg::ref_ptr<MapNode> mapNode = MapNode::load( args ); if ( !mapNode.valid() ) return usage( "Failed to load a valid .earth file" ); // create a folder for the output osgDB::makeDirectory(rootFolder); if ( !osgDB::fileExists(rootFolder) ) return usage("Failed to create root output folder" ); Map* map = mapNode->getMap(); // fire up a packager: TMSPackager packager( map->getProfile() ); packager.setVerbose( verbose ); if ( maxLevel != ~0 ) packager.setMaxLevel( maxLevel ); // package any image layers that are enabled: ImageLayerVector imageLayers; map->getImageLayers( imageLayers ); unsigned counter = 0; for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i, ++counter ) { ImageLayer* layer = i->get(); if ( layer->getImageLayerOptions().enabled() == true ) { std::string layerFolder = toLegalFileName( layer->getName() ); if ( layerFolder.empty() ) layerFolder = Stringify() << "image_layer_" << counter; if ( verbose ) { OE_NOTICE << LC << "Packaging image layer \"" << layerFolder << "\"" << std::endl; } std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder ); TMSPackager::Result r = packager.package( layer, layerRoot, extension ); if ( !r.ok ) { OE_WARN << LC << r.message << std::endl; } } else if ( verbose ) { OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl; } } // package any elevation layers that are enabled: counter = 0; ElevationLayerVector elevationLayers; map->getElevationLayers( elevationLayers ); for( ElevationLayerVector::iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i, ++counter ) { ElevationLayer* layer = i->get(); if ( layer->getElevationLayerOptions().enabled() == true ) { std::string layerFolder = toLegalFileName( layer->getName() ); if ( layerFolder.empty() ) layerFolder = Stringify() << "elevation_layer_" << counter; if ( verbose ) { OE_NOTICE << LC << "Packaging elevation layer \"" << layerFolder << "\"" << std::endl; } std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder ); packager.package( layer, layerRoot ); } else if ( verbose ) { OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl; } } return 0; }
int purge( osg::ArgumentParser& args ) { osg::ref_ptr<osg::Node> node = osgDB::readNodeFiles( args ); if ( !node.valid() ) return usage( "Failed to read .earth file." ); MapNode* mapNode = MapNode::findMapNode( node.get() ); if ( !mapNode ) return usage( "Input file was not a .earth file" ); Map* map = mapNode->getMap(); if ( !map->getCache() ) return message( "Earth file does not contain a cache." ); std::vector<Entry> entries; ImageLayerVector imageLayers; map->getLayers( imageLayers ); for( ImageLayerVector::const_iterator i = imageLayers.begin(); i != imageLayers.end(); ++i ) { ImageLayer* layer = i->get(); bool useMFP = layer->getProfile() && layer->getProfile()->getSRS()->isSphericalMercator() && mapNode->getMapNodeOptions().getTerrainOptions().enableMercatorFastPath() == true; const Profile* cacheProfile = useMFP ? layer->getProfile() : map->getProfile(); CacheSettings* cacheSettings = layer->getCacheSettings(); if (cacheSettings) { CacheBin* bin = cacheSettings->getCacheBin(); if ( bin ) { entries.push_back(Entry()); entries.back()._isImage = true; entries.back()._name = i->get()->getName(); entries.back()._bin = bin; } } } ElevationLayerVector elevationLayers; map->getLayers( elevationLayers ); for( ElevationLayerVector::const_iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i ) { ElevationLayer* layer = i->get(); bool useMFP = layer->getProfile() && layer->getProfile()->getSRS()->isSphericalMercator() && mapNode->getMapNodeOptions().getTerrainOptions().enableMercatorFastPath() == true; const Profile* cacheProfile = useMFP ? layer->getProfile() : map->getProfile(); CacheSettings* cacheSettings = layer->getCacheSettings(); if (cacheSettings) { CacheBin* bin = cacheSettings->getCacheBin(); if (bin) { entries.push_back(Entry()); entries.back()._isImage = false; entries.back()._name = i->get()->getName(); entries.back()._bin = bin; } } } if ( entries.size() > 0 ) { std::cout << std::endl; for( unsigned i=0; i<entries.size(); ++i ) { std::cout << (i+1) << ") " << entries[i]._name << " (" << (entries[i]._isImage? "image" : "elevation" ) << ")" << std::endl; } std::cout << std::endl << "Enter number of cache to purge, or <enter> to quit: " << std::flush; std::string input; std::getline( std::cin, input ); if ( !input.empty() ) { unsigned k = as<unsigned>(input, 0L); if ( k > 0 && k <= entries.size() ) { Config meta = entries[k-1]._bin->readMetadata(); if ( !meta.empty() ) { std::cout << std::endl << "Cache METADATA:" << std::endl << meta.toJSON() << std::endl << std::endl; } std::cout << "Are you sure (y/N)? " << std::flush; std::getline( std::cin, input ); if ( input == "y" || input == "Y" ) { std::cout << "Purging.." << std::flush; entries[k-1]._bin->clear(); } else { std::cout << "No action taken." << std::endl; } } else { std::cout << "Invalid choice." << std::endl; } } else { std::cout << "No action taken." << std::endl; } } return 0; }
void TerrainEngineNode::updateImageUniforms() { // don't bother if this is a hurting old card if ( !Registry::instance()->getCapabilities().supportsGLSL() ) return; // update the layer uniform arrays: osg::StateSet* stateSet = this->getOrCreateStateSet(); // get a copy of the image layer stack: MapFrame mapf( _map.get(), Map::IMAGE_LAYERS ); _imageLayerController->_layerEnabledUniform.detach(); _imageLayerController->_layerOpacityUniform.detach(); _imageLayerController->_layerRangeUniform.detach(); #if 0 if ( _imageLayerController->_layerEnabledUniform.valid() ) _imageLayerController->_layerEnabledUniform->removeFrom( stateSet ); if ( _imageLayerController->_layerOpacityUniform.valid() ) _imageLayerController->_layerOpacityUniform->removeFrom( stateSet ); if ( _imageLayerController->_layerRangeUniform.valid() ) _imageLayerController->_layerRangeUniform->removeFrom( stateSet ); #endif //stateSet->removeUniform( "osgearth_ImageLayerAttenuation" ); if ( mapf.imageLayers().size() > 0 ) { // the "enabled" uniform is fixed size. this is handy to account for layers that are in flux...i.e., their source // layer count has changed, but the shader has not yet caught up. In the future we might use this to disable // "ghost" layers that used to exist at a given index, but no longer do. _imageLayerController->_layerEnabledUniform.attach( "osgearth_ImageLayerEnabled", osg::Uniform::BOOL, stateSet, 64 ); _imageLayerController->_layerOpacityUniform.attach( "osgearth_ImageLayerOpacity", osg::Uniform::FLOAT, stateSet, mapf.imageLayers().size() ); _imageLayerController->_layerRangeUniform.attach ( "osgearth_ImageLayerRange", osg::Uniform::FLOAT, stateSet, 2 * mapf.imageLayers().size() ); //_imageLayerController->_layerEnabledUniform = new ArrayUniform( osg::Uniform::BOOL, "osgearth_ImageLayerEnabled", 64 ); //mapf.imageLayers().size() ); //_imageLayerController->_layerOpacityUniform = new ArrayUniform( osg::Uniform::FLOAT, "osgearth_ImageLayerOpacity", mapf.imageLayers().size() ); //_imageLayerController->_layerRangeUniform = new ArrayUniform( osg::Uniform::FLOAT, "osgearth_ImageLayerRange", 2 * mapf.imageLayers().size() ); for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); int index = (int)(i - mapf.imageLayers().begin()); _imageLayerController->_layerOpacityUniform.setElement( index, layer->getOpacity() ); _imageLayerController->_layerEnabledUniform.setElement( index, layer->getEnabled() ); _imageLayerController->_layerRangeUniform.setElement( (2*index), layer->getImageLayerOptions().minVisibleRange().value() ); _imageLayerController->_layerRangeUniform.setElement( (2*index)+1, layer->getImageLayerOptions().maxVisibleRange().value() ); } // set the remainder of the layers to disabled for( int j=mapf.imageLayers().size(); j<64; ++j ) _imageLayerController->_layerEnabledUniform.setElement( j, false ); //_imageLayerController->_layerOpacityUniform->addTo( stateSet ); //_imageLayerController->_layerEnabledUniform->addTo( stateSet ); //_imageLayerController->_layerRangeUniform->addTo( stateSet ); } }
void CacheSeed::seed( Map* map ) { if ( !map->getCache() ) { OE_WARN << LC << "Warning: No cache defined; aborting." << std::endl; return; } std::vector<TileKey> keys; map->getProfile()->getRootKeys(keys); //Add the map's entire extent if we don't have one specified. if (_extents.empty()) { addExtent( map->getProfile()->getExtent() ); } bool hasCaches = false; int src_min_level = INT_MAX; unsigned int src_max_level = 0; MapFrame mapf( map, Map::TERRAIN_LAYERS, "CacheSeed::seed" ); //Assumes the the TileSource will perform the caching for us when we call createImage for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); i++ ) { ImageLayer* layer = i->get(); TileSource* src = layer->getTileSource(); const ImageLayerOptions& opt = layer->getImageLayerOptions(); if ( layer->isCacheOnly() ) { OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" is set to cache-only; skipping." << std::endl; } else if ( !src ) { OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource; skipping." << std::endl; } else if ( src->getCachePolicyHint() == CachePolicy::NO_CACHE ) { OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" does not support seeding; skipping." << std::endl; } else if ( !layer->getCache() ) { OE_WARN << LC << "Notice: Layer \"" << layer->getName() << "\" has no cache defined; skipping." << std::endl; } else { hasCaches = true; if (opt.minLevel().isSet() && (int)opt.minLevel().get() < src_min_level) src_min_level = opt.minLevel().get(); if (opt.maxLevel().isSet() && opt.maxLevel().get() > src_max_level) src_max_level = opt.maxLevel().get(); } } for( ElevationLayerVector::const_iterator i = mapf.elevationLayers().begin(); i != mapf.elevationLayers().end(); i++ ) { ElevationLayer* layer = i->get(); TileSource* src = layer->getTileSource(); const ElevationLayerOptions& opt = layer->getElevationLayerOptions(); if ( layer->isCacheOnly() ) { OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" is set to cache-only; skipping." << std::endl; } else if (!src) { OE_WARN << "Warning: Layer \"" << layer->getName() << "\" could not create TileSource; skipping." << std::endl; } else if ( src->getCachePolicyHint() == CachePolicy::NO_CACHE ) { OE_WARN << LC << "Warning: Layer \"" << layer->getName() << "\" does not support seeding; skipping." << std::endl; } else if ( !layer->getCache() ) { OE_WARN << LC << "Notice: Layer \"" << layer->getName() << "\" has no cache defined; skipping." << std::endl; } else { hasCaches = true; if (opt.minLevel().isSet() && (int)opt.minLevel().get() < src_min_level) src_min_level = opt.minLevel().get(); if (opt.maxLevel().isSet() && opt.maxLevel().get() > src_max_level) src_max_level = opt.maxLevel().get(); } } if ( !hasCaches ) { OE_WARN << LC << "There are either no caches defined in the map, or no sources to cache; aborting." << std::endl; return; } if ( src_max_level > 0 && src_max_level < _maxLevel ) { _maxLevel = src_max_level; } OE_NOTICE << LC << "Maximum cache level will be " << _maxLevel << std::endl; osg::Timer_t startTime = osg::Timer::instance()->tick(); //Estimate the number of tiles _total = 0; for (unsigned int level = _minLevel; level <= _maxLevel; level++) { double coverageRatio = 0.0; if (_extents.empty()) { unsigned int wide, high; map->getProfile()->getNumTiles( level, wide, high ); _total += (wide * high); } else { for (std::vector< GeoExtent >::const_iterator itr = _extents.begin(); itr != _extents.end(); itr++) { const GeoExtent& extent = *itr; double boundsArea = extent.area(); TileKey ll = map->getProfile()->createTileKey(extent.xMin(), extent.yMin(), level); TileKey ur = map->getProfile()->createTileKey(extent.xMax(), extent.yMax(), level); int tilesWide = ur.getTileX() - ll.getTileX() + 1; int tilesHigh = ll.getTileY() - ur.getTileY() + 1; int tilesAtLevel = tilesWide * tilesHigh; //OE_NOTICE << "Tiles at level " << level << "=" << tilesAtLevel << std::endl; bool hasData = false; for (ImageLayerVector::const_iterator itr = mapf.imageLayers().begin(); itr != mapf.imageLayers().end(); itr++) { TileSource* src = itr->get()->getTileSource(); if (src) { if (src->hasDataAtLOD( level )) { //Compute the percent coverage of this dataset on the current extent if (src->getDataExtents().size() > 0) { double cov = 0.0; for (unsigned int j = 0; j < src->getDataExtents().size(); j++) { GeoExtent b = src->getDataExtents()[j].transform( extent.getSRS()); GeoExtent intersection = b.intersectionSameSRS( extent ); if (intersection.isValid()) { double coverage = intersection.area() / boundsArea; cov += coverage; //Assumes the extents aren't overlapping } } if (coverageRatio < cov) coverageRatio = cov; } else { //We have no way of knowing how much coverage we have coverageRatio = 1.0; } hasData = true; break; } } } for (ElevationLayerVector::const_iterator itr = mapf.elevationLayers().begin(); itr != mapf.elevationLayers().end(); itr++) { TileSource* src = itr->get()->getTileSource(); if (src) { if (src->hasDataAtLOD( level )) { //Compute the percent coverage of this dataset on the current extent if (src->getDataExtents().size() > 0) { double cov = 0.0; for (unsigned int j = 0; j < src->getDataExtents().size(); j++) { GeoExtent b = src->getDataExtents()[j].transform( extent.getSRS()); GeoExtent intersection = b.intersectionSameSRS( extent ); if (intersection.isValid()) { double coverage = intersection.area() / boundsArea; cov += coverage; //Assumes the extents aren't overlapping } } if (coverageRatio < cov) coverageRatio = cov; } else { //We have no way of knowing how much coverage we have coverageRatio = 1.0; } hasData = true; break; } } } //Adjust the coverage ratio by a fudge factor to try to keep it from being too small, //tiles are either processed or not and the ratio is exact so will cover tiles partially //and potentially be too small double adjust = 4.0; coverageRatio = osg::clampBetween(coverageRatio * adjust, 0.0, 1.0); //OE_NOTICE << level << " CoverageRatio = " << coverageRatio << std::endl; if (hasData) { _total += (int)ceil(coverageRatio * (double)tilesAtLevel ); } } } } //Adjust the # of tiles again to be bigger than computed to avoid giving false hope _total *= 2; osg::Timer_t endTime = osg::Timer::instance()->tick(); //OE_NOTICE << "Counted tiles in " << osg::Timer::instance()->delta_s(startTime, endTime) << " s" << std::endl; OE_INFO << "Processing ~" << _total << " tiles" << std::endl; for (unsigned int i = 0; i < keys.size(); ++i) { processKey( mapf, keys[i] ); } _total = _completed; if ( _progress.valid()) _progress->reportProgress(_completed, _total, 0, 1, "Finished"); }
/** Packages an image layer as a TMS folder. */ int makeTMS( osg::ArgumentParser& args ) { osgDB::Registry::instance()->getReaderWriterForExtension("png"); osgDB::Registry::instance()->getReaderWriterForExtension("jpg"); osgDB::Registry::instance()->getReaderWriterForExtension("tiff"); //Read the min level unsigned int minLevel = 0; while (args.read("--min-level", minLevel)); //Read the max level unsigned int maxLevel = 5; while (args.read("--max-level", maxLevel)); std::vector< Bounds > bounds; // restrict packaging to user-specified bounds. double xmin=DBL_MAX, ymin=DBL_MAX, xmax=DBL_MIN, ymax=DBL_MIN; while (args.read("--bounds", xmin, ymin, xmax, ymax )) { Bounds b; b.xMin() = xmin, b.yMin() = ymin, b.xMax() = xmax, b.yMax() = ymax; bounds.push_back( b ); } std::string tileList; while (args.read( "--tiles", tileList ) ); bool verbose = args.read("--verbose"); unsigned int batchSize = 0; args.read("--batchsize", batchSize); // Read the concurrency level unsigned int concurrency = 0; args.read("-c", concurrency); args.read("--concurrency", concurrency); bool applyAlphaMask = args.read("--alpha-mask"); bool writeXML = true; // load up the map osg::ref_ptr<MapNode> mapNode = MapNode::load( args ); if( !mapNode.valid() ) return usage( "Failed to load a valid .earth file" ); // Read in an index shapefile std::string index; while (args.read("--index", index)) { //Open the feature source OGRFeatureOptions featureOpt; featureOpt.url() = index; osg::ref_ptr< FeatureSource > features = FeatureSourceFactory::create( featureOpt ); features->initialize(); features->getFeatureProfile(); osg::ref_ptr< FeatureCursor > cursor = features->createFeatureCursor(); while (cursor.valid() && cursor->hasMore()) { osg::ref_ptr< Feature > feature = cursor->nextFeature(); osgEarth::Bounds featureBounds = feature->getGeometry()->getBounds(); GeoExtent ext( feature->getSRS(), featureBounds ); ext = ext.transform( mapNode->getMapSRS() ); bounds.push_back( ext.bounds() ); } } // see if the user wants to override the type extension (imagery only) std::string extension; args.read( "--ext", extension ); // find a .earth file on the command line std::string earthFile = findArgumentWithExtension( args, ".earth" ); // folder to which to write the TMS archive. std::string rootFolder; if( !args.read( "--out", rootFolder ) ) rootFolder = Stringify() << earthFile << ".tms_repo"; // whether to overwrite existing tile files //TODO: Support bool overwrite = false; if( args.read( "--overwrite" ) ) overwrite = true; // write out an earth file std::string outEarth; args.read( "--out-earth", outEarth ); std::string dbOptions; args.read( "--db-options", dbOptions ); std::string::size_type n = 0; while( (n = dbOptions.find( '"', n )) != dbOptions.npos ) { dbOptions.erase( n, 1 ); } osg::ref_ptr<osgDB::Options> options = new osgDB::Options( dbOptions ); // whether to keep 'empty' tiles bool keepEmpties = args.read( "--keep-empties" ); //TODO: Single color bool continueSingleColor = args.read( "--continue-single-color" ); // elevation pixel depth unsigned elevationPixelDepth = 32; args.read( "--elevation-pixel-depth", elevationPixelDepth ); // create a folder for the output osgDB::makeDirectory( rootFolder ); if( !osgDB::fileExists( rootFolder ) ) return usage( "Failed to create root output folder" ); int imageLayerIndex = -1; args.read("--image", imageLayerIndex); int elevationLayerIndex = -1; args.read("--elevation", elevationLayerIndex); Map* map = mapNode->getMap(); osg::ref_ptr< TileVisitor > visitor; // If we are given a task file, load it up and create a new TileKeyListVisitor if (!tileList.empty()) { TaskList tasks( mapNode->getMap()->getProfile() ); tasks.load( tileList ); TileKeyListVisitor* v = new TileKeyListVisitor(); v->setKeys( tasks.getKeys() ); visitor = v; // This process is a lowly worker, and shouldn't write out the XML file. writeXML = false; } // If we dont' have a visitor create one. if (!visitor.valid()) { if (args.read("--mt")) { // Create a multithreaded visitor MultithreadedTileVisitor* v = new MultithreadedTileVisitor(); if (concurrency > 0) { v->setNumThreads(concurrency); } visitor = v; } else if (args.read("--mp")) { // Create a multiprocess visitor MultiprocessTileVisitor* v = new MultiprocessTileVisitor(); if (concurrency > 0) { v->setNumProcesses(concurrency); OE_NOTICE << "Set num processes " << concurrency << std::endl; } if (batchSize > 0) { v->setBatchSize(batchSize); } // Try to find the earth file std::string earthFile; for(int pos=1;pos<args.argc();++pos) { if (!args.isOption(pos)) { earthFile = args[ pos ]; break; } } v->setEarthFile( earthFile ); visitor = v; } else { // Create a single thread visitor visitor = new TileVisitor(); } } osg::ref_ptr< ProgressCallback > progress = new ConsoleProgressCallback(); if (verbose) { visitor->setProgressCallback( progress ); } visitor->setMinLevel( minLevel ); visitor->setMaxLevel( maxLevel ); for (unsigned int i = 0; i < bounds.size(); i++) { GeoExtent extent(mapNode->getMapSRS(), bounds[i]); OE_DEBUG << "Adding extent " << extent.toString() << std::endl; visitor->addExtent( extent ); } // Setup a TMSPackager with all the options. TMSPackager packager; packager.setExtension(extension); packager.setVisitor(visitor); packager.setDestination(rootFolder); packager.setElevationPixelDepth(elevationPixelDepth); packager.setWriteOptions(options); packager.setOverwrite(overwrite); packager.setKeepEmpties(keepEmpties); packager.setApplyAlphaMask(applyAlphaMask); // new map for an output earth file if necessary. osg::ref_ptr<Map> outMap = 0L; if( !outEarth.empty() ) { // copy the options from the source map first outMap = new Map( map->getInitialMapOptions() ); } std::string outEarthFile = osgDB::concatPaths( rootFolder, osgDB::getSimpleFileName( outEarth ) ); // Package an individual image layer if (imageLayerIndex >= 0) { ImageLayer* layer = map->getImageLayerAt(imageLayerIndex); if (layer) { packager.run(layer, map); if (writeXML) { packager.writeXML(layer, map); } } else { std::cout << "Failed to find an image layer at index " << imageLayerIndex << std::endl; return 1; } } // Package an individual elevation layer else if (elevationLayerIndex >= 0) { ElevationLayer* layer = map->getElevationLayerAt(elevationLayerIndex); if (layer) { packager.run(layer, map); if (writeXML) { packager.writeXML(layer, map ); } } else { std::cout << "Failed to find an elevation layer at index " << elevationLayerIndex << std::endl; return 1; } } else { // Package all the ImageLayer's for (unsigned int i = 0; i < map->getNumImageLayers(); i++) { ImageLayer* layer = map->getImageLayerAt(i); OE_NOTICE << "Packaging " << layer->getName() << std::endl; osg::Timer_t start = osg::Timer::instance()->tick(); packager.run(layer, map); osg::Timer_t end = osg::Timer::instance()->tick(); if (verbose) { OE_NOTICE << "Completed seeding layer " << layer->getName() << " in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl; } if (writeXML) { packager.writeXML(layer, map); } // save to the output map if requested: if( outMap.valid() ) { std::string layerFolder = toLegalFileName( packager.getLayerName() ); // new TMS driver info: TMSOptions tms; tms.url() = URI( osgDB::concatPaths( layerFolder, "tms.xml" ), outEarthFile ); ImageLayerOptions layerOptions( packager.getLayerName(), tms ); layerOptions.mergeConfig( layer->getInitialOptions().getConfig( true ) ); layerOptions.cachePolicy() = CachePolicy::NO_CACHE; outMap->addImageLayer( new ImageLayer( layerOptions ) ); } } // Package all the ElevationLayer's for (unsigned int i = 0; i < map->getNumElevationLayers(); i++) { ElevationLayer* layer = map->getElevationLayerAt(i); OE_NOTICE << "Packaging " << layer->getName() << std::endl; osg::Timer_t start = osg::Timer::instance()->tick(); packager.run(layer, map); osg::Timer_t end = osg::Timer::instance()->tick(); if (verbose) { OE_NOTICE << "Completed seeding layer " << layer->getName() << " in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl; } if (writeXML) { packager.writeXML(layer, map); } // save to the output map if requested: if( outMap.valid() ) { std::string layerFolder = toLegalFileName( packager.getLayerName() ); // new TMS driver info: TMSOptions tms; tms.url() = URI( osgDB::concatPaths( layerFolder, "tms.xml" ), outEarthFile ); ElevationLayerOptions layerOptions( packager.getLayerName(), tms ); layerOptions.mergeConfig( layer->getInitialOptions().getConfig( true ) ); layerOptions.cachePolicy() = CachePolicy::NO_CACHE; outMap->addElevationLayer( new ElevationLayer( layerOptions ) ); } } } // Write out an earth file if it was requested // Finally, write an earth file if requested: if( outMap.valid() ) { MapNodeOptions outNodeOptions = mapNode->getMapNodeOptions(); osg::ref_ptr<MapNode> outMapNode = new MapNode( outMap.get(), outNodeOptions ); if( !osgDB::writeNodeFile( *outMapNode.get(), outEarthFile ) ) { OE_WARN << LC << "Error writing earth file to \"" << outEarthFile << "\"" << std::endl; } else if( verbose ) { OE_NOTICE << LC << "Wrote earth file to \"" << outEarthFile << "\"" << std::endl; } } return 0; }
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(); } } 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; } 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; } }
osg::Node* OSGTileFactory::createPopulatedTile(const MapFrame& mapf, Terrain* terrain, const TileKey& key, bool wrapInPagedLOD, bool fallback, bool& validData ) { const MapInfo& mapInfo = mapf.getMapInfo(); bool isPlateCarre = !mapInfo.isGeocentric() && mapInfo.isGeographicSRS(); typedef std::vector<GeoImageData> GeoImageDataVector; GeoImageDataVector image_tiles; // Collect the image layers bool empty_map = mapf.imageLayers().size() == 0 && mapf.elevationLayers().size() == 0; // Create the images for the tile for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); GeoImageData imageData; // Only try to create images if the key is valid if ( layer->isKeyValid( key ) ) { imageData._image = layer->createImage( key ); imageData._layerUID = layer->getUID(); imageData._imageTileKey = key; } // always push images, even it they are empty, so that the image_tiles vector is one-to-one // with the imageLayers() vector. image_tiles.push_back( imageData ); } bool hasElevation = false; //Create the heightfield for the tile osg::ref_ptr<osg::HeightField> hf; if ( mapf.elevationLayers().size() > 0 ) { mapf.getHeightField( key, false, hf, 0L, _terrainOptions.elevationInterpolation().value()); } //If we are on the first LOD and we couldn't get a heightfield tile, just create an empty one. Otherwise you can run into the situation //where you could have an inset heightfield on one hemisphere and the whole other hemisphere won't show up. if ( mapInfo.isGeocentric() && key.getLevelOfDetail() <= 1 && !hf.valid()) { hf = createEmptyHeightField( key ); } hasElevation = hf.valid(); //Determine if we've created any images unsigned int numValidImages = 0; for (unsigned int i = 0; i < image_tiles.size(); ++i) { if (image_tiles[i]._image.valid()) numValidImages++; } //If we couldn't create any imagery or heightfields, bail out if (!hf.valid() && (numValidImages == 0) && !empty_map) { OE_DEBUG << LC << "Could not create any imagery or heightfields for " << key.str() <<". Not building tile" << std::endl; validData = false; //If we're not asked to fallback on previous LOD's and we have no data, return NULL if (!fallback) { return NULL; } } else { validData = true; } //Try to interpolate any missing image layers from parent tiles for (unsigned int i = 0; i < mapf.imageLayers().size(); i++ ) { if (!image_tiles[i]._image.valid()) { if (mapf.getImageLayerAt(i)->isKeyValid(key)) { //If the key was valid and we have no image, then something possibly went wrong with the image creation such as a server being busy. createValidGeoImage(mapf.getImageLayerAt(i), key, image_tiles[i]._image, image_tiles[i]._imageTileKey); } //If we still couldn't create an image, either something is really wrong or the key wasn't valid, so just create a transparent placeholder image if (!image_tiles[i]._image.valid()) { //If the image is not valid, create an empty texture as a placeholder image_tiles[i]._image = GeoImage(ImageUtils::createEmptyImage(), key.getExtent()); image_tiles[i]._imageTileKey = key; } } } //Fill in missing heightfield information from parent tiles if (!hf.valid()) { //We have no heightfield sources, if ( mapf.elevationLayers().size() == 0 ) { hf = createEmptyHeightField( key ); } else { //Try to get a heightfield again, but this time fallback on parent tiles if ( mapf.getHeightField( key, true, hf, 0L, _terrainOptions.elevationInterpolation().value() ) ) { hasElevation = true; } else { //We couldn't get any heightfield, so just create an empty one. hf = createEmptyHeightField( key ); } } } // In a Plate Carre tesselation, scale the heightfield elevations from meters to degrees if ( isPlateCarre ) { HeightFieldUtils::scaleHeightFieldToDegrees( hf.get() ); } osg::ref_ptr<GeoLocator> locator = GeoLocator::createForKey( key, mapInfo ); osgTerrain::HeightFieldLayer* hf_layer = new osgTerrain::HeightFieldLayer(); hf_layer->setLocator( locator.get() ); hf_layer->setHeightField( hf.get() ); bool isStreaming = _terrainOptions.loadingPolicy()->mode() == LoadingPolicy::MODE_SEQUENTIAL || _terrainOptions.loadingPolicy()->mode() == LoadingPolicy::MODE_PREEMPTIVE; Tile* tile = terrain->createTile( key, locator.get() ); tile->setTerrainTechnique( terrain->cloneTechnique() ); tile->setVerticalScale( _terrainOptions.verticalScale().value() ); //tile->setLocator( locator.get() ); tile->setElevationLayer( hf_layer ); //tile->setRequiresNormals( true ); tile->setDataVariance(osg::Object::DYNAMIC); #if 0 //Attach an updatecallback to normalize the edges of TerrainTiles. if (hasElevation && _terrainOptions.normalizeEdges().get() ) { tile->setUpdateCallback(new TerrainTileEdgeNormalizerUpdateCallback()); tile->setDataVariance(osg::Object::DYNAMIC); } #endif //Assign the terrain system to the TerrainTile. //It is very important the terrain system is set while the MapConfig's sourceMutex is locked. //This registers the terrain tile so that adding/removing layers are always in sync. If you don't do this //you can end up with a situation where the database pager is waiting to merge a tile, then a layer is added, then //the tile is finally merged and is out of sync. double min_units_per_pixel = DBL_MAX; #if 0 // create contour layer: if (map->getContourTransferFunction() != NULL) { osgTerrain::ContourLayer* contourLayer(new osgTerrain::ContourLayer(map->getContourTransferFunction())); contourLayer->setMagFilter(_terrainOptions.getContourMagFilter().value()); contourLayer->setMinFilter(_terrainOptions.getContourMinFilter().value()); tile->setCustomColorLayer(layer,contourLayer); //TODO: need layerUID, not layer index here -GW ++layer; } #endif for (unsigned int i = 0; i < image_tiles.size(); ++i) { if (image_tiles[i]._image.valid()) { const GeoImage& geo_image = image_tiles[i]._image; double img_xmin, img_ymin, img_xmax, img_ymax; geo_image.getExtent().getBounds( img_xmin, img_ymin, img_xmax, img_ymax ); //Specify a new locator for the color with the coordinates of the TileKey that was actually used to create the image osg::ref_ptr<GeoLocator> img_locator = key.getProfile()->getSRS()->createLocator( img_xmin, img_ymin, img_xmax, img_ymax, isPlateCarre ); if ( mapInfo.isGeocentric() ) img_locator->setCoordinateSystemType( osgTerrain::Locator::GEOCENTRIC ); tile->setCustomColorLayer( CustomColorLayer( mapf.getImageLayerAt(i), geo_image.getImage(), img_locator.get(), key.getLevelOfDetail(), key) ); double upp = geo_image.getUnitsPerPixel(); // Scale the units per pixel to degrees if the image is mercator (and the key is geo) if ( geo_image.getSRS()->isMercator() && key.getExtent().getSRS()->isGeographic() ) upp *= 1.0f/111319.0f; min_units_per_pixel = osg::minimum(upp, min_units_per_pixel); } } osg::BoundingSphere bs = tile->getBound(); double max_range = 1e10; double radius = bs.radius(); #if 1 double min_range = radius * _terrainOptions.minTileRangeFactor().get(); //osg::LOD::RangeMode mode = osg::LOD::DISTANCE_FROM_EYE_POINT; #else double width = key.getExtent().width(); if (min_units_per_pixel == DBL_MAX) min_units_per_pixel = width/256.0; double min_range = (width / min_units_per_pixel) * _terrainOptions.getMinTileRangeFactor(); //osg::LOD::RangeMode mode = osg::LOD::PIXEL_SIZE_ON_SCREEN; #endif // a skirt hides cracks when transitioning between LODs: hf->setSkirtHeight(radius * _terrainOptions.heightFieldSkirtRatio().get() ); // for now, cluster culling does not work for CUBE rendering //bool isCube = mapInfo.isCube(); //map->getMapOptions().coordSysType() == MapOptions::CSTYPE_GEOCENTRIC_CUBE; if ( mapInfo.isGeocentric() && !mapInfo.isCube() ) { //TODO: Work on cluster culling computation for cube faces osg::ClusterCullingCallback* ccc = createClusterCullingCallback(tile, locator->getEllipsoidModel() ); tile->setCullCallback( ccc ); } // Wait until now, when the tile is fully baked, to assign the terrain to the tile. // Placeholder tiles might try to locate this tile as an ancestor, and access its layers // and locators...so they must be intact before making this tile available via setTerrain. // // If there's already a placeholder tile registered, this will be ignored. If there isn't, // this will register the new tile. tile->attachToTerrain( terrain ); //tile->setTerrain( terrain ); //terrain->registerTile( tile ); if ( isStreaming && key.getLevelOfDetail() > 0 ) { static_cast<StreamingTile*>(tile)->setHasElevationHint( hasElevation ); } osg::Node* result = 0L; if (wrapInPagedLOD) { // create a PLOD so we can keep subdividing: osg::PagedLOD* plod = new osg::PagedLOD(); plod->setCenter( bs.center() ); plod->addChild( tile, min_range, max_range ); std::string filename = createURI( _engineId, key ); //map->getId(), key ); //Only add the next tile if it hasn't been blacklisted bool isBlacklisted = osgEarth::Registry::instance()->isBlacklisted( filename ); if (!isBlacklisted && key.getLevelOfDetail() < (unsigned int)getTerrainOptions().maxLOD().value() && validData ) { plod->setFileName( 1, filename ); plod->setRange( 1, 0.0, min_range ); } else { plod->setRange( 0, 0, FLT_MAX ); } #if USE_FILELOCATIONCALLBACK osgDB::Options* options = new osgDB::Options; options->setFileLocationCallback( new FileLocationCallback() ); plod->setDatabaseOptions( options ); #endif result = plod; if ( isStreaming ) result->addCullCallback( new PopulateStreamingTileDataCallback( _cull_thread_mapf ) ); } else { result = tile; } return result; }
void RexTerrainEngineNode::addTileLayer(Layer* tileLayer) { if ( tileLayer && tileLayer->getEnabled() ) { // Install the image layer stateset on this layer. // Later we will refactor this into an ImageLayerRenderer or something similar. //osg::StateSet* stateSet = tileLayer->getOrCreateStateSet(); //stateSet->merge(*getSurfaceStateSet()); ImageLayer* imageLayer = dynamic_cast<ImageLayer*>(tileLayer); if (imageLayer) { // for a shared layer, allocate a shared image unit if necessary. if ( imageLayer->isShared() ) { optional<int>& unit = imageLayer->shareImageUnit(); if ( !unit.isSet() ) { int temp; if ( getResources()->reserveTextureImageUnit(temp) ) { imageLayer->shareImageUnit() = temp; OE_INFO << LC << "Image unit " << temp << " assigned to shared layer " << imageLayer->getName() << std::endl; } else { OE_WARN << LC << "Insufficient GPU image units to share layer " << imageLayer->getName() << std::endl; } } // Build a sampler binding for the shared layer. if ( unit.isSet() ) { // Find the next empty SHARED slot: unsigned newIndex = SamplerBinding::SHARED; while (_renderBindings[newIndex].isActive()) ++newIndex; // Put the new binding there: SamplerBinding& newBinding = _renderBindings[newIndex]; newBinding.usage() = SamplerBinding::SHARED; newBinding.sourceUID() = imageLayer->getUID(); newBinding.unit() = unit.get(); newBinding.samplerName() = imageLayer->shareTexUniformName().get(); newBinding.matrixName() = imageLayer->shareTexMatUniformName().get(); OE_INFO << LC << " .. Sampler=\"" << newBinding.samplerName() << "\", " << "Matrix=\"" << newBinding.matrixName() << ", " << "unit=" << newBinding.unit() << "\n"; } } } else { // non-image tile layer. Keep track of these.. } refresh(); } }
/** Packages an image layer as a TMS folder. */ int makeTMS( osg::ArgumentParser& args ) { // see if the user wants to override the type extension (imagery only) std::string extension; args.read( "--ext", extension ); // verbosity? bool verbose = !args.read( "--quiet" ); // find a .earth file on the command line std::string earthFile = findArgumentWithExtension(args, ".earth"); /* if ( earthFile.empty() ) return usage( "Missing required .earth file" ); */ // folder to which to write the TMS archive. std::string rootFolder; if ( !args.read( "--out", rootFolder ) ) rootFolder = Stringify() << earthFile << ".tms_repo"; // whether to overwrite existing tile files bool overwrite = false; if ( args.read("--overwrite") ) overwrite = true; // write out an earth file std::string outEarth; args.read("--out-earth", outEarth); std::string dbOptions; args.read("--db-options", dbOptions); std::string::size_type n = 0; while ((n=dbOptions.find('"', n))!=dbOptions.npos) { dbOptions.erase(n,1); } osg::ref_ptr<osgDB::Options> options = new osgDB::Options(dbOptions); std::vector< Bounds > bounds; // restrict packaging to user-specified bounds. double xmin=DBL_MAX, ymin=DBL_MAX, xmax=DBL_MIN, ymax=DBL_MIN; while (args.read("--bounds", xmin, ymin, xmax, ymax )) { Bounds b; b.xMin() = xmin, b.yMin() = ymin, b.xMax() = xmax, b.yMax() = ymax; bounds.push_back( b ); } // max level to which to generate unsigned maxLevel = ~0; args.read( "--max-level", maxLevel ); // whether to keep 'empty' tiles bool keepEmpties = args.read("--keep-empties"); bool continueSingleColor = args.read("--continue-single-color"); // load up the map osg::ref_ptr<MapNode> mapNode = MapNode::load( args ); if ( !mapNode.valid() ) return usage( "Failed to load a valid .earth file" ); // create a folder for the output osgDB::makeDirectory(rootFolder); if ( !osgDB::fileExists(rootFolder) ) return usage("Failed to create root output folder" ); Map* map = mapNode->getMap(); // fire up a packager: TMSPackager packager( map->getProfile(), options); packager.setVerbose( verbose ); packager.setOverwrite( overwrite ); packager.setKeepEmptyImageTiles( keepEmpties ); packager.setSubdivideSingleColorImageTiles( continueSingleColor ); if ( maxLevel != ~0 ) packager.setMaxLevel( maxLevel ); if (bounds.size() > 0) { for (unsigned int i = 0; i < bounds.size(); ++i) { Bounds b = bounds[i]; if ( b.isValid() ) packager.addExtent( GeoExtent(map->getProfile()->getSRS(), b) ); } } // new map for an output earth file if necessary. osg::ref_ptr<Map> outMap = 0L; if ( !outEarth.empty() ) { // copy the options from the source map first outMap = new Map(map->getInitialMapOptions()); } // establish the output path of the earth file, if applicable: std::string outEarthFile = osgDB::concatPaths(rootFolder, osgDB::getSimpleFileName(outEarth)); // package any image layers that are enabled: ImageLayerVector imageLayers; map->getImageLayers( imageLayers ); unsigned counter = 0; for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i, ++counter ) { ImageLayer* layer = i->get(); if ( layer->getImageLayerOptions().enabled() == true ) { std::string layerFolder = toLegalFileName( layer->getName() ); if ( layerFolder.empty() ) layerFolder = Stringify() << "image_layer_" << counter; if ( verbose ) { OE_NOTICE << LC << "Packaging image layer \"" << layerFolder << "\"" << std::endl; } osg::ref_ptr< ConsoleProgressCallback > progress = new ConsoleProgressCallback(); std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder ); TMSPackager::Result r = packager.package( layer, layerRoot, progress, extension ); if ( r.ok ) { // save to the output map if requested: if ( outMap.valid() ) { // new TMS driver info: TMSOptions tms; tms.url() = URI( osgDB::concatPaths(layerFolder, "tms.xml"), outEarthFile ); ImageLayerOptions layerOptions( layer->getName(), tms ); layerOptions.mergeConfig( layer->getInitialOptions().getConfig(true) ); layerOptions.cachePolicy() = CachePolicy::NO_CACHE; outMap->addImageLayer( new ImageLayer(layerOptions) ); } } else { OE_WARN << LC << r.message << std::endl; } } else if ( verbose ) { OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl; } } // package any elevation layers that are enabled: counter = 0; ElevationLayerVector elevationLayers; map->getElevationLayers( elevationLayers ); for( ElevationLayerVector::iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i, ++counter ) { ElevationLayer* layer = i->get(); if ( layer->getElevationLayerOptions().enabled() == true ) { std::string layerFolder = toLegalFileName( layer->getName() ); if ( layerFolder.empty() ) layerFolder = Stringify() << "elevation_layer_" << counter; if ( verbose ) { OE_NOTICE << LC << "Packaging elevation layer \"" << layerFolder << "\"" << std::endl; } std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder ); TMSPackager::Result r = packager.package( layer, layerRoot ); if ( r.ok ) { // save to the output map if requested: if ( outMap.valid() ) { // new TMS driver info: TMSOptions tms; tms.url() = URI( osgDB::concatPaths(layerFolder, "tms.xml"), outEarthFile ); ElevationLayerOptions layerOptions( layer->getName(), tms ); layerOptions.mergeConfig( layer->getInitialOptions().getConfig(true) ); layerOptions.cachePolicy() = CachePolicy::NO_CACHE; outMap->addElevationLayer( new ElevationLayer(layerOptions) ); } } else { OE_WARN << LC << r.message << std::endl; } } else if ( verbose ) { OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl; } } // Finally, write an earth file if requested: if ( outMap.valid() ) { MapNodeOptions outNodeOptions = mapNode->getMapNodeOptions(); osg::ref_ptr<MapNode> outMapNode = new MapNode(outMap.get(), outNodeOptions); if ( !osgDB::writeNodeFile(*outMapNode.get(), outEarthFile) ) { OE_WARN << LC << "Error writing earth file to \"" << outEarthFile << "\"" << std::endl; } else if ( verbose ) { OE_NOTICE << LC << "Wrote earth file to \"" << outEarthFile << "\"" << std::endl; } } return 0; }
void TileModelFactory::createTileModel(const TileKey& key, const MapFrame& frame, osg::ref_ptr<TileModel>& out_model) //, //bool& out_hasRealData) { osg::ref_ptr<TileModel> model = new TileModel( frame.getRevision(), frame.getMapInfo() ); model->_tileKey = key; model->_tileLocator = GeoLocator::createForKey(key, frame.getMapInfo()); // Fetch the image data and make color layers. unsigned order = 0; for( ImageLayerVector::const_iterator i = frame.imageLayers().begin(); i != frame.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() ) { BuildColorData build; build.init( key, layer, order, frame.getMapInfo(), _terrainOptions, model.get() ); bool addedToModel = build.execute(); if ( addedToModel ) { // only bump the order if we added something to the data model. order++; } } } // make an elevation layer. BuildElevationData build; build.init( key, frame, _terrainOptions, model.get(), _hfCache ); build.execute(); // Bail out now if there's no data to be had. if ( model->_colorData.size() == 0 && !model->_elevationData.getHeightField() ) { return; } // OK we are making a tile, so if there's no heightfield yet, make an empty one (and mark it // as fallback data of course) if ( !model->_elevationData.getHeightField() ) { osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 15, 15 ); model->_elevationData = TileModel::ElevationData( hf, GeoLocator::createForKey(key, frame.getMapInfo()), true ); } // look up the parent model and cache it. osg::ref_ptr<TileNode> parentTile; if ( _liveTiles->get(key.createParentKey(), parentTile) ) model->_parentModel = parentTile->getTileModel(); out_model = model.release(); }
int main(int argc, char** argv) { osg::ArgumentParser arguments(&argc,argv); // Which filter? bool useHSL = arguments.read("--hsl"); bool useRGB = arguments.read("--rgb"); bool useCMYK = arguments.read("--cmyk"); bool useBC = arguments.read("--bc"); bool useGamma = arguments.read("--gamma"); bool useChromaKey = arguments.read("--chromakey"); if ( !useHSL && !useRGB && !useCMYK && !useBC && !useGamma && !useChromaKey ) { return usage( "Please select one of the filter options!" ); } osgViewer::Viewer viewer(arguments); viewer.setCameraManipulator( new EarthManipulator() ); // load an earth file osg::Node* node = MapNodeHelper().load(arguments, &viewer); if ( !node ) return usage( "Unable to load map from earth file!" ); viewer.setSceneData( node ); //Create the control panel Container* box = createControlPanel(&viewer); osgEarth::MapNode* mapNode = osgEarth::MapNode::findMapNode( node ); if ( node ) { if (mapNode->getMap()->getNumImageLayers() == 0) { return usage("Please provide a map with at least one image layer."); } // attach color filter to each layer. unsigned numLayers = mapNode->getMap()->getNumImageLayers(); for( unsigned i=0; i<numLayers; ++i ) { ImageLayer* layer = mapNode->getMap()->getImageLayerAt( i ); if ( layer->getEnabled() && layer->getVisible() ) { if ( useHSL ) { HSLColorFilter* filter = new HSLColorFilter(); layer->addColorFilter( filter ); HSL::addControls( filter, box, i ); } else if ( useRGB ) { RGBColorFilter* filter = new RGBColorFilter(); layer->addColorFilter( filter ); RGB::addControls( filter, box, i ); } else if ( useCMYK ) { CMYKColorFilter* filter = new CMYKColorFilter(); layer->addColorFilter( filter ); CMYK::addControls( filter, box, i ); } else if ( useBC ) { BrightnessContrastColorFilter* filter = new BrightnessContrastColorFilter(); layer->addColorFilter( filter ); BC::addControls( filter, box, i ); } else if ( useGamma ) { GammaColorFilter* filter = new GammaColorFilter(); layer->addColorFilter( filter ); GAMMA::addControls( filter, box, i ); } else if ( useChromaKey ) { ChromaKeyColorFilter* filter = new ChromaKeyColorFilter(); layer->addColorFilter( filter ); CHROMAKEY::addControls( filter, box , i ); } } } } return viewer.run(); }