-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
draw_line.js
124 lines (97 loc) · 4.98 KB
/
draw_line.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
'use strict';
const browser = require('../util/browser');
const pixelsToTileUnits = require('../source/pixels_to_tile_units');
/**
* Draw a line. Under the hood this will read elements from
* a tile, dash textures from a lineAtlas, and style properties from a layer.
* @param {Object} painter
* @param {Object} layer
* @param {Object} posMatrix
* @param {Tile} tile
* @returns {undefined} draws with the painter
* @private
*/
module.exports = function drawLine(painter, sourceCache, layer, coords) {
if (painter.isOpaquePass) return;
painter.setDepthSublayer(0);
painter.depthMask(false);
const gl = painter.gl;
gl.enable(gl.STENCIL_TEST);
// don't draw zero-width lines
if (layer.paint['line-width'] <= 0) return;
const programId =
layer.paint['line-dasharray'] ? 'lineSDF' :
layer.paint['line-pattern'] ? 'linePattern' : 'line';
let prevTileZoom;
let firstTile = true;
for (const coord of coords) {
const tile = sourceCache.getTile(coord);
const bucket = tile.getBucket(layer);
if (!bucket) continue;
const layerData = bucket.buffers.layerData[layer.id];
const prevProgram = painter.currentProgram;
const program = painter.useProgram(programId, layerData.programConfiguration);
const programChanged = firstTile || program !== prevProgram;
const tileRatioChanged = prevTileZoom !== tile.coord.z;
if (programChanged) {
layerData.programConfiguration.setUniforms(painter.gl, program, layer, {zoom: painter.transform.zoom});
}
drawLineTile(program, painter, tile, bucket.buffers, layer, coord, layerData, programChanged, tileRatioChanged);
prevTileZoom = tile.coord.z;
firstTile = false;
}
};
function drawLineTile(program, painter, tile, buffers, layer, coord, layerData, programChanged, tileRatioChanged) {
const gl = painter.gl;
const dasharray = layer.paint['line-dasharray'];
const image = layer.paint['line-pattern'];
let posA, posB, imagePosA, imagePosB;
if (programChanged || tileRatioChanged) {
const tileRatio = 1 / pixelsToTileUnits(tile, 1, painter.transform.tileZoom);
if (dasharray) {
posA = painter.lineAtlas.getDash(dasharray.from, layer.layout['line-cap'] === 'round');
posB = painter.lineAtlas.getDash(dasharray.to, layer.layout['line-cap'] === 'round');
const widthA = posA.width * dasharray.fromScale;
const widthB = posB.width * dasharray.toScale;
gl.uniform2f(program.u_patternscale_a, tileRatio / widthA, -posA.height / 2);
gl.uniform2f(program.u_patternscale_b, tileRatio / widthB, -posB.height / 2);
gl.uniform1f(program.u_sdfgamma, painter.lineAtlas.width / (Math.min(widthA, widthB) * 256 * browser.devicePixelRatio) / 2);
} else if (image) {
imagePosA = painter.spriteAtlas.getPosition(image.from, true);
imagePosB = painter.spriteAtlas.getPosition(image.to, true);
if (!imagePosA || !imagePosB) return;
gl.uniform2f(program.u_pattern_size_a, imagePosA.size[0] * image.fromScale / tileRatio, imagePosB.size[1]);
gl.uniform2f(program.u_pattern_size_b, imagePosB.size[0] * image.toScale / tileRatio, imagePosB.size[1]);
}
}
if (programChanged) {
if (dasharray) {
gl.uniform1i(program.u_image, 0);
gl.activeTexture(gl.TEXTURE0);
painter.lineAtlas.bind(gl);
gl.uniform1f(program.u_tex_y_a, posA.y);
gl.uniform1f(program.u_tex_y_b, posB.y);
gl.uniform1f(program.u_mix, dasharray.t);
} else if (image) {
gl.uniform1i(program.u_image, 0);
gl.activeTexture(gl.TEXTURE0);
painter.spriteAtlas.bind(gl, true);
gl.uniform2fv(program.u_pattern_tl_a, imagePosA.tl);
gl.uniform2fv(program.u_pattern_br_a, imagePosA.br);
gl.uniform2fv(program.u_pattern_tl_b, imagePosB.tl);
gl.uniform2fv(program.u_pattern_br_b, imagePosB.br);
gl.uniform1f(program.u_fade, image.t);
}
gl.uniform1f(program.u_width, layer.paint['line-width']);
gl.uniformMatrix2fv(program.u_antialiasingmatrix, false, painter.transform.lineAntialiasingMatrix);
gl.uniform1f(program.u_extra, painter.transform.lineStretch);
}
painter.enableTileClippingMask(coord);
const posMatrix = painter.translatePosMatrix(coord.posMatrix, tile, layer.paint['line-translate'], layer.paint['line-translate-anchor']);
gl.uniformMatrix4fv(program.u_matrix, false, posMatrix);
gl.uniform1f(program.u_ratio, 1 / pixelsToTileUnits(tile, 1, painter.transform.zoom));
for (const segment of buffers.segments) {
segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, layerData.paintVertexBuffer, segment.vertexOffset);
gl.drawElements(gl.TRIANGLES, segment.primitiveLength * 3, gl.UNSIGNED_SHORT, segment.primitiveOffset * 3 * 2);
}
}