#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { using namespace style; RenderFillExtrusionLayer::RenderFillExtrusionLayer(Immutable _impl) : RenderLayer(std::move(_impl)), unevaluated(impl().paint.untransitioned()) { } const style::FillExtrusionLayer::Impl& RenderFillExtrusionLayer::impl() const { return static_cast(*baseImpl); } std::unique_ptr RenderFillExtrusionLayer::createBucket(const BucketParameters&, const std::vector&) const { // Should be calling createLayout() instead. assert(baseImpl->getTypeInfo()->layout == LayerTypeInfo::Layout::NotRequired); return nullptr; } std::unique_ptr RenderFillExtrusionLayer::createLayout(const BucketParameters& parameters, const std::vector& group, std::unique_ptr layer, GlyphDependencies&, ImageDependencies& imageDependencies) const { return std::make_unique>(parameters, group, std::move(layer), imageDependencies); } void RenderFillExtrusionLayer::transition(const TransitionParameters& parameters) { unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated)); } void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& parameters) { evaluated = unevaluated.evaluate(parameters); crossfade = parameters.getCrossfadeParameters(); passes = (evaluated.get() > 0) ? (RenderPass::Translucent | RenderPass::Pass3D) : RenderPass::None; } bool RenderFillExtrusionLayer::hasTransition() const { return unevaluated.hasTransition(); } bool RenderFillExtrusionLayer::hasCrossfade() const { return crossfade.t != 1; } void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*) { if (parameters.pass == RenderPass::Opaque) { return; } if (parameters.pass == RenderPass::Pass3D) { const auto& size = parameters.staticData.backendSize; if (!renderTexture || renderTexture->getSize() != size) { renderTexture = OffscreenTexture(parameters.context, size, *parameters.staticData.depthRenderbuffer); } renderTexture->bind(); optional depthClearValue = {}; if (parameters.staticData.depthRenderbuffer->needsClearing()) depthClearValue = 1.0; // Flag the depth buffer as no longer needing to be cleared for the remainder of this pass. parameters.staticData.depthRenderbuffer->shouldClear(false); parameters.context.setStencilMode(gl::StencilMode::disabled()); parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, depthClearValue, {}); auto draw = [&](auto& programInstance, const auto& tileBucket, auto&& uniformValues, const optional& patternPositionA, const optional& patternPositionB) { const auto& paintPropertyBinders = tileBucket.paintPropertyBinders.at(getID()); paintPropertyBinders.setPatternParameters(patternPositionA, patternPositionB, crossfade); const auto allUniformValues = programInstance.computeAllUniformValues( std::move(uniformValues), paintPropertyBinders, evaluated, parameters.state.getZoom() ); const auto allAttributeBindings = programInstance.computeAllAttributeBindings( *tileBucket.vertexBuffer, paintPropertyBinders, evaluated ); checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); programInstance.draw( parameters.context, gl::Triangles(), parameters.depthModeFor3D(gl::DepthMode::ReadWrite), gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), gl::CullFaceMode::backCCW(), *tileBucket.indexBuffer, tileBucket.triangleSegments, allUniformValues, allAttributeBindings, getID()); }; if (unevaluated.get().isUndefined()) { for (const RenderTile& tile : renderTiles) { auto bucket_ = tile.tile.getBucket(*baseImpl); if (!bucket_) { continue; } FillExtrusionBucket& bucket = *bucket_; draw( parameters.programs.getFillExtrusionLayerPrograms().fillExtrusion.get(evaluated), bucket, FillExtrusionUniforms::values( tile.translatedClipMatrix(evaluated.get(), evaluated.get(), parameters.state), parameters.state, parameters.evaluatedLight ), {}, {} ); } } else { for (const RenderTile& tile : renderTiles) { auto bucket_ = tile.tile.getBucket(*baseImpl); if (!bucket_) { continue; } const auto fillPatternValue = evaluated.get().constantOr(mbgl::Faded >{"", ""}); assert(dynamic_cast(&tile.tile)); GeometryTile& geometryTile = static_cast(tile.tile); optional patternPosA = geometryTile.getPattern(fillPatternValue.from); optional patternPosB = geometryTile.getPattern(fillPatternValue.to); parameters.context.bindTexture(*geometryTile.iconAtlasTexture, 0, gl::TextureFilter::Linear); FillExtrusionBucket& bucket = *bucket_; draw( parameters.programs.getFillExtrusionLayerPrograms().fillExtrusionPattern.get(evaluated), bucket, FillExtrusionPatternUniforms::values( tile.translatedClipMatrix(evaluated.get(), evaluated.get(), parameters.state), geometryTile.iconAtlasTexture->size, crossfade, tile.id, parameters.state, -std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f, parameters.pixelRatio, parameters.evaluatedLight ), patternPosA, patternPosB ); } } } else if (parameters.pass == RenderPass::Translucent) { parameters.context.bindTexture(renderTexture->getTexture()); const auto& size = parameters.staticData.backendSize; mat4 viewportMat; matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1); const Properties<>::PossiblyEvaluated properties; const ExtrusionTextureProgram::PaintPropertyBinders paintAttributeData{ properties, 0 }; auto& programInstance = parameters.programs.getFillExtrusionLayerPrograms().extrusionTexture; const auto allUniformValues = programInstance.computeAllUniformValues( ExtrusionTextureProgram::UniformValues{ uniforms::u_matrix::Value( viewportMat ), uniforms::u_world::Value( size ), uniforms::u_image::Value( 0 ), uniforms::u_opacity::Value( evaluated.get() ) }, paintAttributeData, properties, parameters.state.getZoom() ); const auto allAttributeBindings = programInstance.computeAllAttributeBindings( parameters.staticData.extrusionTextureVertexBuffer, paintAttributeData, properties ); checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); programInstance.draw( parameters.context, gl::Triangles(), gl::DepthMode::disabled(), gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), gl::CullFaceMode::disabled(), parameters.staticData.quadTriangleIndexBuffer, parameters.staticData.extrusionTextureSegments, allUniformValues, allAttributeBindings, getID()); } } style::FillExtrusionPaintProperties::PossiblyEvaluated RenderFillExtrusionLayer::paintProperties() const { return FillExtrusionPaintProperties::PossiblyEvaluated { evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get(), evaluated.get() }; } bool RenderFillExtrusionLayer::queryIntersectsFeature( const GeometryCoordinates& queryGeometry, const GeometryTileFeature& feature, const float, const TransformState& transformState, const float pixelsToTileUnits, const mat4&) const { auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry( queryGeometry, evaluated.get(), evaluated.get(), transformState.getAngle(), pixelsToTileUnits); return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries()); } } // namespace mbgl