Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix label clipping by switching to layer-by-layer rendering #1727

Closed
wants to merge 56 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
7aeca98
Implement layer by layer rendering
ansis Apr 21, 2015
735bbba
Fixed circle rendering
Nov 13, 2015
21e278c
Diff cleanup
Nov 13, 2015
a8beee0
Fix Tile#hasLayerData
Nov 16, 2015
889e0cd
Fix fill z-index problems
Nov 16, 2015
7727552
Fixed test-suite crashes from image_source and video_source
Nov 16, 2015
b61fa84
Fix fill draw order
Nov 16, 2015
36f339c
Fix symbol rendering order
Nov 17, 2015
b7da3a2
Fix debug mode
Nov 17, 2015
93cc75f
Fix collision debug mode
Nov 17, 2015
06ff436
Fixed background wrapping
Nov 17, 2015
3ab839a
Fixed tile wrapping and overzooming
Nov 19, 2015
3d11ad3
Fixed circle rendering
Nov 19, 2015
b4a7fa9
Fix overzoomed debug mode
Nov 19, 2015
295c95b
WIP
Nov 19, 2015
ca58225
Fixed line render order
Nov 19, 2015
64a5a4a
Fixed debug mode's rendering of underzoomed tiles
Nov 24, 2015
06d4593
Fix background rendering order
Dec 9, 2015
88e0307
Fix lint errors
Dec 10, 2015
5746f0d
Fix fill outline clipping
Dec 10, 2015
cc7d527
Fix symbol clipping
Dec 10, 2015
34a18ff
Fix fill pattern outline
Dec 10, 2015
4aad08a
Fixed image and video source rendering
Dec 11, 2015
85c0f80
Fix overzoomed tile rendering
Dec 11, 2015
ce34fce
Updated test-suite
Dec 11, 2015
e72a756
Refactored painter render methods
Dec 11, 2015
f3c8672
Factored out Source#renderedTiles
Dec 11, 2015
deeac5a
Remove _drawClippingMasks's dependency on tiles
Dec 11, 2015
f3a2d26
Don't pass tiles to draw functions
Dec 11, 2015
9c64002
Use instances of TileCoord instead of ids
Dec 11, 2015
2addcf5
Rename "calculateMatrix" to "calculatePosMatrix"
Dec 11, 2015
4052d6d
Fixed tile rendering order
Dec 12, 2015
39a68da
Remove tile#sourceMaxZoom
Dec 14, 2015
51e2636
Simplify draw_fill diff
Dec 14, 2015
9a090fc
Simplify ImageSource and VideoSource diffs
Dec 14, 2015
5479a8f
Remove unnecessary maxzoom parameter in TilePyramid
Dec 14, 2015
aa62470
Bike shedding in Painter class
Dec 14, 2015
a1c474a
Removed TODO
Dec 15, 2015
7625a12
Rerefactoring
Dec 15, 2015
29e10be
Refactored to use Coordinate instead of TileCoord in ImageSource and …
Dec 15, 2015
0906985
Don't pass infinity to calculatePosMatrix
Dec 15, 2015
c9d5dd3
Restored switchShader API
Dec 15, 2015
cfc43e9
layer-by-layer-ize draw_circle
Dec 15, 2015
392db57
Fix collision debug mode
Dec 15, 2015
56af94c
WIP
Dec 16, 2015
50e7cad
layer-by-layer-ify draw_fill
Dec 16, 2015
df192bc
Added comment about sublayers in Painter
Dec 16, 2015
516d9cb
Added comment about earcut migration
Dec 16, 2015
82300d4
Draw background in one call WIP
Dec 16, 2015
16004ce
Rename painter.setDepthMaskEnabled
Dec 16, 2015
1c5a555
Reverted draw_background changes
Dec 16, 2015
f1ee84c
Fix lint
Dec 16, 2015
7715e51
Make terminology consistent with gl native
Dec 16, 2015
e0b3aa5
Don't draw circles during opaque pass
Dec 17, 2015
96c85f6
remove unecessary blend func changes
ansis Jan 4, 2016
aaa7e63
remove feature and line order reversal
ansis Jan 5, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion js/data/symbol_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ SymbolBucket.prototype.placeFeatures = function(collisionTile, buffers, collisio
this.symbolInstances.sort(function(a, b) {
var aRotated = sin * a.x + cos * a.y;
var bRotated = sin * b.x + cos * b.y;
return bRotated - aRotated;
return aRotated - bRotated;
});
}

