#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { using namespace style; RenderSymbolLayer::RenderSymbolLayer(Immutable _impl) : RenderLayer(style::LayerType::Symbol, _impl), unevaluated(impl().paint.untransitioned()) { } const style::SymbolLayer::Impl& RenderSymbolLayer::impl() const { return static_cast(*baseImpl); } std::unique_ptr RenderSymbolLayer::createBucket(const BucketParameters&, const std::vector&) const { assert(false); // Should be calling createLayout() instead. return nullptr; } std::unique_ptr RenderSymbolLayer::createLayout(const BucketParameters& parameters, const std::vector& group, std::unique_ptr layer, GlyphDependencies& glyphDependencies, ImageDependencies& imageDependencies) const { return std::make_unique(parameters, group, std::move(layer), imageDependencies, glyphDependencies); } void RenderSymbolLayer::transition(const TransitionParameters& parameters) { unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated)); } void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters) { evaluated = unevaluated.evaluate(parameters); auto hasIconOpacity = evaluated.get().constantOr(Color::black()).a > 0 || evaluated.get().constantOr(Color::black()).a > 0; auto hasTextOpacity = evaluated.get().constantOr(Color::black()).a > 0 || evaluated.get().constantOr(Color::black()).a > 0; passes = ((evaluated.get().constantOr(1) > 0 && hasIconOpacity && iconSize > 0) || (evaluated.get().constantOr(1) > 0 && hasTextOpacity && textSize > 0)) ? RenderPass::Translucent : RenderPass::None; } bool RenderSymbolLayer::hasTransition() const { return unevaluated.hasTransition(); } void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (parameters.pass == RenderPass::Opaque) { return; } for (const RenderTile& tile : renderTiles) { assert(dynamic_cast(tile.tile.getBucket(*baseImpl))); SymbolBucket& bucket = *reinterpret_cast(tile.tile.getBucket(*baseImpl)); const auto& layout = bucket.layout; auto draw = [&] (auto& program, auto&& uniformValues, const auto& buffers, const auto& symbolSizeBinder, const SymbolPropertyValues& values_, const auto& binders, const auto& paintProperties) { program.get(paintProperties).draw( parameters.context, gl::Triangles(), values_.pitchAlignment == AlignmentType::Map ? parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly) : gl::DepthMode::disabled(), gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), std::move(uniformValues), *buffers.vertexBuffer, *buffers.dynamicVertexBuffer, *buffers.opacityVertexBuffer, *symbolSizeBinder, *buffers.indexBuffer, buffers.segments, binders, paintProperties, parameters.state.getZoom(), getID() ); }; assert(dynamic_cast(&tile.tile)); GeometryTile& geometryTile = static_cast(tile.tile); if (bucket.hasIconData()) { auto values = iconPropertyValues(layout); auto paintPropertyValues = iconPaintProperties(); const bool alongLine = layout.get() == SymbolPlacementType::Line && layout.get() == AlignmentType::Map; if (alongLine) { reprojectLineLabels(bucket.icon.dynamicVertices, bucket.icon.placedSymbols, tile.matrix, values, tile, *bucket.iconSizeBinder, parameters.state); parameters.context.updateVertexBuffer(*bucket.icon.dynamicVertexBuffer, std::move(bucket.icon.dynamicVertices)); } const bool iconScaled = layout.get().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear; const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || parameters.state.getPitch() != 0; parameters.context.bindTexture(*geometryTile.iconAtlasTexture, 0, bucket.sdfIcons || parameters.state.isChanging() || iconScaled || iconTransformed ? gl::TextureFilter::Linear : gl::TextureFilter::Nearest); const Size texsize = geometryTile.iconAtlasTexture->size; if (bucket.sdfIcons) { if (values.hasHalo) { draw(parameters.programs.symbolIconSDF, SymbolSDFIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), bucket.icon, bucket.iconSizeBinder, values, bucket.paintPropertyBinders.at(getID()).first, paintPropertyValues); } if (values.hasFill) { draw(parameters.programs.symbolIconSDF, SymbolSDFIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), bucket.icon, bucket.iconSizeBinder, values, bucket.paintPropertyBinders.at(getID()).first, paintPropertyValues); } } else { draw(parameters.programs.symbolIcon, SymbolIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange), bucket.icon, bucket.iconSizeBinder, values, bucket.paintPropertyBinders.at(getID()).first, paintPropertyValues); } } if (bucket.hasTextData()) { parameters.context.bindTexture(*geometryTile.glyphAtlasTexture, 0, gl::TextureFilter::Linear); auto values = textPropertyValues(layout); auto paintPropertyValues = textPaintProperties(); const bool alongLine = layout.get() == SymbolPlacementType::Line && layout.get() == AlignmentType::Map; if (alongLine) { reprojectLineLabels(bucket.text.dynamicVertices, bucket.text.placedSymbols, tile.matrix, values, tile, *bucket.textSizeBinder, parameters.state); parameters.context.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices)); } const Size texsize = geometryTile.glyphAtlasTexture->size; if (values.hasHalo) { draw(parameters.programs.symbolGlyph, SymbolSDFTextProgram::uniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), bucket.text, bucket.textSizeBinder, values, bucket.paintPropertyBinders.at(getID()).second, paintPropertyValues); } if (values.hasFill) { draw(parameters.programs.symbolGlyph, SymbolSDFTextProgram::uniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), bucket.text, bucket.textSizeBinder, values, bucket.paintPropertyBinders.at(getID()).second, paintPropertyValues); } } if (bucket.hasCollisionBoxData()) { static const style::Properties<>::PossiblyEvaluated properties {}; static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0); auto pixelRatio = tile.id.pixelsToTileUnits(1, parameters.state.getZoom()); auto scale = std::pow(2.0f, float(parameters.state.getZoom() - tile.tile.id.overscaledZ)); std::array extrudeScale = {{ parameters.pixelsToGLUnits[0] / (pixelRatio * scale), parameters.pixelsToGLUnits[1] / (pixelRatio * scale) }}; parameters.programs.collisionBox.draw( parameters.context, gl::Lines { 1.0f }, gl::DepthMode::disabled(), gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), CollisionBoxProgram::UniformValues { uniforms::u_matrix::Value{ tile.matrix }, uniforms::u_extrude_scale::Value{ extrudeScale }, uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() } }, *bucket.collisionBox.vertexBuffer, *bucket.collisionBox.dynamicVertexBuffer, *bucket.collisionBox.indexBuffer, bucket.collisionBox.segments, paintAttributeData, properties, parameters.state.getZoom(), getID() ); } if (bucket.hasCollisionCircleData()) { static const style::Properties<>::PossiblyEvaluated properties {}; static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0); auto pixelRatio = tile.id.pixelsToTileUnits(1, parameters.state.getZoom()); auto scale = std::pow(2.0f, float(parameters.state.getZoom() - tile.tile.id.overscaledZ)); std::array extrudeScale = {{ parameters.pixelsToGLUnits[0] / (pixelRatio * scale), parameters.pixelsToGLUnits[1] / (pixelRatio * scale) }}; parameters.programs.collisionCircle.draw( parameters.context, gl::Triangles(), gl::DepthMode::disabled(), gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), CollisionCircleProgram::UniformValues { uniforms::u_matrix::Value{ tile.matrix }, uniforms::u_extrude_scale::Value{ extrudeScale }, uniforms::u_overscale_factor::Value{ float(tile.tile.id.overscaleFactor()) }, uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() } }, *bucket.collisionCircle.vertexBuffer, *bucket.collisionCircle.dynamicVertexBuffer, *bucket.collisionCircle.indexBuffer, bucket.collisionCircle.segments, paintAttributeData, properties, parameters.state.getZoom(), getID() ); } } } style::IconPaintProperties::PossiblyEvaluated RenderSymbolLayer::iconPaintProperties() const { return style::IconPaintProperties::PossiblyEvaluated { evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get() }; } style::TextPaintProperties::PossiblyEvaluated RenderSymbolLayer::textPaintProperties() const { return style::TextPaintProperties::PossiblyEvaluated { evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get() }; } style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const { return style::SymbolPropertyValues { layout_.get(), layout_.get(), layout_.get(), evaluated.get(), evaluated.get(), evaluated.get().constantOr(Color::black()).a > 0 && evaluated.get().constantOr(1), evaluated.get().constantOr(Color::black()).a > 0, 10.0f }; } style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const { // We hide line labels with viewport alignment as they move into the distance // because the approximations we use for drawing their glyphs get progressively worse // The "1.5" here means we start hiding them when the distance from the label // to the camera is 50% greater than the distance from the center of the map // to the camera. Depending on viewport properties, you might expect this to filter // the top third of the screen at pitch 60, and do almost nothing at pitch 45 // "10" is effectively infinite at any pitch we support const bool limitMaxDistance = layout_.get() == style::SymbolPlacementType::Line && layout_.get() == style::AlignmentType::Map && layout_.get() == style::AlignmentType::Viewport; return style::SymbolPropertyValues { layout_.get(), layout_.get(), layout_.get(), evaluated.get(), evaluated.get(), evaluated.get().constantOr(Color::black()).a > 0 && evaluated.get().constantOr(1), evaluated.get().constantOr(Color::black()).a > 0, limitMaxDistance ? 1.5f : 10.0f }; } } // namespace mbgl