#include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { using namespace style; namespace { inline const BackgroundLayer::Impl& impl_cast(const Immutable& impl) { assert(impl->getTypeInfo() == BackgroundLayer::Impl::staticTypeInfo()); return static_cast(*impl); } } // namespace RenderBackgroundLayer::RenderBackgroundLayer(Immutable _impl) : RenderLayer(makeMutable(std::move(_impl))), unevaluated(impl_cast(baseImpl).paint.untransitioned()) {} RenderBackgroundLayer::~RenderBackgroundLayer() = default; void RenderBackgroundLayer::transition(const TransitionParameters ¶meters) { unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); } void RenderBackgroundLayer::evaluate(const PropertyEvaluationParameters ¶meters) { auto properties = makeMutable( staticImmutableCast(baseImpl), parameters.getCrossfadeParameters(), unevaluated.evaluate(parameters)); passes = properties->evaluated.get() == 0.0f ? RenderPass::None : (!unevaluated.get().isUndefined() || properties->evaluated.get() < 1.0f || properties->evaluated.get().a < 1.0f) ? RenderPass::Translucent // Supply both - evaluated based on opaquePassCutoff in render(). : RenderPass::Opaque | RenderPass::Translucent; properties->renderPasses = mbgl::underlying_type(passes); evaluatedProperties = std::move(properties); } bool RenderBackgroundLayer::hasTransition() const { return unevaluated.hasTransition(); } bool RenderBackgroundLayer::hasCrossfade() const { return getCrossfade(evaluatedProperties).t != 1; } void RenderBackgroundLayer::render(PaintParameters& parameters) { // Note that for bottommost layers without a pattern, the background color is drawn with // glClear rather than this method. const Properties<>::PossiblyEvaluated properties; const BackgroundProgram::Binders paintAttributeData(properties, 0); auto draw = [&](auto& program, auto&& uniformValues, const auto& textureBindings, const uint32_t id) { const auto allUniformValues = program.computeAllUniformValues(std::forward(uniformValues), paintAttributeData, properties, parameters.state.getZoom()); const auto allAttributeBindings = program.computeAllAttributeBindings( *parameters.staticData.tileVertexBuffer, paintAttributeData, properties ); checkRenderability(parameters, program.activeBindingCount(allAttributeBindings)); program.draw( parameters.context, *parameters.renderPass, gfx::Triangles(), parameters.depthModeForSublayer( 0, parameters.pass == RenderPass::Opaque ? gfx::DepthMaskType::ReadWrite : gfx::DepthMaskType::ReadOnly), gfx::StencilMode::disabled(), parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), *parameters.staticData.quadTriangleIndexBuffer, segments, allUniformValues, allAttributeBindings, textureBindings, util::toString(id)); }; if (segments.empty()) { segments = RenderStaticData::tileTriangleSegments(); } const auto& evaluated = static_cast(*evaluatedProperties).evaluated; const auto& crossfade = static_cast(*evaluatedProperties).crossfade; if (!evaluated.get().to.empty()) { optional imagePosA = parameters.patternAtlas.getPattern(evaluated.get().from.id()); optional imagePosB = parameters.patternAtlas.getPattern(evaluated.get().to.id()); if (!imagePosA || !imagePosB) return; uint32_t i = 0; for (const auto& tileID : util::tileCover(parameters.state, parameters.state.getIntegerZoom())) { const UnwrappedTileID unwrappedTileID = tileID.toUnwrapped(); draw(parameters.programs.getBackgroundLayerPrograms().backgroundPattern, BackgroundPatternProgram::layoutUniformValues(parameters.matrixForTile(unwrappedTileID), evaluated.get(), parameters.patternAtlas.getPixelSize(), *imagePosA, *imagePosB, crossfade, unwrappedTileID, parameters.state), BackgroundPatternProgram::TextureBindings{ textures::image::Value{parameters.patternAtlas.textureBinding()}, }, i++); } } else { auto backgroundRenderPass = (evaluated.get().a >= 1.0f && evaluated.get() >= 1.0f && parameters.currentLayer >= parameters.opaquePassCutoff) ? RenderPass::Opaque : RenderPass::Translucent; if (parameters.pass != backgroundRenderPass) { return; } uint32_t i = 0; for (const auto& tileID : util::tileCover(parameters.state, parameters.state.getIntegerZoom())) { draw(parameters.programs.getBackgroundLayerPrograms().background, BackgroundProgram::LayoutUniformValues{ uniforms::matrix::Value(parameters.matrixForTile(tileID.toUnwrapped())), uniforms::color::Value(evaluated.get()), uniforms::opacity::Value(evaluated.get()), }, BackgroundProgram::TextureBindings{}, i++); } } } optional RenderBackgroundLayer::getSolidBackground() const { const auto& evaluated = getEvaluated(evaluatedProperties); if (!evaluated.get().from.empty() || evaluated.get() <= 0.0f) { return nullopt; } return { evaluated.get() * evaluated.get() }; } namespace { void addPatternIfNeeded(const std::string& id, const LayerPrepareParameters& params) { if (!params.patternAtlas.getPattern(id)) { if (auto* image = params.imageManager.getImage(id)) { params.patternAtlas.addPattern(*image); } } } } // namespace void RenderBackgroundLayer::prepare(const LayerPrepareParameters& params) { const auto& evaluated = getEvaluated(evaluatedProperties); if (!evaluated.get().to.empty()) { // Ensures that the pattern bitmap gets copied to atlas bitmap. // Atlas bitmap is uploaded to atlas texture in upload. addPatternIfNeeded(evaluated.get().from.id(), params); addPatternIfNeeded(evaluated.get().to.id(), params); } } } // namespace mbgl