/** * Creates a complete set of positioned label nodes from a feature list. */ osg::Node* createNode( const FeatureList& input, const Style& style, FilterContext& context ) { if ( style.get<TextSymbol>() == 0L && style.get<IconSymbol>() == 0L ) return 0L; // copy the style so we can (potentially) modify the text symbol. Style styleCopy = style; TextSymbol* text = styleCopy.get<TextSymbol>(); IconSymbol* icon = styleCopy.get<IconSymbol>(); osg::Group* group = new osg::Group(); StringExpression textContentExpr ( text ? *text->content() : StringExpression() ); NumericExpression textPriorityExpr( text ? *text->priority() : NumericExpression() ); NumericExpression textSizeExpr ( text ? *text->size() : NumericExpression() ); StringExpression iconUrlExpr ( icon ? *icon->url() : StringExpression() ); NumericExpression iconScaleExpr ( icon ? *icon->scale() : NumericExpression() ); NumericExpression iconHeadingExpr ( icon ? *icon->heading() : NumericExpression() ); for( FeatureList::const_iterator i = input.begin(); i != input.end(); ++i ) { Feature* feature = i->get(); if ( !feature ) continue; // run a symbol script if present. if ( text && text->script().isSet() ) { StringExpression temp( text->script().get() ); feature->eval( temp, &context ); } // run a symbol script if present. if ( icon && icon->script().isSet() ) { StringExpression temp( icon->script().get() ); feature->eval( temp, &context ); } const Geometry* geom = feature->getGeometry(); if ( !geom ) continue; Style tempStyle = styleCopy; // evaluate expressions into literals. // TODO: Later we could replace this with a generate "expression evaluator" type // that we could pass to PlaceNode in the DB options. -gw if ( text ) { if ( text->content().isSet() ) tempStyle.get<TextSymbol>()->content()->setLiteral( feature->eval( textContentExpr, &context ) ); if ( text->size().isSet() ) tempStyle.get<TextSymbol>()->size()->setLiteral( feature->eval(textSizeExpr, &context) ); } if ( icon ) { if ( icon->url().isSet() ) tempStyle.get<IconSymbol>()->url()->setLiteral( feature->eval(iconUrlExpr, &context) ); if ( icon->scale().isSet() ) tempStyle.get<IconSymbol>()->scale()->setLiteral( feature->eval(iconScaleExpr, &context) ); if ( icon->heading().isSet() ) tempStyle.get<IconSymbol>()->heading()->setLiteral( feature->eval(iconHeadingExpr, &context) ); } osg::Node* node = makePlaceNode( context, feature, tempStyle, textPriorityExpr); if ( node ) { if ( context.featureIndex() ) { context.featureIndex()->tagNode(node, feature); } group->addChild( node ); } } // Note to self: need to change this to support picking later. -gw //VirtualProgram* vp = VirtualProgram::getOrCreate(group->getOrCreateStateSet()); //vp->setInheritShaders( false ); return group; }
void TrackNode::init( const TrackNodeFieldSchema& schema ) { osg::StateSet* ss = this->getOrCreateStateSet(); ScreenSpaceLayout::activate(ss); // Disable lighting for place nodes by default ss->setDefine(OE_LIGHTING_DEFINE, osg::StateAttribute::OFF); osgEarth::clearChildren( getPositionAttitudeTransform() ); _geode = new osg::Geode(); IconSymbol* icon = _style.get<IconSymbol>(); osg::Image* image = icon ? icon->getImage() : 0L; if ( icon && image ) { // apply the image icon. osg::Geometry* imageGeom = AnnotationUtils::createImageGeometry( image, // image osg::Vec2s(0,0), // offset 0, // tex image unit icon->heading()->eval(), icon->scale()->eval() ); if ( imageGeom ) { _geode->addDrawable( imageGeom ); ScreenSpaceLayoutData* layout = new ScreenSpaceLayoutData(); layout->setPriority(getPriority()); imageGeom->setUserData(layout); } } if ( !schema.empty() ) { // turn the schema defs into text drawables and record a map so we can // set the field text later. for( TrackNodeFieldSchema::const_iterator i = schema.begin(); i != schema.end(); ++i ) { const TrackNodeField& field = i->second; if ( field._symbol.valid() ) { osg::Vec3 offset( field._symbol->pixelOffset()->x(), field._symbol->pixelOffset()->y(), 0.0); osg::Drawable* drawable = AnnotationUtils::createTextDrawable( field._symbol->content()->expr(), // text field._symbol.get(), // symbol offset ); // offset if ( drawable ) { // if the user intends to change the label later, make it dynamic // since osgText updates are not thread-safe if ( field._dynamic ) drawable->setDataVariance( osg::Object::DYNAMIC ); else drawable->setDataVariance( osg::Object::STATIC ); addDrawable( i->first, drawable ); } } } } // ensure depth testing always passes, and disable depth buffer writes. osg::StateSet* stateSet = _geode->getOrCreateStateSet(); stateSet->setAttributeAndModes( new osg::Depth(osg::Depth::ALWAYS, 0, 1, false), 1 ); applyStyle( _style ); setLightingIfNotSet( false ); getPositionAttitudeTransform()->addChild( _geode ); // generate shaders: Registry::shaderGenerator().run( this, "osgEarth.TrackNode", Registry::stateSetCache() ); }