#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(std::move(_impl)), unevaluated(impl().paint.untransitioned()) { } const style::SymbolLayer::Impl& RenderSymbolLayer::impl() const { return static_cast(*baseImpl); } 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(); } bool RenderSymbolLayer::hasCrossfade() const { return false; } const std::string& RenderSymbolLayer::layerID() const { return RenderLayer::getID(); } const RenderLayerSymbolInterface* RenderSymbolLayer::getSymbolInterface() const { return this; } const std::vector>& RenderSymbolLayer::getRenderTiles() const { return renderTiles; } SymbolBucket* RenderSymbolLayer::getSymbolBucket(const RenderTile& renderTile) const { return renderTile.tile.getBucket(*baseImpl); } void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (parameters.pass == RenderPass::Opaque) { return; } for (const RenderTile& tile : renderTiles) { auto bucket_ = tile.tile.getBucket(*baseImpl); if (!bucket_) { continue; } SymbolBucket& bucket = *bucket_; assert(bucket.paintProperties.find(getID()) != bucket.paintProperties.end()); const auto& bucketPaintProperties = bucket.paintProperties.at(getID()); const auto& evaluated_ = bucketPaintProperties.evaluated; 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) { auto& programInstance = program.get(paintProperties); const auto allUniformValues = programInstance.computeAllUniformValues( std::move(uniformValues), *symbolSizeBinder, binders, paintProperties, parameters.state.getZoom() ); const auto allAttributeBindings = programInstance.computeAllAttributeBindings( *buffers.vertexBuffer, *buffers.dynamicVertexBuffer, *buffers.opacityVertexBuffer, binders, paintProperties ); checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); programInstance.draw( parameters.context, gfx::Triangles(), values_.pitchAlignment == AlignmentType::Map ? parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly) : gfx::DepthMode::disabled(), gfx::StencilMode::disabled(), parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), *buffers.indexBuffer, buffers.segments, allUniformValues, allAttributeBindings, getID() ); }; assert(tile.tile.kind == Tile::Kind::Geometry); GeometryTile& geometryTile = static_cast(tile.tile); if (bucket.hasIconData()) { auto values = iconPropertyValues(evaluated_, layout); const auto& paintPropertyValues = iconPaintProperties(evaluated_); const bool alongLine = layout.get() != SymbolPlacementType::Point && 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 ? gfx::TextureFilterType::Linear : gfx::TextureFilterType::Nearest); const Size texsize = geometryTile.iconAtlasTexture->size; if (bucket.sdfIcons) { if (values.hasHalo) { draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF, SymbolSDFIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), bucket.icon, bucket.iconSizeBinder, values, bucketPaintProperties.iconBinders, paintPropertyValues); } if (values.hasFill) { draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF, SymbolSDFIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), bucket.icon, bucket.iconSizeBinder, values, bucketPaintProperties.iconBinders, paintPropertyValues); } } else { draw(parameters.programs.getSymbolLayerPrograms().symbolIcon, SymbolIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange), bucket.icon, bucket.iconSizeBinder, values, bucketPaintProperties.iconBinders, paintPropertyValues); } } if (bucket.hasTextData()) { parameters.context.bindTexture(*geometryTile.glyphAtlasTexture, 0, gfx::TextureFilterType::Linear); auto values = textPropertyValues(evaluated_, layout); const auto& paintPropertyValues = textPaintProperties(evaluated_); const bool alongLine = layout.get() != SymbolPlacementType::Point && 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.getSymbolLayerPrograms().symbolGlyph, SymbolSDFTextProgram::uniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), bucket.text, bucket.textSizeBinder, values, bucketPaintProperties.textBinders, paintPropertyValues); } if (values.hasFill) { draw(parameters.programs.getSymbolLayerPrograms().symbolGlyph, SymbolSDFTextProgram::uniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), bucket.text, bucket.textSizeBinder, values, bucketPaintProperties.textBinders, paintPropertyValues); } } if (bucket.hasCollisionBoxData()) { static const style::Properties<>::PossiblyEvaluated properties {}; static const CollisionBoxProgram::Binders paintAttributeData(properties, 0); auto pixelRatio = tile.id.pixelsToTileUnits(1, parameters.state.getZoom()); const float scale = std::pow(2, parameters.state.getZoom() - tile.tile.id.overscaledZ); std::array extrudeScale = {{ parameters.pixelsToGLUnits[0] / (pixelRatio * scale), parameters.pixelsToGLUnits[1] / (pixelRatio * scale) }}; parameters.programs.getSymbolLayerPrograms().collisionBox.draw( parameters.context, gfx::Lines { 1.0f }, gfx::DepthMode::disabled(), gfx::StencilMode::disabled(), parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), 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::Binders paintAttributeData(properties, 0); auto pixelRatio = tile.id.pixelsToTileUnits(1, parameters.state.getZoom()); const float scale = std::pow(2, parameters.state.getZoom() - tile.tile.id.overscaledZ); std::array extrudeScale = {{ parameters.pixelsToGLUnits[0] / (pixelRatio * scale), parameters.pixelsToGLUnits[1] / (pixelRatio * scale) }}; parameters.programs.getSymbolLayerPrograms().collisionCircle.draw( parameters.context, gfx::Triangles(), gfx::DepthMode::disabled(), gfx::StencilMode::disabled(), parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), 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() ); } } } // static style::IconPaintProperties::PossiblyEvaluated RenderSymbolLayer::iconPaintProperties(const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_) { return style::IconPaintProperties::PossiblyEvaluated { evaluated_.get(), evaluated_.get(), evaluated_.get(), evaluated_.get(), evaluated_.get(), evaluated_.get(), evaluated_.get() }; } // static style::TextPaintProperties::PossiblyEvaluated RenderSymbolLayer::textPaintProperties(const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_) { return style::TextPaintProperties::PossiblyEvaluated { evaluated_.get(), evaluated_.get(), evaluated_.get(), evaluated_.get(), evaluated_.get(), evaluated_.get(), evaluated_.get() }; } // static style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_, const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) { 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 }; } // static style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_, const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) { 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 }; } RenderLayer::RenderTiles RenderSymbolLayer::filterRenderTiles(RenderTiles tiles) const { auto filterFn = [](auto& tile){ return !tile.tile.isRenderable(); }; return RenderLayer::filterRenderTiles(std::move(tiles), filterFn); } void RenderSymbolLayer::sortRenderTiles(const TransformState& state) { // Sort symbol tiles in opposite y position, so tiles with overlapping symbols are drawn // on top of each other, with lower symbols being drawn on top of higher symbols. std::sort(renderTiles.begin(), renderTiles.end(), [&state](const auto& a, const auto& b) { Point pa(a.get().id.canonical.x, a.get().id.canonical.y); Point pb(b.get().id.canonical.x, b.get().id.canonical.y); auto par = util::rotate(pa, state.getBearing()); auto pbr = util::rotate(pb, state.getBearing()); return std::tie(b.get().id.canonical.z, par.y, par.x) < std::tie(a.get().id.canonical.z, pbr.y, pbr.x); }); } void RenderSymbolLayer::updateBucketPaintProperties(Bucket* bucket) const { assert(bucket->supportsLayer(*baseImpl)); static_cast(bucket)->paintProperties.at(getID()).evaluated = evaluated; } } // namespace mbgl