Files
MapLibreParticleLab/src/mbgl/renderer/painter_fill.cpp
2016-06-20 13:24:20 +03:00

172 lines
7.9 KiB
C++

#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/fill_layer_impl.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/shader/outline_shader.hpp>
#include <mbgl/shader/outlinepattern_shader.hpp>
#include <mbgl/shader/pattern_shader.hpp>
#include <mbgl/shader/plain_shader.hpp>
#include <mbgl/util/convert.hpp>
namespace mbgl {
using namespace style;
void Painter::renderFill(FillBucket& bucket,
const FillLayer& layer,
const UnwrappedTileID& tileID,
const mat4& matrix) {
const FillPaintProperties& properties = layer.impl->paint;
mat4 vertexMatrix =
translatedMatrix(matrix, properties.fillTranslate, tileID, properties.fillTranslateAnchor);
Color fillColor = properties.fillColor;
float opacity = properties.fillOpacity;
Color strokeColor = properties.fillOutlineColor;
bool isOutlineColorDefined = strokeColor.a >= 0;
if (!isOutlineColorDefined) {
strokeColor = fillColor;
}
auto worldSize = util::convert<GLfloat>(frame.framebufferSize);
bool pattern = !properties.fillPattern.value.from.empty();
bool outline = properties.fillAntialias && !pattern && isOutlineColorDefined;
bool fringeline = properties.fillAntialias && !pattern && !isOutlineColorDefined;
config.stencilOp.reset();
config.stencilTest = GL_TRUE;
config.depthFunc.reset();
config.depthTest = GL_TRUE;
config.depthMask = GL_TRUE;
config.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!
// Because we're drawing top-to-bottom, and we update the stencil mask
// befrom, we have to draw the outline first (!)
if (outline && pass == RenderPass::Translucent) {
config.program = isWireframe() ? outlineShader->getOverdrawID() : outlineShader->getID();
outlineShader->u_matrix = vertexMatrix;
outlineShader->u_outline_color = strokeColor;
outlineShader->u_opacity = opacity;
// Draw the entire line
outlineShader->u_world = worldSize;
if (isOutlineColorDefined) {
// If we defined a different color for the fill outline, we are
// going to ignore the bits in 0x07 and just care about the global
// clipping mask.
setDepthSublayer(2); // OK
} else {
// Otherwise, we only want to drawFill the antialiased parts that are
// *outside* the current shape. This is important in case the fill
// or stroke color is translucent. If we wouldn't clip to outside
// the current shape, some pixels from the outline stroke overlapped
// the (non-antialiased) fill.
setDepthSublayer(0); // OK
}
bucket.drawVertices(*outlineShader, store);
}
if (pattern) {
optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(properties.fillPattern.value.from, true);
optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition(properties.fillPattern.value.to, true);
// Image fill.
if (pass == RenderPass::Translucent && imagePosA && imagePosB) {
config.program = isWireframe() ? patternShader->getOverdrawID() : patternShader->getID();
patternShader->u_matrix = vertexMatrix;
patternShader->u_pattern_tl_a = imagePosA->tl;
patternShader->u_pattern_br_a = imagePosA->br;
patternShader->u_pattern_tl_b = imagePosB->tl;
patternShader->u_pattern_br_b = imagePosB->br;
patternShader->u_opacity = properties.fillOpacity;
patternShader->u_image = 0;
patternShader->u_mix = properties.fillPattern.value.t;
patternShader->u_pattern_size_a = imagePosA->size;
patternShader->u_pattern_size_b = imagePosB->size;
patternShader->u_scale_a = properties.fillPattern.value.fromScale;
patternShader->u_scale_b = properties.fillPattern.value.toScale;
patternShader->u_tile_units_to_pixels = 1.0f / tileID.pixelsToTileUnits(1.0f, state.getIntegerZoom());
GLint tileSizeAtNearestZoom = util::tileSize * state.zoomScale(state.getIntegerZoom() - tileID.canonical.z);
GLint pixelX = tileSizeAtNearestZoom * (tileID.canonical.x + tileID.wrap * state.zoomScale(tileID.canonical.z));
GLint pixelY = tileSizeAtNearestZoom * tileID.canonical.y;
patternShader->u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }};
patternShader->u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }};
config.activeTexture = GL_TEXTURE0;
spriteAtlas->bind(true, store);
// Draw the actual triangles into the color & stencil buffer.
setDepthSublayer(0);
bucket.drawElements(*patternShader, store);
if (properties.fillAntialias && !isOutlineColorDefined) {
config.program = isWireframe() ? outlinePatternShader->getOverdrawID() : outlinePatternShader->getID();
outlinePatternShader->u_matrix = vertexMatrix;
// Draw the entire line
outlineShader->u_world = worldSize;
outlinePatternShader->u_pattern_tl_a = imagePosA->tl;
outlinePatternShader->u_pattern_br_a = imagePosA->br;
outlinePatternShader->u_pattern_tl_b = imagePosB->tl;
outlinePatternShader->u_pattern_br_b = imagePosB->br;
outlinePatternShader->u_opacity = properties.fillOpacity;
outlinePatternShader->u_image = 0;
outlinePatternShader->u_mix = properties.fillPattern.value.t;
outlinePatternShader->u_pattern_size_a = imagePosA->size;
outlinePatternShader->u_pattern_size_b = imagePosB->size;
outlinePatternShader->u_scale_a = properties.fillPattern.value.fromScale;
outlinePatternShader->u_scale_b = properties.fillPattern.value.toScale;
outlinePatternShader->u_tile_units_to_pixels = 1.0f / tileID.pixelsToTileUnits(1.0f, state.getIntegerZoom());
outlinePatternShader->u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }};
outlinePatternShader->u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }};
config.activeTexture = GL_TEXTURE0;
spriteAtlas->bind(true, store);
setDepthSublayer(2);
bucket.drawVertices(*outlinePatternShader, store);
}
}
} else {
// No image fill.
if ((fillColor.a >= 1.0f && opacity >= 1.0f) == (pass == RenderPass::Opaque)) {
// Only draw the fill when it's either opaque and we're drawing opaque
// fragments or when it's translucent and we're drawing translucent
// fragments
// Draw filling rectangle.
config.program = isWireframe() ? plainShader->getOverdrawID() : plainShader->getID();
plainShader->u_matrix = vertexMatrix;
plainShader->u_color = fillColor;
plainShader->u_opacity = opacity;
// Draw the actual triangles into the color & stencil buffer.
setDepthSublayer(1);
bucket.drawElements(*plainShader, store);
}
}
// Because we're drawing top-to-bottom, and we update the stencil mask
// below, we have to draw the outline first (!)
if (fringeline && pass == RenderPass::Translucent) {
config.program = isWireframe() ? outlineShader->getOverdrawID() : outlineShader->getID();
outlineShader->u_matrix = vertexMatrix;
outlineShader->u_outline_color = fillColor;
outlineShader->u_opacity = opacity;
// Draw the entire line
outlineShader->u_world = worldSize;
setDepthSublayer(2);
bucket.drawVertices(*outlineShader, store);
}
}
} // namespace mbgl