void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source) { if (parameters.pass != RenderPass::Translucent) return; auto draw = [&] (const mat4& matrix, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments) { parameters.programs.raster.draw( parameters.context, gl::Triangles(), parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), RasterProgram::UniformValues { uniforms::u_matrix::Value{ matrix }, uniforms::u_image0::Value{ 0 }, uniforms::u_image1::Value{ 1 }, uniforms::u_opacity::Value{ evaluated.get<RasterOpacity>() }, uniforms::u_fade_t::Value{ 1 }, uniforms::u_brightness_low::Value{ evaluated.get<RasterBrightnessMin>() }, uniforms::u_brightness_high::Value{ evaluated.get<RasterBrightnessMax>() }, uniforms::u_saturation_factor::Value{ saturationFactor(evaluated.get<RasterSaturation>()) }, uniforms::u_contrast_factor::Value{ contrastFactor(evaluated.get<RasterContrast>()) }, uniforms::u_spin_weights::Value{ spinWeights(evaluated.get<RasterHueRotate>()) }, uniforms::u_buffer_scale::Value{ 1.0f }, uniforms::u_scale_parent::Value{ 1.0f }, uniforms::u_tl_parent::Value{ std::array<float, 2> {{ 0.0f, 0.0f }} }, }, vertexBuffer, indexBuffer, segments, RasterProgram::PaintPropertyBinders { evaluated, 0 }, evaluated, parameters.state.getZoom(), getID() ); }; if (RenderImageSource* imageSource = source->as<RenderImageSource>()) { if (imageSource->isEnabled() && imageSource->isLoaded() && !imageSource->bucket->needsUpload()) { RasterBucket& bucket = *imageSource->bucket; assert(bucket.texture); parameters.context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear); parameters.context.bindTexture(*bucket.texture, 1, gl::TextureFilter::Linear); for (auto matrix_ : imageSource->matrices) { draw(matrix_, *bucket.vertexBuffer, *bucket.indexBuffer, bucket.segments); } } } else { for (const RenderTile& tile : renderTiles) { assert(dynamic_cast<RasterBucket*>(tile.tile.getBucket(*baseImpl))); RasterBucket& bucket = *reinterpret_cast<RasterBucket*>(tile.tile.getBucket(*baseImpl)); if (!bucket.hasData()) continue; assert(bucket.texture); parameters.context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear); parameters.context.bindTexture(*bucket.texture, 1, gl::TextureFilter::Linear); if (bucket.vertexBuffer && bucket.indexBuffer && !bucket.segments.empty()) { // Draw only the parts of the tile that aren't drawn by another tile in the layer. draw(tile.matrix, *bucket.vertexBuffer, *bucket.indexBuffer, bucket.segments); } else { // Draw the full tile. draw(tile.matrix, parameters.staticData.rasterVertexBuffer, parameters.staticData.quadTriangleIndexBuffer, parameters.staticData.rasterSegments); } } } }
void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { if (parameters.pass == RenderPass::Opaque) { return; } if (parameters.pass == RenderPass::Pass3D) { const auto& viewportSize = parameters.staticData.backendSize; const auto size = Size{viewportSize.width / 4, viewportSize.height / 4}; if (!renderTexture || renderTexture->getSize() != size) { if (parameters.context.supportsHalfFloatTextures) { renderTexture = OffscreenTexture(parameters.context, size, gl::TextureType::HalfFloat); try { renderTexture->bind(); } catch (const std::runtime_error& ex) { // can't render to a half-float texture; falling back to unsigned byte one renderTexture = nullopt; parameters.context.supportsHalfFloatTextures = false; } } if (!parameters.context.supportsHalfFloatTextures || !renderTexture) { renderTexture = OffscreenTexture(parameters.context, size, gl::TextureType::UnsignedByte); renderTexture->bind(); } } else { renderTexture->bind(); } if (!colorRampTexture) { colorRampTexture = parameters.context.createTexture(colorRamp, 1, gl::TextureType::UnsignedByte); } parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 1.0f }, {}, {}); for (const RenderTile& tile : renderTiles) { auto bucket_ = tile.tile.getBucket<HeatmapBucket>(*baseImpl); if (!bucket_) { continue; } HeatmapBucket& bucket = *bucket_; const auto extrudeScale = tile.id.pixelsToTileUnits(1, parameters.state.getZoom()); const auto stencilMode = parameters.mapMode != MapMode::Continuous ? parameters.stencilModeForClipping(tile.clip) : gl::StencilMode::disabled(); const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); auto& programInstance = parameters.programs.heatmap.get(evaluated); const auto allUniformValues = programInstance.computeAllUniformValues( HeatmapProgram::UniformValues { uniforms::u_intensity::Value( evaluated.get<style::HeatmapIntensity>() ), uniforms::u_matrix::Value( tile.matrix ), uniforms::heatmap::u_extrude_scale::Value( extrudeScale ) }, paintPropertyBinders, evaluated, parameters.state.getZoom() ); const auto allAttributeBindings = programInstance.computeAllAttributeBindings( *bucket.vertexBuffer, paintPropertyBinders, evaluated ); checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); programInstance.draw( parameters.context, gl::Triangles(), parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), stencilMode, gl::ColorMode::additive(), gl::CullFaceMode::disabled(), *bucket.indexBuffer, bucket.segments, allUniformValues, allAttributeBindings, getID() ); } } else if (parameters.pass == RenderPass::Translucent) { parameters.context.bindTexture(renderTexture->getTexture(), 0, gl::TextureFilter::Linear); parameters.context.bindTexture(*colorRampTexture, 1, gl::TextureFilter::Linear); const auto& size = parameters.staticData.backendSize; mat4 viewportMat; matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1); const Properties<>::PossiblyEvaluated properties; const HeatmapTextureProgram::PaintPropertyBinders paintAttributeData{ properties, 0 }; auto& programInstance = parameters.programs.heatmapTexture; const auto allUniformValues = programInstance.computeAllUniformValues( HeatmapTextureProgram::UniformValues{ uniforms::u_matrix::Value( viewportMat ), uniforms::u_world::Value( size ), uniforms::u_image::Value( 0 ), uniforms::u_color_ramp::Value( 1 ), uniforms::u_opacity::Value( evaluated.get<HeatmapOpacity>() ) }, 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() ); } }
void RenderRasterLayer::render(PaintParameters& parameters) { if (parameters.pass != RenderPass::Translucent) return; const auto& evaluated = static_cast<const RasterLayerProperties&>(*evaluatedProperties).evaluated; RasterProgram::Binders paintAttributeData{ evaluated, 0 }; auto draw = [&] (const mat4& matrix, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments, const auto& textureBindings, const std::string& drawScopeID) { auto& programInstance = parameters.programs.getRasterLayerPrograms().raster; const auto allUniformValues = programInstance.computeAllUniformValues( RasterProgram::LayoutUniformValues { uniforms::matrix::Value( matrix ), uniforms::opacity::Value( evaluated.get<RasterOpacity>() ), uniforms::fade_t::Value( 1 ), uniforms::brightness_low::Value( evaluated.get<RasterBrightnessMin>() ), uniforms::brightness_high::Value( evaluated.get<RasterBrightnessMax>() ), uniforms::saturation_factor::Value( saturationFactor(evaluated.get<RasterSaturation>()) ), uniforms::contrast_factor::Value( contrastFactor(evaluated.get<RasterContrast>()) ), uniforms::spin_weights::Value( spinWeights(evaluated.get<RasterHueRotate>()) ), uniforms::buffer_scale::Value( 1.0f ), uniforms::scale_parent::Value( 1.0f ), uniforms::tl_parent::Value( std::array<float, 2> {{ 0.0f, 0.0f }} ), }, paintAttributeData, evaluated, parameters.state.getZoom() ); const auto allAttributeBindings = programInstance.computeAllAttributeBindings( vertexBuffer, paintAttributeData, 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(), indexBuffer, segments, allUniformValues, allAttributeBindings, textureBindings, getID() + "/" + drawScopeID ); }; const gfx::TextureFilterType filter = evaluated.get<RasterResampling>() == RasterResamplingType::Nearest ? gfx::TextureFilterType::Nearest : gfx::TextureFilterType::Linear; if (imageData && !imageData->bucket->needsUpload()) { RasterBucket& bucket = *imageData->bucket; assert(bucket.texture); size_t i = 0; for (const auto& matrix_ : *imageData->matrices) { draw(matrix_, *bucket.vertexBuffer, *bucket.indexBuffer, bucket.segments, RasterProgram::TextureBindings{ textures::image0::Value{ bucket.texture->getResource(), filter }, textures::image1::Value{ bucket.texture->getResource(), filter }, }, bucket.drawScopeID + std::to_string(i++)); } } else { for (const RenderTile& tile : renderTiles) { auto* bucket_ = tile.getBucket(*baseImpl); if (!bucket_) { continue; } auto& bucket = static_cast<RasterBucket&>(*bucket_); if (!bucket.hasData()) continue; assert(bucket.texture); if (bucket.vertexBuffer && bucket.indexBuffer && !bucket.segments.empty()) { // Draw only the parts of the tile that aren't drawn by another tile in the layer. draw(parameters.matrixForTile(tile.id, true), *bucket.vertexBuffer, *bucket.indexBuffer, bucket.segments, RasterProgram::TextureBindings{ textures::image0::Value{ bucket.texture->getResource(), filter }, textures::image1::Value{ bucket.texture->getResource(), filter }, }, bucket.drawScopeID); } else { // Draw the full tile. draw(parameters.matrixForTile(tile.id, true), *parameters.staticData.rasterVertexBuffer, *parameters.staticData.quadTriangleIndexBuffer, parameters.staticData.rasterSegments, RasterProgram::TextureBindings{ textures::image0::Value{ bucket.texture->getResource(), filter }, textures::image1::Value{ bucket.texture->getResource(), filter }, }, bucket.drawScopeID); } } } }
void RenderHillshadeLayer::render(PaintParameters& parameters) { if (parameters.pass != RenderPass::Translucent && parameters.pass != RenderPass::Pass3D) return; const auto& evaluated = static_cast<const HillshadeLayerProperties&>(*evaluatedProperties).evaluated; auto draw = [&] (const mat4& matrix, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments, const UnwrappedTileID& id, const auto& textureBindings) { auto& programInstance = parameters.programs.getHillshadeLayerPrograms().hillshade; const HillshadeProgram::Binders paintAttributeData{ evaluated, 0 }; const auto allUniformValues = programInstance.computeAllUniformValues( HillshadeProgram::LayoutUniformValues { uniforms::matrix::Value( matrix ), uniforms::highlight::Value( evaluated.get<HillshadeHighlightColor>() ), uniforms::shadow::Value( evaluated.get<HillshadeShadowColor>() ), uniforms::accent::Value( evaluated.get<HillshadeAccentColor>() ), uniforms::light::Value( getLight(parameters) ), uniforms::latrange::Value( getLatRange(id) ), }, paintAttributeData, evaluated, parameters.state.getZoom() ); const auto allAttributeBindings = programInstance.computeAllAttributeBindings( vertexBuffer, paintAttributeData, 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(), indexBuffer, segments, allUniformValues, allAttributeBindings, textureBindings, getID() ); }; mat4 mat; matrix::ortho(mat, 0, util::EXTENT, -util::EXTENT, 0, 0, 1); matrix::translate(mat, mat, 0, -util::EXTENT, 0); for (const RenderTile& tile : renderTiles) { auto* bucket_ = tile.getBucket(*baseImpl); if (!bucket_) { continue; } auto& bucket = static_cast<HillshadeBucket&>(*bucket_); if (!bucket.hasData()){ continue; } if (!bucket.isPrepared() && parameters.pass == RenderPass::Pass3D) { assert(bucket.dem); const uint16_t stride = bucket.getDEMData().stride; const uint16_t tilesize = bucket.getDEMData().dim; auto view = parameters.context.createOffscreenTexture({ tilesize, tilesize }); auto renderPass = parameters.encoder->createRenderPass( "hillshade prepare", { *view, Color{ 0.0f, 0.0f, 0.0f, 0.0f }, {}, {} }); const Properties<>::PossiblyEvaluated properties; const HillshadePrepareProgram::Binders paintAttributeData{ properties, 0 }; auto& programInstance = parameters.programs.getHillshadeLayerPrograms().hillshadePrepare; const auto allUniformValues = programInstance.computeAllUniformValues( HillshadePrepareProgram::LayoutUniformValues { uniforms::matrix::Value( mat ), uniforms::dimension::Value( {{stride, stride}} ), uniforms::zoom::Value( float(tile.id.canonical.z) ), uniforms::maxzoom::Value( float(maxzoom) ), }, paintAttributeData, properties, parameters.state.getZoom() ); const auto allAttributeBindings = programInstance.computeAllAttributeBindings( *parameters.staticData.rasterVertexBuffer, paintAttributeData, properties ); checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); programInstance.draw( parameters.context, *renderPass, gfx::Triangles(), parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly), gfx::StencilMode::disabled(), parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), *parameters.staticData.quadTriangleIndexBuffer, parameters.staticData.rasterSegments, allUniformValues, allAttributeBindings, HillshadePrepareProgram::TextureBindings{ textures::image::Value{ bucket.dem->getResource() }, }, getID() ); bucket.texture = std::move(view->getTexture()); bucket.setPrepared(true); } else if (parameters.pass == RenderPass::Translucent) { assert(bucket.texture); if (bucket.vertexBuffer && bucket.indexBuffer && !bucket.segments.empty()) { // Draw only the parts of the tile that aren't drawn by another tile in the layer. draw(parameters.matrixForTile(tile.id, true), *bucket.vertexBuffer, *bucket.indexBuffer, bucket.segments, tile.id, HillshadeProgram::TextureBindings{ textures::image::Value{ bucket.texture->getResource(), gfx::TextureFilterType::Linear }, }); } else { // Draw the full tile. draw(parameters.matrixForTile(tile.id, true), *parameters.staticData.rasterVertexBuffer, *parameters.staticData.quadTriangleIndexBuffer, parameters.staticData.rasterSegments, tile.id, HillshadeProgram::TextureBindings{ textures::image::Value{ bucket.texture->getResource(), gfx::TextureFilterType::Linear }, }); } } } }
void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { if (evaluated.get<FillPattern>().from.empty()) { for (const RenderTile& tile : renderTiles) { assert(dynamic_cast<FillBucket*>(tile.tile.getBucket(*baseImpl))); FillBucket& bucket = *reinterpret_cast<FillBucket*>(tile.tile.getBucket(*baseImpl)); auto draw = [&] (auto& program, const auto& drawMode, const auto& depthMode, const auto& indexBuffer, const auto& segments) { program.get(evaluated).draw( parameters.context, drawMode, depthMode, parameters.stencilModeForClipping(tile.clip), parameters.colorModeForRenderPass(), FillProgram::UniformValues { uniforms::u_matrix::Value{ tile.translatedMatrix(evaluated.get<FillTranslate>(), evaluated.get<FillTranslateAnchor>(), parameters.state) }, uniforms::u_world::Value{ parameters.context.viewport.getCurrentValue().size }, }, *bucket.vertexBuffer, indexBuffer, segments, bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(), getID() ); }; // Only draw the fill when it's opaque and we're drawing opaque fragments, // or when it's translucent and we're drawing translucent fragments. if ((evaluated.get<FillColor>().constantOr(Color()).a >= 1.0f && evaluated.get<FillOpacity>().constantOr(0) >= 1.0f) == (parameters.pass == RenderPass::Opaque)) { draw(parameters.programs.fill, gl::Triangles(), parameters.depthModeForSublayer(1, parameters.pass == RenderPass::Opaque ? gl::DepthMode::ReadWrite : gl::DepthMode::ReadOnly), *bucket.triangleIndexBuffer, bucket.triangleSegments); } if (evaluated.get<FillAntialias>() && parameters.pass == RenderPass::Translucent) { draw(parameters.programs.fillOutline, gl::Lines{ 2.0f }, parameters.depthModeForSublayer( unevaluated.get<FillOutlineColor>().isUndefined() ? 2 : 0, gl::DepthMode::ReadOnly), *bucket.lineIndexBuffer, bucket.lineSegments); } } } else { if (parameters.pass != RenderPass::Translucent) { return; } optional<ImagePosition> imagePosA = parameters.imageManager.getPattern(evaluated.get<FillPattern>().from); optional<ImagePosition> imagePosB = parameters.imageManager.getPattern(evaluated.get<FillPattern>().to); if (!imagePosA || !imagePosB) { return; } parameters.imageManager.bind(parameters.context, 0); for (const RenderTile& tile : renderTiles) { assert(dynamic_cast<FillBucket*>(tile.tile.getBucket(*baseImpl))); FillBucket& bucket = *reinterpret_cast<FillBucket*>(tile.tile.getBucket(*baseImpl)); auto draw = [&] (auto& program, const auto& drawMode, const auto& depthMode, const auto& indexBuffer, const auto& segments) { program.get(evaluated).draw( parameters.context, drawMode, depthMode, parameters.stencilModeForClipping(tile.clip), parameters.colorModeForRenderPass(), FillPatternUniforms::values( tile.translatedMatrix(evaluated.get<FillTranslate>(), evaluated.get<FillTranslateAnchor>(), parameters.state), parameters.context.viewport.getCurrentValue().size, parameters.imageManager.getPixelSize(), *imagePosA, *imagePosB, evaluated.get<FillPattern>(), tile.id, parameters.state ), *bucket.vertexBuffer, indexBuffer, segments, bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(), getID() ); }; draw(parameters.programs.fillPattern, gl::Triangles(), parameters.depthModeForSublayer(1, gl::DepthMode::ReadWrite), *bucket.triangleIndexBuffer, bucket.triangleSegments); if (evaluated.get<FillAntialias>() && unevaluated.get<FillOutlineColor>().isUndefined()) { draw(parameters.programs.fillOutlinePattern, gl::Lines { 2.0f }, parameters.depthModeForSublayer(2, gl::DepthMode::ReadOnly), *bucket.lineIndexBuffer, bucket.lineSegments); } } } }
void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (parameters.pass == RenderPass::Opaque) { return; } for (const RenderTile& tile : renderTiles) { assert(dynamic_cast<SymbolBucket*>(tile.tile.getBucket(*baseImpl))); SymbolBucket& bucket = *reinterpret_cast<SymbolBucket*>(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) { 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, gl::Triangles(), values_.pitchAlignment == AlignmentType::Map ? parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly) : gl::DepthMode::disabled(), gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), *buffers.indexBuffer, buffers.segments, allUniformValues, allAttributeBindings, getID() ); }; assert(dynamic_cast<GeometryTile*>(&tile.tile)); GeometryTile& geometryTile = static_cast<GeometryTile&>(tile.tile); if (bucket.hasIconData()) { auto values = iconPropertyValues(layout); auto paintPropertyValues = iconPaintProperties(); const bool alongLine = layout.get<SymbolPlacement>() == SymbolPlacementType::Line && layout.get<IconRotationAlignment>() == 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<IconSize>().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<SymbolPlacement>() == SymbolPlacementType::Line && layout.get<TextRotationAlignment>() == 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()); const float scale = std::pow(2, parameters.state.getZoom() - tile.tile.id.overscaledZ); std::array<float,2> 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()); const float scale = std::pow(2, parameters.state.getZoom() - tile.tile.id.overscaledZ); std::array<float,2> 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() ); } } }