Files
MapLibreParticleLab/src/mbgl/renderer/painter_fill.cpp
kelvinabrokwa 73be3558d7 [core] seamless fill-pattern
seamless across dateline

upgrade test-suite version
2016-01-12 16:18:24 -08:00

157 lines
6.5 KiB
C++

#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/layer/fill_layer.hpp>
#include <mbgl/map/tile_id.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/shader/outline_shader.hpp>
#include <mbgl/shader/pattern_shader.hpp>
#include <mbgl/shader/plain_shader.hpp>
#include <mbgl/util/mat3.hpp>
using namespace mbgl;
void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileID& id, const mat4& matrix) {
const FillPaintProperties& properties = layer.paint;
mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor);
Color fill_color = properties.color;
fill_color[0] *= properties.opacity;
fill_color[1] *= properties.opacity;
fill_color[2] *= properties.opacity;
fill_color[3] *= properties.opacity;
Color stroke_color = properties.outlineColor;
if (stroke_color[3] < 0) {
stroke_color = fill_color;
} else {
stroke_color[0] *= properties.opacity;
stroke_color[1] *= properties.opacity;
stroke_color[2] *= properties.opacity;
stroke_color[3] *= properties.opacity;
}
const bool pattern = !properties.pattern.value.from.empty();
bool outline = properties.antialias && !pattern && stroke_color != fill_color;
bool fringeline = properties.antialias && !pattern && stroke_color == fill_color;
config.stencilOp.reset();
config.stencilTest = GL_TRUE;
config.depthFunc.reset();
config.depthTest = GL_TRUE;
config.depthMask = GL_TRUE;
// 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 = outlineShader->program;
outlineShader->u_matrix = vtxMatrix;
config.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!
outlineShader->u_color = stroke_color;
// Draw the entire line
outlineShader->u_world = {{
static_cast<float>(frame.framebufferSize[0]),
static_cast<float>(frame.framebufferSize[1])
}};
setDepthSublayer(0);
bucket.drawVertices(*outlineShader);
}
if (pattern) {
mapbox::util::optional<SpriteAtlasPosition> posA = spriteAtlas->getPosition(properties.pattern.value.from, true);
mapbox::util::optional<SpriteAtlasPosition> posB = spriteAtlas->getPosition(properties.pattern.value.to, true);
// Image fill.
if (pass == RenderPass::Translucent && posA && posB) {
float factor = (8.0 / std::pow(2, state.getIntegerZoom() - id.z)) / id.overscaling;
mat3 patternMatrixA;
matrix::identity(patternMatrixA);
matrix::scale(patternMatrixA, patternMatrixA,
1.0f / ((*posA).size[0] * factor * properties.pattern.value.fromScale),
1.0f / ((*posA).size[1] * factor * properties.pattern.value.fromScale));
mat3 patternMatrixB;
matrix::identity(patternMatrixB);
matrix::scale(patternMatrixB, patternMatrixB,
1.0f / ((*posB).size[0] * factor * properties.pattern.value.toScale),
1.0f / ((*posB).size[1] * factor * properties.pattern.value.toScale));
config.program = patternShader->program;
patternShader->u_matrix = vtxMatrix;
patternShader->u_pattern_tl_a = (*posA).tl;
patternShader->u_pattern_br_a = (*posA).br;
patternShader->u_pattern_tl_b = (*posB).tl;
patternShader->u_pattern_br_b = (*posB).br;
patternShader->u_opacity = properties.opacity;
patternShader->u_image = 0;
patternShader->u_mix = properties.pattern.value.t;
patternShader->u_patternmatrix_a = patternMatrixA;
patternShader->u_patternmatrix_b = patternMatrixB;
std::array<int, 2> imageSizeScaledA = {{
(int)((*posA).size[0] * properties.pattern.value.fromScale),
(int)((*posA).size[1] * properties.pattern.value.fromScale)
}};
std::array<int, 2> imageSizeScaledB = {{
(int)((*posB).size[0] * properties.pattern.value.toScale),
(int)((*posB).size[1] * properties.pattern.value.toScale)
}};
int tileSize = 512;
float offsetAx = ((tileSize % imageSizeScaledA[0]) * id.x) / (float)imageSizeScaledA[0];
float offsetAy = ((tileSize % imageSizeScaledA[1]) * id.y) / (float)imageSizeScaledA[1];
float offsetBx = ((tileSize % imageSizeScaledB[0]) * id.x) / (float)imageSizeScaledB[0];
float offsetBy = ((tileSize % imageSizeScaledB[1]) * id.y) / (float)imageSizeScaledB[1];
patternShader->u_offset_a = std::array<float, 2>{{offsetAx, offsetAy}};
patternShader->u_offset_b = std::array<float, 2>{{offsetBx, offsetBy}};
MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0));
spriteAtlas->bind(true);
// Draw the actual triangles into the color & stencil buffer.
setDepthSublayer(0);
bucket.drawElements(*patternShader);
}
}
else {
// No image fill.
if ((fill_color[3] >= 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 = plainShader->program;
plainShader->u_matrix = vtxMatrix;
plainShader->u_color = fill_color;
// Draw the actual triangles into the color & stencil buffer.
setDepthSublayer(1);
bucket.drawElements(*plainShader);
}
}
// 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 = outlineShader->program;
outlineShader->u_matrix = vtxMatrix;
config.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!
outlineShader->u_color = fill_color;
// Draw the entire line
outlineShader->u_world = {{
static_cast<float>(frame.framebufferSize[0]),
static_cast<float>(frame.framebufferSize[1])
}};
setDepthSublayer(2);
bucket.drawVertices(*outlineShader);
}
}