summaryrefslogtreecommitdiff
path: root/src/mbgl/renderer/painters
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/renderer/painters')
-rw-r--r--src/mbgl/renderer/painters/painter_background.cpp83
-rw-r--r--src/mbgl/renderer/painters/painter_circle.cpp57
-rw-r--r--src/mbgl/renderer/painters/painter_clipping.cpp37
-rw-r--r--src/mbgl/renderer/painters/painter_debug.cpp162
-rw-r--r--src/mbgl/renderer/painters/painter_fill.cpp141
-rw-r--r--src/mbgl/renderer/painters/painter_fill_extrusion.cpp86
-rw-r--r--src/mbgl/renderer/painters/painter_line.cpp91
-rw-r--r--src/mbgl/renderer/painters/painter_raster.cpp89
-rw-r--r--src/mbgl/renderer/painters/painter_symbol.cpp166
9 files changed, 912 insertions, 0 deletions
diff --git a/src/mbgl/renderer/painters/painter_background.cpp b/src/mbgl/renderer/painters/painter_background.cpp
new file mode 100644
index 0000000000..577d7d6cda
--- /dev/null
+++ b/src/mbgl/renderer/painters/painter_background.cpp
@@ -0,0 +1,83 @@
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/layers/render_background_layer.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/style/layers/background_layer_impl.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/fill_program.hpp>
+#include <mbgl/util/tile_cover.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+void Painter::renderBackground(PaintParameters& parameters, const RenderBackgroundLayer& layer) {
+ // Note that for bottommost layers without a pattern, the background color is drawn with
+ // glClear rather than this method.
+ const BackgroundPaintProperties::PossiblyEvaluated& background = layer.evaluated;
+
+ style::FillPaintProperties::PossiblyEvaluated properties;
+ properties.get<FillPattern>() = background.get<BackgroundPattern>();
+ properties.get<FillOpacity>() = { background.get<BackgroundOpacity>() };
+ properties.get<FillColor>() = { background.get<BackgroundColor>() };
+
+ const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+
+ if (!background.get<BackgroundPattern>().to.empty()) {
+ optional<ImagePosition> imagePosA = imageManager->getPattern(background.get<BackgroundPattern>().from);
+ optional<ImagePosition> imagePosB = imageManager->getPattern(background.get<BackgroundPattern>().to);
+
+ if (!imagePosA || !imagePosB)
+ return;
+
+ imageManager->bind(context, 0);
+
+ for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) {
+ parameters.programs.fillPattern.get(properties).draw(
+ context,
+ gl::Triangles(),
+ depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ FillPatternUniforms::values(
+ matrixForTile(tileID),
+ context.viewport.getCurrentValue().size,
+ imageManager->getPixelSize(),
+ *imagePosA,
+ *imagePosB,
+ background.get<BackgroundPattern>(),
+ tileID,
+ state
+ ),
+ tileVertexBuffer,
+ quadTriangleIndexBuffer,
+ tileTriangleSegments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
+ );
+ }
+ } else {
+ for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) {
+ parameters.programs.fill.get(properties).draw(
+ context,
+ gl::Triangles(),
+ depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ FillProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrixForTile(tileID) },
+ uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
+ },
+ tileVertexBuffer,
+ quadTriangleIndexBuffer,
+ tileTriangleSegments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
+ );
+ }
+ }
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painters/painter_circle.cpp b/src/mbgl/renderer/painters/painter_circle.cpp
new file mode 100644
index 0000000000..58e384979d
--- /dev/null
+++ b/src/mbgl/renderer/painters/painter_circle.cpp
@@ -0,0 +1,57 @@
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/buckets/circle_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/layers/render_circle_layer.hpp>
+#include <mbgl/style/layers/circle_layer_impl.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/circle_program.hpp>
+#include <mbgl/gl/context.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+void Painter::renderCircle(PaintParameters& parameters,
+ CircleBucket& bucket,
+ const RenderCircleLayer& layer,
+ const RenderTile& tile) {
+ if (pass == RenderPass::Opaque) {
+ return;
+ }
+
+ const CirclePaintProperties::PossiblyEvaluated& properties = layer.evaluated;
+ const bool scaleWithMap = properties.get<CirclePitchScale>() == CirclePitchScaleType::Map;
+
+ parameters.programs.circle.get(properties).draw(
+ context,
+ gl::Triangles(),
+ depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ frame.mapMode == MapMode::Still
+ ? stencilModeForClipping(tile.clip)
+ : gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ CircleProgram::UniformValues {
+ uniforms::u_matrix::Value{
+ tile.translatedMatrix(properties.get<CircleTranslate>(),
+ properties.get<CircleTranslateAnchor>(),
+ state)
+ },
+ uniforms::u_scale_with_map::Value{ scaleWithMap },
+ uniforms::u_extrude_scale::Value{ scaleWithMap
+ ? std::array<float, 2> {{
+ pixelsToGLUnits[0] * state.getCameraToCenterDistance(),
+ pixelsToGLUnits[1] * state.getCameraToCenterDistance()
+ }}
+ : pixelsToGLUnits }
+ },
+ *bucket.vertexBuffer,
+ *bucket.indexBuffer,
+ bucket.segments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom()
+ );
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painters/painter_clipping.cpp b/src/mbgl/renderer/painters/painter_clipping.cpp
new file mode 100644
index 0000000000..cad092594e
--- /dev/null
+++ b/src/mbgl/renderer/painters/painter_clipping.cpp
@@ -0,0 +1,37 @@
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/fill_program.hpp>
+#include <mbgl/util/clip_id.hpp>
+
+namespace mbgl {
+
+void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& clip) {
+ static const style::FillPaintProperties::PossiblyEvaluated properties {};
+ static const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+ programs->fill.get(properties).draw(
+ context,
+ gl::Triangles(),
+ gl::DepthMode::disabled(),
+ gl::StencilMode {
+ gl::StencilMode::Always(),
+ static_cast<int32_t>(clip.reference.to_ulong()),
+ 0b11111111,
+ gl::StencilMode::Keep,
+ gl::StencilMode::Keep,
+ gl::StencilMode::Replace
+ },
+ gl::ColorMode::disabled(),
+ FillProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrixForTile(tileID) },
+ uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
+ },
+ tileVertexBuffer,
+ quadTriangleIndexBuffer,
+ tileTriangleSegments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
+ );
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painters/painter_debug.cpp b/src/mbgl/renderer/painters/painter_debug.cpp
new file mode 100644
index 0000000000..ee76aee54c
--- /dev/null
+++ b/src/mbgl/renderer/painters/painter_debug.cpp
@@ -0,0 +1,162 @@
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/buckets/debug_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/map/view.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/fill_program.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/gl/debugging.hpp>
+#include <mbgl/util/color.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+void Painter::renderTileDebug(const RenderTile& renderTile) {
+ if (frame.debugOptions == MapDebugOptions::NoDebug)
+ return;
+
+ MBGL_DEBUG_GROUP(context, std::string { "debug " } + util::toString(renderTile.id));
+
+ static const style::Properties<>::PossiblyEvaluated properties {};
+ static const DebugProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+
+ auto draw = [&] (Color color, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments, auto drawMode) {
+ programs->debug.draw(
+ context,
+ drawMode,
+ gl::DepthMode::disabled(),
+ stencilModeForClipping(renderTile.clip),
+ gl::ColorMode::unblended(),
+ DebugProgram::UniformValues {
+ uniforms::u_matrix::Value{ renderTile.matrix },
+ uniforms::u_color::Value{ color }
+ },
+ vertexBuffer,
+ indexBuffer,
+ segments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
+ );
+ };
+
+ if (frame.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) {
+ Tile& tile = renderTile.tile;
+ if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() ||
+ tile.debugBucket->complete != tile.isComplete() ||
+ !(tile.debugBucket->modified == tile.modified) ||
+ !(tile.debugBucket->expires == tile.expires) ||
+ tile.debugBucket->debugMode != frame.debugOptions) {
+ tile.debugBucket = std::make_unique<DebugBucket>(
+ tile.id, tile.isRenderable(), tile.isComplete(), tile.modified,
+ tile.expires, frame.debugOptions, context);
+ }
+
+ draw(Color::white(),
+ *tile.debugBucket->vertexBuffer,
+ *tile.debugBucket->indexBuffer,
+ tile.debugBucket->segments,
+ gl::Lines { 4.0f * frame.pixelRatio });
+
+ draw(Color::black(),
+ *tile.debugBucket->vertexBuffer,
+ *tile.debugBucket->indexBuffer,
+ tile.debugBucket->segments,
+ gl::Lines { 2.0f * frame.pixelRatio });
+ }
+
+ if (frame.debugOptions & MapDebugOptions::TileBorders) {
+ draw(Color::red(),
+ tileVertexBuffer,
+ tileBorderIndexBuffer,
+ tileBorderSegments,
+ gl::LineStrip { 4.0f * frame.pixelRatio });
+ }
+}
+
+void Painter::renderTileDebug(const mat4& matrix) {
+ if (frame.debugOptions == MapDebugOptions::NoDebug)
+ return;
+
+ static const style::Properties<>::PossiblyEvaluated properties {};
+ static const DebugProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+
+ if (frame.debugOptions & MapDebugOptions::TileBorders) {
+ programs->debug.draw(
+ context,
+ gl::LineStrip { 4.0f * frame.pixelRatio },
+ gl::DepthMode::disabled(),
+ gl::StencilMode::disabled(),
+ gl::ColorMode::unblended(),
+ DebugProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_color::Value{ Color::red() }
+ },
+ tileVertexBuffer,
+ tileBorderIndexBuffer,
+ tileBorderSegments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
+ );
+ }
+}
+
+#ifndef NDEBUG
+void Painter::renderClipMasks(PaintParameters&) {
+ context.setStencilMode(gl::StencilMode::disabled());
+ context.setDepthMode(gl::DepthMode::disabled());
+ context.setColorMode(gl::ColorMode::unblended());
+ context.program = 0;
+
+#if not MBGL_USE_GLES2
+ // Reset the value in case someone else changed it, or it's dirty.
+ context.pixelTransferStencil = gl::value::PixelTransferStencil::Default;
+
+ // Read the stencil buffer
+ const auto viewport = context.viewport.getCurrentValue();
+ auto image =
+ context.readFramebuffer<AlphaImage, gl::TextureFormat::Stencil>(viewport.size, false);
+
+ // Scale the Stencil buffer to cover the entire color space.
+ auto it = image.data.get();
+ auto end = it + viewport.size.width * viewport.size.height;
+ const auto factor = 255.0f / *std::max_element(it, end);
+ for (; it != end; ++it) {
+ *it *= factor;
+ }
+
+ context.pixelZoom = { 1, 1 };
+ context.rasterPos = { -1, -1, 0, 1 };
+ context.drawPixels(image);
+#endif // MBGL_USE_GLES2
+}
+
+void Painter::renderDepthBuffer(PaintParameters&) {
+ context.setStencilMode(gl::StencilMode::disabled());
+ context.setDepthMode(gl::DepthMode::disabled());
+ context.setColorMode(gl::ColorMode::unblended());
+ context.program = 0;
+
+#if not MBGL_USE_GLES2
+ // Scales the values in the depth buffer so that they cover the entire grayscale range. This
+ // makes it easier to spot tiny differences.
+ const float base = 1.0f / (1.0f - depthRangeSize);
+ context.pixelTransferDepth = { base, 1.0f - base };
+
+ // Read the stencil buffer
+ auto viewport = context.viewport.getCurrentValue();
+ auto image =
+ context.readFramebuffer<AlphaImage, gl::TextureFormat::Depth>(viewport.size, false);
+
+ context.pixelZoom = { 1, 1 };
+ context.rasterPos = { -1, -1, 0, 1 };
+ context.drawPixels(image);
+#endif // MBGL_USE_GLES2
+}
+#endif // NDEBUG
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painters/painter_fill.cpp b/src/mbgl/renderer/painters/painter_fill.cpp
new file mode 100644
index 0000000000..3a0bfed454
--- /dev/null
+++ b/src/mbgl/renderer/painters/painter_fill.cpp
@@ -0,0 +1,141 @@
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/buckets/fill_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/layers/render_fill_layer.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/style/layers/fill_layer_impl.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/fill_program.hpp>
+#include <mbgl/util/convert.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+void Painter::renderFill(PaintParameters& parameters,
+ FillBucket& bucket,
+ const RenderFillLayer& layer,
+ const RenderTile& tile) {
+ const FillPaintProperties::PossiblyEvaluated& properties = layer.evaluated;
+
+ if (!properties.get<FillPattern>().from.empty()) {
+ if (pass != RenderPass::Translucent) {
+ return;
+ }
+
+ optional<ImagePosition> imagePosA = imageManager->getPattern(properties.get<FillPattern>().from);
+ optional<ImagePosition> imagePosB = imageManager->getPattern(properties.get<FillPattern>().to);
+
+ if (!imagePosA || !imagePosB) {
+ return;
+ }
+
+ imageManager->bind(context, 0);
+
+ auto draw = [&] (uint8_t sublayer,
+ auto& program,
+ const auto& drawMode,
+ const auto& indexBuffer,
+ const auto& segments) {
+ program.get(properties).draw(
+ context,
+ drawMode,
+ depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite),
+ stencilModeForClipping(tile.clip),
+ colorModeForRenderPass(),
+ FillPatternUniforms::values(
+ tile.translatedMatrix(properties.get<FillTranslate>(),
+ properties.get<FillTranslateAnchor>(),
+ state),
+ context.viewport.getCurrentValue().size,
+ imageManager->getPixelSize(),
+ *imagePosA,
+ *imagePosB,
+ properties.get<FillPattern>(),
+ tile.id,
+ state
+ ),
+ *bucket.vertexBuffer,
+ indexBuffer,
+ segments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom()
+ );
+ };
+
+ draw(0,
+ parameters.programs.fillPattern,
+ gl::Triangles(),
+ *bucket.triangleIndexBuffer,
+ bucket.triangleSegments);
+
+ if (!properties.get<FillAntialias>() || !layer.unevaluated.get<FillOutlineColor>().isUndefined()) {
+ return;
+ }
+
+ draw(2,
+ parameters.programs.fillOutlinePattern,
+ gl::Lines { 2.0f },
+ *bucket.lineIndexBuffer,
+ bucket.lineSegments);
+ } else {
+ auto draw = [&] (uint8_t sublayer,
+ auto& program,
+ const auto& drawMode,
+ const auto& indexBuffer,
+ const auto& segments) {
+ program.get(properties).draw(
+ context,
+ drawMode,
+ depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite),
+ stencilModeForClipping(tile.clip),
+ colorModeForRenderPass(),
+ FillProgram::UniformValues {
+ uniforms::u_matrix::Value{
+ tile.translatedMatrix(properties.get<FillTranslate>(),
+ properties.get<FillTranslateAnchor>(),
+ state)
+ },
+ uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
+ },
+ *bucket.vertexBuffer,
+ indexBuffer,
+ segments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom()
+ );
+ };
+
+ if (properties.get<FillAntialias>() && !layer.unevaluated.get<FillOutlineColor>().isUndefined() && pass == RenderPass::Translucent) {
+ draw(2,
+ parameters.programs.fillOutline,
+ gl::Lines { 2.0f },
+ *bucket.lineIndexBuffer,
+ bucket.lineSegments);
+ }
+
+ // 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 ((properties.get<FillColor>().constantOr(Color()).a >= 1.0f
+ && properties.get<FillOpacity>().constantOr(0) >= 1.0f) == (pass == RenderPass::Opaque)) {
+ draw(1,
+ parameters.programs.fill,
+ gl::Triangles(),
+ *bucket.triangleIndexBuffer,
+ bucket.triangleSegments);
+ }
+
+ if (properties.get<FillAntialias>() && layer.unevaluated.get<FillOutlineColor>().isUndefined() && pass == RenderPass::Translucent) {
+ draw(2,
+ parameters.programs.fillOutline,
+ gl::Lines { 2.0f },
+ *bucket.lineIndexBuffer,
+ bucket.lineSegments);
+ }
+ }
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painters/painter_fill_extrusion.cpp b/src/mbgl/renderer/painters/painter_fill_extrusion.cpp
new file mode 100644
index 0000000000..165476944b
--- /dev/null
+++ b/src/mbgl/renderer/painters/painter_fill_extrusion.cpp
@@ -0,0 +1,86 @@
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/buckets/fill_extrusion_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/fill_extrusion_program.hpp>
+#include <mbgl/util/constants.hpp>
+#include <mbgl/util/convert.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+void Painter::renderFillExtrusion(PaintParameters& parameters,
+ FillExtrusionBucket& bucket,
+ const RenderFillExtrusionLayer& layer,
+ const RenderTile& tile) {
+ const FillExtrusionPaintProperties::PossiblyEvaluated& properties = layer.evaluated;
+
+ if (pass == RenderPass::Opaque) {
+ return;
+ }
+
+ if (!properties.get<FillExtrusionPattern>().from.empty()) {
+ optional<ImagePosition> imagePosA = imageManager->getPattern(properties.get<FillExtrusionPattern>().from);
+ optional<ImagePosition> imagePosB = imageManager->getPattern(properties.get<FillExtrusionPattern>().to);
+
+ if (!imagePosA || !imagePosB) {
+ return;
+ }
+
+ imageManager->bind(context, 0);
+
+ parameters.programs.fillExtrusionPattern.get(properties).draw(
+ context,
+ gl::Triangles(),
+ depthModeForSublayer(0, gl::DepthMode::ReadWrite),
+ gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ FillExtrusionPatternUniforms::values(
+ tile.translatedClipMatrix(properties.get<FillExtrusionTranslate>(),
+ properties.get<FillExtrusionTranslateAnchor>(),
+ state),
+ imageManager->getPixelSize(),
+ *imagePosA,
+ *imagePosB,
+ properties.get<FillExtrusionPattern>(),
+ tile.id,
+ state,
+ -std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f,
+ evaluatedLight
+ ),
+ *bucket.vertexBuffer,
+ *bucket.indexBuffer,
+ bucket.triangleSegments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom());
+
+ } else {
+ parameters.programs.fillExtrusion.get(properties).draw(
+ context,
+ gl::Triangles(),
+ depthModeForSublayer(0, gl::DepthMode::ReadWrite),
+ gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ FillExtrusionUniforms::values(
+ tile.translatedClipMatrix(properties.get<FillExtrusionTranslate>(),
+ properties.get<FillExtrusionTranslateAnchor>(),
+ state),
+ state,
+ evaluatedLight
+ ),
+ *bucket.vertexBuffer,
+ *bucket.indexBuffer,
+ bucket.triangleSegments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom());
+ };
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painters/painter_line.cpp b/src/mbgl/renderer/painters/painter_line.cpp
new file mode 100644
index 0000000000..58f4131d96
--- /dev/null
+++ b/src/mbgl/renderer/painters/painter_line.cpp
@@ -0,0 +1,91 @@
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/buckets/line_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/layers/render_line_layer.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/style/layers/line_layer_impl.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/line_program.hpp>
+#include <mbgl/geometry/line_atlas.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+void Painter::renderLine(PaintParameters& parameters,
+ LineBucket& bucket,
+ const RenderLineLayer& layer,
+ const RenderTile& tile) {
+ if (pass == RenderPass::Opaque) {
+ return;
+ }
+
+ const RenderLinePaintProperties::PossiblyEvaluated& properties = layer.evaluated;
+
+ auto draw = [&] (auto& program, auto&& uniformValues) {
+ program.get(properties).draw(
+ context,
+ gl::Triangles(),
+ depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ stencilModeForClipping(tile.clip),
+ colorModeForRenderPass(),
+ std::move(uniformValues),
+ *bucket.vertexBuffer,
+ *bucket.indexBuffer,
+ bucket.segments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom()
+ );
+ };
+
+ if (!properties.get<LineDasharray>().from.empty()) {
+ const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round
+ ? LinePatternCap::Round : LinePatternCap::Square;
+ LinePatternPos posA = lineAtlas->getDashPosition(properties.get<LineDasharray>().from, cap);
+ LinePatternPos posB = lineAtlas->getDashPosition(properties.get<LineDasharray>().to, cap);
+
+ lineAtlas->bind(context, 0);
+
+ draw(parameters.programs.lineSDF,
+ LineSDFProgram::uniformValues(
+ properties,
+ frame.pixelRatio,
+ tile,
+ state,
+ pixelsToGLUnits,
+ posA,
+ posB,
+ lineAtlas->getSize().width));
+
+ } else if (!properties.get<LinePattern>().from.empty()) {
+ optional<ImagePosition> posA = imageManager->getPattern(properties.get<LinePattern>().from);
+ optional<ImagePosition> posB = imageManager->getPattern(properties.get<LinePattern>().to);
+
+ if (!posA || !posB)
+ return;
+
+ imageManager->bind(context, 0);
+
+ draw(parameters.programs.linePattern,
+ LinePatternProgram::uniformValues(
+ properties,
+ tile,
+ state,
+ pixelsToGLUnits,
+ imageManager->getPixelSize(),
+ *posA,
+ *posB));
+
+ } else {
+ draw(parameters.programs.line,
+ LineProgram::uniformValues(
+ properties,
+ tile,
+ state,
+ pixelsToGLUnits));
+ }
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painters/painter_raster.cpp b/src/mbgl/renderer/painters/painter_raster.cpp
new file mode 100644
index 0000000000..56e38ae8f4
--- /dev/null
+++ b/src/mbgl/renderer/painters/painter_raster.cpp
@@ -0,0 +1,89 @@
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/buckets/raster_bucket.hpp>
+#include <mbgl/renderer/layers/render_raster_layer.hpp>
+#include <mbgl/style/layers/raster_layer_impl.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/raster_program.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+static float saturationFactor(float saturation) {
+ if (saturation > 0) {
+ return 1 - 1 / (1.001 - saturation);
+ } else {
+ return -saturation;
+ }
+}
+
+static float contrastFactor(float contrast) {
+ if (contrast > 0) {
+ return 1 / (1 - contrast);
+ } else {
+ return 1 + contrast;
+ }
+}
+
+static std::array<float, 3> spinWeights(float spin) {
+ spin *= util::DEG2RAD;
+ float s = std::sin(spin);
+ float c = std::cos(spin);
+ std::array<float, 3> spin_weights = {{
+ (2 * c + 1) / 3,
+ (-std::sqrt(3.0f) * s - c + 1) / 3,
+ (std::sqrt(3.0f) * s - c + 1) / 3
+ }};
+ return spin_weights;
+}
+
+void Painter::renderRaster(PaintParameters& parameters,
+ RasterBucket& bucket,
+ const RenderRasterLayer& layer,
+ const mat4& matrix,
+ bool useBucketBuffers = false) {
+ if (pass != RenderPass::Translucent)
+ return;
+ if (!bucket.hasData())
+ return;
+
+ const RasterPaintProperties::PossiblyEvaluated& properties = layer.evaluated;
+ const RasterProgram::PaintPropertyBinders paintAttributeData(properties, 0);
+
+ assert(bucket.texture);
+ context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear);
+ context.bindTexture(*bucket.texture, 1, gl::TextureFilter::Linear);
+
+ parameters.programs.raster.draw(
+ context,
+ gl::Triangles(),
+ depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ RasterProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_image0::Value{ 0 },
+ uniforms::u_image1::Value{ 1 },
+ uniforms::u_opacity::Value{ properties.get<RasterOpacity>() },
+ uniforms::u_fade_t::Value{ 1 },
+ uniforms::u_brightness_low::Value{ properties.get<RasterBrightnessMin>() },
+ uniforms::u_brightness_high::Value{ properties.get<RasterBrightnessMax>() },
+ uniforms::u_saturation_factor::Value{ saturationFactor(properties.get<RasterSaturation>()) },
+ uniforms::u_contrast_factor::Value{ contrastFactor(properties.get<RasterContrast>()) },
+ uniforms::u_spin_weights::Value{ spinWeights(properties.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 }} },
+ },
+ useBucketBuffers ? *bucket.vertexBuffer : rasterVertexBuffer,
+ useBucketBuffers ? *bucket.indexBuffer : quadTriangleIndexBuffer,
+ useBucketBuffers ? bucket.segments : rasterSegments,
+ paintAttributeData,
+ properties,
+ state.getZoom()
+ );
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/painters/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp
new file mode 100644
index 0000000000..d3a505aa3f
--- /dev/null
+++ b/src/mbgl/renderer/painters/painter_symbol.cpp
@@ -0,0 +1,166 @@
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/buckets/symbol_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
+#include <mbgl/text/glyph_atlas.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/symbol_program.hpp>
+#include <mbgl/programs/collision_box_program.hpp>
+#include <mbgl/util/math.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
+
+#include <cmath>
+
+namespace mbgl {
+
+using namespace style;
+
+void Painter::renderSymbol(PaintParameters& parameters,
+ SymbolBucket& bucket,
+ const RenderSymbolLayer& layer,
+ const RenderTile& tile) {
+ if (pass == RenderPass::Opaque) {
+ return;
+ }
+
+ const auto& layout = bucket.layout;
+
+ frameHistory.bind(context, 1);
+
+ auto draw = [&] (auto& program,
+ auto&& uniformValues,
+ const auto& buffers,
+ const auto& symbolSizeBinder,
+ const SymbolPropertyValues& values_,
+ const auto& binders,
+ const auto& paintProperties)
+ {
+ // We clip symbols to their tile extent in still mode.
+ const bool needsClipping = frame.mapMode == MapMode::Still;
+
+ program.get(paintProperties).draw(
+ context,
+ gl::Triangles(),
+ values_.pitchAlignment == AlignmentType::Map
+ ? depthModeForSublayer(0, gl::DepthMode::ReadOnly)
+ : gl::DepthMode::disabled(),
+ needsClipping
+ ? stencilModeForClipping(tile.clip)
+ : gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ std::move(uniformValues),
+ *buffers.vertexBuffer,
+ *symbolSizeBinder,
+ *buffers.indexBuffer,
+ buffers.segments,
+ binders,
+ paintProperties,
+ state.getZoom()
+ );
+ };
+
+ assert(dynamic_cast<GeometryTile*>(&tile.tile));
+ GeometryTile& geometryTile = static_cast<GeometryTile&>(tile.tile);
+
+ if (bucket.hasIconData()) {
+ auto values = layer.iconPropertyValues(layout);
+ auto paintPropertyValues = layer.iconPaintProperties();
+
+ const bool iconScaled = layout.get<IconSize>().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear;
+ const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || state.getPitch() != 0;
+
+ context.bindTexture(*geometryTile.iconAtlasTexture, 0,
+ bucket.sdfIcons || 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, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
+ bucket.icon,
+ bucket.iconSizeBinder,
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).first,
+ paintPropertyValues);
+ }
+
+ if (values.hasFill) {
+ draw(parameters.programs.symbolIconSDF,
+ SymbolSDFIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
+ bucket.icon,
+ bucket.iconSizeBinder,
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).first,
+ paintPropertyValues);
+ }
+ } else {
+ draw(parameters.programs.symbolIcon,
+ SymbolIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state),
+ bucket.icon,
+ bucket.iconSizeBinder,
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).first,
+ paintPropertyValues);
+ }
+ }
+
+ if (bucket.hasTextData()) {
+ context.bindTexture(*geometryTile.glyphAtlasTexture, 0, gl::TextureFilter::Linear);
+
+ auto values = layer.textPropertyValues(layout);
+ auto paintPropertyValues = layer.textPaintProperties();
+
+ const Size texsize = geometryTile.glyphAtlasTexture->size;
+
+ if (values.hasHalo) {
+ draw(parameters.programs.symbolGlyph,
+ SymbolSDFTextProgram::uniformValues(true, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
+ bucket.text,
+ bucket.textSizeBinder,
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).second,
+ paintPropertyValues);
+ }
+
+ if (values.hasFill) {
+ draw(parameters.programs.symbolGlyph,
+ SymbolSDFTextProgram::uniformValues(true, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
+ bucket.text,
+ bucket.textSizeBinder,
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).second,
+ paintPropertyValues);
+ }
+ }
+
+ if (bucket.hasCollisionBoxData()) {
+ static const style::Properties<>::PossiblyEvaluated properties {};
+ static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0);
+
+ programs->collisionBox.draw(
+ context,
+ gl::Lines { 1.0f },
+ gl::DepthMode::disabled(),
+ gl::StencilMode::disabled(),
+ colorModeForRenderPass(),
+ CollisionBoxProgram::UniformValues {
+ uniforms::u_matrix::Value{ tile.matrix },
+ uniforms::u_scale::Value{ std::pow(2.0f, float(state.getZoom() - tile.tile.id.overscaledZ)) },
+ uniforms::u_zoom::Value{ float(state.getZoom() * 10) },
+ uniforms::u_maxzoom::Value{ float((tile.id.canonical.z + 1) * 10) },
+ },
+ *bucket.collisionBox.vertexBuffer,
+ *bucket.collisionBox.indexBuffer,
+ bucket.collisionBox.segments,
+ paintAttributeData,
+ properties,
+ state.getZoom()
+ );
+ }
+}
+
+} // namespace mbgl