#include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { using namespace style; inline const style::CircleLayer::Impl& impl(const Immutable& impl) { return static_cast(*impl); } RenderCircleLayer::RenderCircleLayer(Immutable _impl) : RenderLayer(makeMutable(std::move(_impl))), unevaluated(impl(baseImpl).paint.untransitioned()) { } void RenderCircleLayer::transition(const TransitionParameters& parameters) { unevaluated = impl(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); } void RenderCircleLayer::evaluate(const PropertyEvaluationParameters& parameters) { auto properties = makeMutable( staticImmutableCast(baseImpl), unevaluated.evaluate(parameters)); const auto& evaluated = properties->evaluated; passes = ((evaluated.get().constantOr(1) > 0 || evaluated.get().constantOr(1) > 0) && (evaluated.get().constantOr(Color::black()).a > 0 || evaluated.get().constantOr(Color::black()).a > 0) && (evaluated.get().constantOr(1) > 0 || evaluated.get().constantOr(1) > 0)) ? RenderPass::Translucent : RenderPass::None; evaluatedProperties = std::move(properties); } bool RenderCircleLayer::hasTransition() const { return unevaluated.hasTransition(); } bool RenderCircleLayer::hasCrossfade() const { return false; } void RenderCircleLayer::render(PaintParameters& parameters) { assert(renderTiles); if (parameters.pass == RenderPass::Opaque) { return; } for (const RenderTile& tile : *renderTiles) { const LayerRenderData* renderData = tile.getLayerRenderData(*baseImpl); if (!renderData) { continue; } auto& bucket = static_cast(*renderData->bucket); const auto& evaluated = getEvaluated(renderData->layerProperties); const bool scaleWithMap = evaluated.get() == CirclePitchScaleType::Map; const bool pitchWithMap = evaluated.get() == AlignmentType::Map; const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); auto& programInstance = parameters.programs.getCircleLayerPrograms().circle; const auto allUniformValues = programInstance.computeAllUniformValues( CircleProgram::LayoutUniformValues { uniforms::matrix::Value( tile.translatedMatrix(evaluated.get(), evaluated.get(), parameters.state) ), uniforms::scale_with_map::Value( scaleWithMap ), uniforms::extrude_scale::Value( pitchWithMap ? std::array {{ tile.id.pixelsToTileUnits(1, parameters.state.getZoom()), tile.id.pixelsToTileUnits(1, parameters.state.getZoom()) }} : parameters.pixelsToGLUnits ), uniforms::device_pixel_ratio::Value( parameters.pixelRatio ), uniforms::camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ), uniforms::pitch_with_map::Value( pitchWithMap ) }, paintPropertyBinders, evaluated, parameters.state.getZoom() ); const auto allAttributeBindings = programInstance.computeAllAttributeBindings( *bucket.vertexBuffer, paintPropertyBinders, evaluated ); checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); programInstance.draw( parameters.context, *parameters.renderPass, gfx::Triangles(), parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly), gfx::StencilMode::disabled(), parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), *bucket.indexBuffer, bucket.segments, allUniformValues, allAttributeBindings, CircleProgram::TextureBindings{}, getID() ); } } GeometryCoordinate projectPoint(const GeometryCoordinate& p, const mat4& posMatrix, const Size& size) { vec4 pos = {{ static_cast(p.x), static_cast(p.y), 0, 1 }}; matrix::transformMat4(pos, pos, posMatrix); return { static_cast((static_cast(pos[0] / pos[3]) + 1) * size.width * 0.5), static_cast((static_cast(pos[1] / pos[3]) + 1) * size.height * 0.5) }; } GeometryCoordinates projectQueryGeometry(const GeometryCoordinates& queryGeometry, const mat4& posMatrix, const Size& size) { GeometryCoordinates projectedGeometry; for (auto& p : queryGeometry) { projectedGeometry.push_back(projectPoint(p, posMatrix, size)); } return projectedGeometry; } bool RenderCircleLayer::queryIntersectsFeature( const GeometryCoordinates& queryGeometry, const GeometryTileFeature& feature, const float zoom, const TransformState& transformState, const float pixelsToTileUnits, const mat4& posMatrix) const { const auto& evaluated = static_cast(*evaluatedProperties).evaluated; // Translate query geometry const GeometryCoordinates& translatedQueryGeometry = FeatureIndex::translateQueryGeometry( queryGeometry, evaluated.get(), evaluated.get(), transformState.getBearing(), pixelsToTileUnits).value_or(queryGeometry); // Evaluate functions auto radius = evaluated.evaluate(zoom, feature); auto stroke = evaluated.evaluate(zoom, feature); auto size = radius + stroke; // For pitch-alignment: map, compare feature geometry to query geometry in the plane of the tile // Otherwise, compare geometry in the plane of the viewport // A circle with fixed scaling relative to the viewport gets larger in tile space as it moves into the distance // A circle with fixed scaling relative to the map gets smaller in viewport space as it moves into the distance bool alignWithMap = evaluated.evaluate(zoom, feature) == AlignmentType::Map; const GeometryCoordinates& transformedQueryGeometry = alignWithMap ? translatedQueryGeometry : projectQueryGeometry(translatedQueryGeometry, posMatrix, transformState.getSize()); auto transformedSize = alignWithMap ? size * pixelsToTileUnits : size; auto geometry = feature.getGeometries(); for (auto& ring : geometry) { for (auto& point : ring) { const GeometryCoordinate& transformedPoint = alignWithMap ? point : projectPoint(point, posMatrix, transformState.getSize()); float adjustedSize = transformedSize; vec4 center = {{ static_cast(point.x), static_cast(point.y), 0, 1 }}; matrix::transformMat4(center, center, posMatrix); auto pitchScale = evaluated.evaluate(zoom, feature); auto pitchAlignment = evaluated.evaluate(zoom, feature); if (pitchScale == CirclePitchScaleType::Viewport && pitchAlignment == AlignmentType::Map) { adjustedSize *= center[3] / transformState.getCameraToCenterDistance(); } else if (pitchScale == CirclePitchScaleType::Map && pitchAlignment == AlignmentType::Viewport) { adjustedSize *= transformState.getCameraToCenterDistance() / center[3]; } if (util::polygonIntersectsBufferedPoint(transformedQueryGeometry, transformedPoint, adjustedSize)) return true; } } return false; } } // namespace mbgl