Expand Down
78 changes: 35 additions & 43 deletions js/render/draw_background.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
'use strict';

var mat3 = require('gl-matrix').mat3;
var TilePyramid = require('../source/tile_pyramid');
var pyramid = new TilePyramid({ tileSize: 512 });

module.exports = drawBackground;

function drawBackground(painter, layer, posMatrix) {
function drawBackground(painter, source, layer) {
var gl = painter.gl;
var transform = painter.transform;
var color = layer.paint['background-color'];
var image = layer.paint['background-pattern'];
var opacity = layer.paint['background-opacity'];
Expand All @@ -14,73 +16,63 @@ function drawBackground(painter, layer, posMatrix) {
var imagePosA = image ? painter.spriteAtlas.getPosition(image.from, true) : null;
var imagePosB = image ? painter.spriteAtlas.getPosition(image.to, true) : null;

painter.setDepthSublayer(0);
if (imagePosA && imagePosB) {

if (painter.isOpaquePass) return;

// Draw texture fill
shader = painter.patternShader;
gl.switchShader(shader, posMatrix);
gl.switchShader(shader);
gl.uniform1i(shader.u_image, 0);
gl.uniform2fv(shader.u_pattern_tl_a, imagePosA.tl);
gl.uniform2fv(shader.u_pattern_br_a, imagePosA.br);
gl.uniform2fv(shader.u_pattern_tl_b, imagePosB.tl);
gl.uniform2fv(shader.u_pattern_br_b, imagePosB.br);
gl.uniform1f(shader.u_opacity, opacity);

var transform = painter.transform;
var sizeA = imagePosA.size;
var sizeB = imagePosB.size;
var center = transform.locationCoordinate(transform.center);
var scale = 1 / Math.pow(2, transform.zoomFraction);

gl.uniform1f(shader.u_mix, image.t);

var matrixA = mat3.create();
mat3.scale(matrixA, matrixA, [
1 / (sizeA[0] * image.fromScale),
1 / (sizeA[1] * image.fromScale)
]);
mat3.translate(matrixA, matrixA, [
(center.column * transform.tileSize) % (sizeA[0] * image.fromScale),
(center.row * transform.tileSize) % (sizeA[1] * image.fromScale)
]);
mat3.rotate(matrixA, matrixA, -transform.angle);
mat3.scale(matrixA, matrixA, [
scale * transform.width / 2,
-scale * transform.height / 2
]);
var factor = (4096 / transform.tileSize) / Math.pow(2, 0);

var matrixB = mat3.create();
mat3.scale(matrixB, matrixB, [
1 / (sizeB[0] * image.toScale),
1 / (sizeB[1] * image.toScale)
]);
mat3.translate(matrixB, matrixB, [
(center.column * transform.tileSize) % (sizeB[0] * image.toScale),
(center.row * transform.tileSize) % (sizeB[1] * image.toScale)
]);
mat3.rotate(matrixB, matrixB, -transform.angle);
mat3.scale(matrixB, matrixB, [
scale * transform.width / 2,
-scale * transform.height / 2
gl.uniform2fv(shader.u_patternscale_a, [
1 / (imagePosA.size[0] * factor * image.fromScale),
1 / (imagePosA.size[1] * factor * image.fromScale)
]);

gl.uniformMatrix3fv(shader.u_patternmatrix_a, false, matrixA);
gl.uniformMatrix3fv(shader.u_patternmatrix_b, false, matrixB);
gl.uniform2fv(shader.u_patternscale_b, [
1 / (imagePosB.size[0] * factor * image.toScale),
1 / (imagePosB.size[1] * factor * image.toScale)
]);

painter.spriteAtlas.bind(gl, true);

} else {
// Draw filling rectangle.
if (painter.isOpaquePass !== (color[3] === 1)) return;

shader = painter.fillShader;
gl.switchShader(shader, posMatrix);
gl.switchShader(shader);
gl.uniform4fv(shader.u_color, color);
}

gl.disable(gl.STENCIL_TEST);
gl.bindBuffer(gl.ARRAY_BUFFER, painter.backgroundBuffer);
gl.vertexAttribPointer(shader.a_pos, painter.backgroundBuffer.itemSize, gl.SHORT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, painter.backgroundBuffer.itemCount);
gl.enable(gl.STENCIL_TEST);

gl.bindBuffer(gl.ARRAY_BUFFER, painter.tileExtentBuffer);
gl.vertexAttribPointer(shader.a_pos, painter.tileExtentBuffer.itemSize, gl.SHORT, false, 0, 0);

// We need to draw the background in tiles in order to use calculatePosMatrix
// which applies the projection matrix (transform.projMatrix). Otherwise
// the depth and stencil buffers get into a bad state.
// This can be refactored into a single draw call once earcut lands and
// we don't have so much going on in the stencil buffer.
var coords = pyramid.coveringTiles(transform);
for (var c = 0; c < coords.length; c++) {
gl.setPosMatrix(painter.calculatePosMatrix(coords[c]));
gl.drawArrays(gl.TRIANGLE_STRIP, 0, painter.tileExtentBuffer.itemCount);
}

gl.enable(gl.STENCIL_TEST);
gl.stencilMask(0x00);
gl.stencilFunc(gl.EQUAL, 0x80, 0x80);
}
58 changes: 36 additions & 22 deletions js/render/draw_circle.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,21 @@ var browser = require('../util/browser.js');

module.exports = drawCircles;

function drawCircles(painter, layer, posMatrix, tile) {
// short-circuit if tile is empty
if (!tile.buffers) return;
function drawCircles(painter, source, layer, coords) {
if (painter.isOpaquePass) return;

posMatrix = painter.translateMatrix(posMatrix, tile, layer.paint['circle-translate'], layer.paint['circle-translate-anchor']);
var gl = painter.gl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native aborts early if it's not the translucent pass. Do we need that here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. Added.


if (!tile.elementGroups[layer.ref || layer.id]) return;
var elementGroups = tile.elementGroups[layer.ref || layer.id].circle;
var shader = painter.circleShader;
painter.gl.switchShader(shader);

var gl = painter.gl;
painter.setDepthSublayer(0);
painter.depthMask(false);

// Allow circles to be drawn across boundaries, so that
// large circles are not clipped to tiles
gl.disable(gl.STENCIL_TEST);

gl.switchShader(painter.circleShader, posMatrix, tile.exMatrix);

var vertex = tile.buffers.circleVertex;
var shader = painter.circleShader;
var elements = tile.buffers.circleElement;

// antialiasing factor: this is a minimum blur distance that serves as
// a faux-antialiasing for the circle. since blur is a ratio of the circle's
// size and the intent is to keep the blur at roughly 1px, the two
Expand All @@ -35,18 +29,38 @@ function drawCircles(painter, layer, posMatrix, tile) {
gl.uniform1f(shader.u_blur, Math.max(layer.paint['circle-blur'], antialias));
gl.uniform1f(shader.u_size, layer.paint['circle-radius']);

for (var k = 0; k < elementGroups.groups.length; k++) {
var group = elementGroups.groups[k];
var offset = group.vertexStartIndex * vertex.itemSize;
for (var i = 0; i < coords.length; i++) {
var coord = coords[i];

var tile = source.getTile(coord);
if (!tile.buffers) continue;
if (!tile.elementGroups[layer.ref || layer.id].circle) continue;

var elementGroups = tile.elementGroups[layer.ref || layer.id].circle;
var vertex = tile.buffers.circleVertex;
var elements = tile.buffers.circleElement;

gl.setPosMatrix(painter.translatePosMatrix(
painter.calculatePosMatrix(coord, source.maxzoom),
tile,
layer.paint['circle-translate'],
layer.paint['circle-translate-anchor']
));
gl.setExMatrix(painter.transform.exMatrix);

for (var k = 0; k < elementGroups.groups.length; k++) {
var group = elementGroups.groups[k];
var offset = group.vertexStartIndex * vertex.itemSize;

vertex.bind(gl);
vertex.setAttribPointers(gl, shader, offset);
vertex.bind(gl);
vertex.setAttribPointers(gl, shader, offset);

elements.bind(gl);
elements.bind(gl);

var count = group.elementLength * 3;
var elementOffset = group.elementStartIndex * elements.itemSize;
gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, elementOffset);
var count = group.elementLength * 3;
var elementOffset = group.elementStartIndex * elements.itemSize;
gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, elementOffset);
}
}

gl.enable(gl.STENCIL_TEST);
Expand Down
10 changes: 7 additions & 3 deletions js/render/draw_collision_debug.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
'use strict';

module.exports = drawPlacementDebug;

function drawPlacementDebug(painter, layer, posMatrix, tile) {
module.exports = drawCollisionDebug;

function drawCollisionDebug(painter, layer, coord, tile) {
if (!tile.elementGroups[layer.ref || layer.id]) return;
var elementGroups = tile.elementGroups[layer.ref || layer.id].collisionBox;
if (!elementGroups) return;
if (!tile.buffers) return;

var gl = painter.gl;
var buffer = tile.buffers.collisionBoxVertex;
var shader = painter.collisionBoxShader;
var posMatrix = painter.calculatePosMatrix(coord);

gl.enable(gl.STENCIL_TEST);
painter.enableTileClippingMask(coord);

gl.switchShader(shader, posMatrix);

buffer.bind(gl);
buffer.setAttribPointers(gl, shader, 0);

Expand Down
32 changes: 18 additions & 14 deletions js/render/draw_debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,37 @@ var browser = require('../util/browser');

module.exports = drawDebug;

function drawDebug(painter, tile) {
var gl = painter.gl;
function drawDebug(painter, coords) {
if (painter.isOpaquePass) return;
if (!painter.options.debug) return;

// Blend to the front, not the back.
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
for (var i = 0; i < coords.length; i++) {
drawDebugTile(painter, coords[i]);
}
}

gl.switchShader(painter.debugShader, tile.posMatrix);
function drawDebugTile(painter, coord) {
var gl = painter.gl;

var shader = painter.debugShader;
gl.switchShader(shader, painter.calculatePosMatrix(coord));

// draw bounding rectangle
gl.bindBuffer(gl.ARRAY_BUFFER, painter.debugBuffer);
gl.vertexAttribPointer(painter.debugShader.a_pos, painter.debugBuffer.itemSize, gl.SHORT, false, 0, 0);
gl.uniform4f(painter.debugShader.u_color, 1, 0, 0, 1);
gl.vertexAttribPointer(shader.a_pos, painter.debugBuffer.itemSize, gl.SHORT, false, 0, 0);
gl.uniform4f(shader.u_color, 1, 0, 0, 1);
gl.lineWidth(4);
gl.drawArrays(gl.LINE_STRIP, 0, painter.debugBuffer.itemCount);

var vertices = textVertices(tile.coord.toString(), 50, 200, 5);
var vertices = textVertices(coord.toString(), 50, 200, 5);

gl.bindBuffer(gl.ARRAY_BUFFER, painter.debugTextBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Int16Array(vertices), gl.STREAM_DRAW);
gl.vertexAttribPointer(painter.debugShader.a_pos, painter.debugTextBuffer.itemSize, gl.SHORT, false, 0, 0);
gl.vertexAttribPointer(shader.a_pos, painter.debugTextBuffer.itemSize, gl.SHORT, false, 0, 0);
gl.lineWidth(8 * browser.devicePixelRatio);
gl.uniform4f(painter.debugShader.u_color, 1, 1, 1, 1);
gl.uniform4f(shader.u_color, 1, 1, 1, 1);
gl.drawArrays(gl.LINES, 0, vertices.length / painter.debugTextBuffer.itemSize);
gl.lineWidth(2 * browser.devicePixelRatio);
gl.uniform4f(painter.debugShader.u_color, 0, 0, 0, 1);
gl.uniform4f(shader.u_color, 0, 0, 0, 1);
gl.drawArrays(gl.LINES, 0, vertices.length / painter.debugTextBuffer.itemSize);

// Revert blending mode to blend to the back.
gl.blendFunc(gl.ONE_MINUS_DST_ALPHA, gl.ONE);
}
Loading