Skip to content

Commit

Permalink
simplify and optimize drawSymbols (#3499)
Browse files Browse the repository at this point in the history
  • Loading branch information
mourner authored Nov 1, 2016
1 parent 3a9778e commit 10d98cf
Showing 1 changed file with 87 additions and 102 deletions.
189 changes: 87 additions & 102 deletions js/render/draw_symbol.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@ const browser = require('../util/browser');
const drawCollisionDebug = require('./draw_collision_debug');
const pixelsToTileUnits = require('../source/pixels_to_tile_units');


module.exports = drawSymbols;

const sdfPx = 8;
const blurOffset = 1.19;
const haloOffset = 6;
const gamma = 0.105 / browser.devicePixelRatio;

function drawSymbols(painter, sourceCache, layer, coords) {
if (painter.isOpaquePass) return;

const drawAcrossEdges = !(layer.layout['text-allow-overlap'] || layer.layout['icon-allow-overlap'] ||
layer.layout['text-ignore-placement'] || layer.layout['icon-ignore-placement']);
const drawAcrossEdges =
!layer.layout['text-allow-overlap'] &&
!layer.layout['icon-allow-overlap'] &&
!layer.layout['text-ignore-placement'] &&
!layer.layout['icon-ignore-placement'];

const gl = painter.gl;

Expand All @@ -26,6 +33,9 @@ function drawSymbols(painter, sourceCache, layer, coords) {
gl.enable(gl.STENCIL_TEST);
}

painter.setDepthSublayer(0);
painter.depthMask(false);

drawLayerSymbols(painter, sourceCache, layer, coords, false,
layer.paint['icon-translate'],
layer.paint['icon-translate-anchor'],
Expand Down Expand Up @@ -59,92 +69,59 @@ function drawSymbols(painter, sourceCache, layer, coords) {
}
}

function drawLayerSymbols(painter, sourceCache, layer, coords, isText,
translate,
translateAnchor,
rotationAlignment,
pitchAlignment,
size,
haloWidth,
haloColor,
haloBlur,
opacity,
color) {
function drawLayerSymbols(painter, sourceCache, layer, coords, isText, translate, translateAnchor,
rotationAlignment, pitchAlignment, size, haloWidth, haloColor, haloBlur, opacity, color) {

if (!isText && painter.style.sprite && !painter.style.sprite.loaded())
return;

const gl = painter.gl;
painter.setDepthSublayer(0);
painter.depthMask(false);
if (pitchAlignment === 'map') {

const rotateWithMap = rotationAlignment === 'map';
const pitchWithMap = pitchAlignment === 'map';

if (pitchWithMap) {
gl.enable(gl.DEPTH_TEST);
} else {
gl.disable(gl.DEPTH_TEST);
}

for (let j = 0; j < coords.length; j++) {
const tile = sourceCache.getTile(coords[j]);
let program;

for (const coord of coords) {
const tile = sourceCache.getTile(coord);
const bucket = tile.getBucket(layer);
if (!bucket) continue;
const buffers = isText ? bucket.buffers.glyph : bucket.buffers.icon;
if (!buffers.segments.length) continue;

painter.enableTileClippingMask(coords[j]);
drawSymbol(painter, layer, coords[j].posMatrix, tile, bucket, buffers, isText,
isText || bucket.sdfIcons, !isText && bucket.iconsNeedLinear,
isText ? bucket.adjustedTextSize : bucket.adjustedIconSize, bucket.fontstack,
translate,
translateAnchor,
rotationAlignment,
pitchAlignment,
size,
haloWidth,
haloColor,
haloBlur,
opacity,
color);
}
const isSDF = isText || bucket.sdfIcons;

gl.enable(gl.DEPTH_TEST);
}
if (!program) {
program = painter.useProgram(isSDF ? 'symbolSDF' : 'symbolIcon');

function drawSymbol(painter, layer, posMatrix, tile, bucket, buffers, isText, sdf, iconsNeedLinear, adjustedSize, fontstack,
translate,
translateAnchor,
rotationAlignment,
pitchAlignment,
size,
haloWidth,
haloColor,
haloBlur,
opacity,
color) {
setSymbolDrawState(program, painter, isText, isSDF, rotateWithMap, pitchWithMap, bucket.fontstack, size,
bucket.iconsNeedLinear, isText ? bucket.adjustedTextSize : bucket.adjustedIconSize, opacity);
}

const gl = painter.gl;
const tr = painter.transform;
const rotateWithMap = rotationAlignment === 'map';
const pitchWithMap = pitchAlignment === 'map';
painter.enableTileClippingMask(coord);

const defaultSize = isText ? 24 : 1;
const fontScale = size / defaultSize;
gl.uniformMatrix4fv(program.u_matrix, false,
painter.translatePosMatrix(coord.posMatrix, tile, translate, translateAnchor));

let extrudeScale, s, gammaScale;
if (pitchWithMap) {
s = pixelsToTileUnits(tile, 1, painter.transform.zoom) * fontScale;
gammaScale = 1 / Math.cos(tr._pitch);
extrudeScale = [s, s];
} else {
s = painter.transform.altitude * fontScale;
gammaScale = 1;
extrudeScale = [ tr.pixelsToGLUnits[0] * s, tr.pixelsToGLUnits[1] * s];
drawTileSymbols(program, painter, layer, tile, buffers, isText, isSDF,
pitchWithMap, size, haloWidth, haloColor, haloBlur, color);
}
}

if (!isText && !painter.style.sprite.loaded())
return;
function setSymbolDrawState(program, painter, isText, isSDF, rotateWithMap, pitchWithMap, fontstack, size,
iconsNeedLinear, adjustedSize, opacity) {

const gl = painter.gl;
const tr = painter.transform;

const program = painter.useProgram(sdf ? 'symbolSDF' : 'symbolIcon');
gl.uniformMatrix4fv(program.u_matrix, false, painter.translatePosMatrix(posMatrix, tile, translate, translateAnchor));
gl.uniform1i(program.u_rotate_with_map, rotateWithMap);
gl.uniform1i(program.u_pitch_with_map, pitchWithMap);
gl.uniform2fv(program.u_extrude_scale, extrudeScale);

gl.activeTexture(gl.TEXTURE0);
gl.uniform1i(program.u_texture, 0);
Expand All @@ -159,57 +136,65 @@ function drawSymbol(painter, layer, posMatrix, tile, bucket, buffers, isText, sd
gl.uniform2f(program.u_texsize, glyphAtlas.width / 4, glyphAtlas.height / 4);
} else {
const mapMoving = painter.options.rotating || painter.options.zooming;
const iconScaled = fontScale !== 1 || browser.devicePixelRatio !== painter.spriteAtlas.pixelRatio || iconsNeedLinear;
const iconTransformed = pitchWithMap || painter.transform.pitch;
painter.spriteAtlas.bind(gl, sdf || mapMoving || iconScaled || iconTransformed);
const iconScaled = size !== 1 || browser.devicePixelRatio !== painter.spriteAtlas.pixelRatio || iconsNeedLinear;
const iconTransformed = pitchWithMap || tr.pitch;
painter.spriteAtlas.bind(gl, isSDF || mapMoving || iconScaled || iconTransformed);
gl.uniform2f(program.u_texsize, painter.spriteAtlas.width / 4, painter.spriteAtlas.height / 4);
}

// adjust min/max zooms for variable font sizes
const zoomAdjust = Math.log(size / adjustedSize) / Math.LN2 || 0;
gl.uniform1f(program.u_zoom, (painter.transform.zoom - zoomAdjust) * 10); // current zoom level

gl.activeTexture(gl.TEXTURE1);
painter.frameHistory.bind(gl);
gl.uniform1i(program.u_fadetexture, 1);

if (sdf) {
const sdfPx = 8;
const blurOffset = 1.19;
const haloOffset = 6;
const gamma = 0.105 * defaultSize / size / browser.devicePixelRatio;
// adjust min/max zooms for variable font sizes
const zoomAdjust = Math.log(size / adjustedSize) / Math.LN2 || 0;
gl.uniform1f(program.u_zoom, (tr.zoom - zoomAdjust) * 10); // current zoom level

gl.uniform1f(program.u_pitch, tr.pitch / 360 * 2 * Math.PI);
gl.uniform1f(program.u_bearing, tr.bearing / 360 * 2 * Math.PI);
gl.uniform1f(program.u_aspect_ratio, tr.width / tr.height);

gl.uniform1f(program.u_opacity, opacity);
}

function drawTileSymbols(program, painter, layer, tile, buffers, isText, isSDF,
pitchWithMap, size, haloWidth, haloColor, haloBlur, color) {

const gl = painter.gl;
const tr = painter.transform;

const fontScale = size / (isText ? 24 : 1);

if (pitchWithMap) {
const s = pixelsToTileUnits(tile, fontScale, tr.zoom);
gl.uniform2f(program.u_extrude_scale, s, s);
} else {
const s = tr.altitude * fontScale;
gl.uniform2f(program.u_extrude_scale, tr.pixelsToGLUnits[0] * s, tr.pixelsToGLUnits[1] * s);
}

if (haloWidth) {
// Draw halo underneath the text.
gl.uniform1f(program.u_gamma, (haloBlur * blurOffset / fontScale / sdfPx + gamma) * gammaScale);
if (isSDF) {
const gammaScale = fontScale * (pitchWithMap ? Math.cos(tr._pitch) : 1);

if (haloWidth) { // Draw halo underneath the text.
gl.uniform1f(program.u_gamma, (haloBlur * blurOffset / sdfPx + gamma) / gammaScale);
gl.uniform4fv(program.u_color, haloColor);
gl.uniform1f(program.u_opacity, opacity);
gl.uniform1f(program.u_buffer, (haloOffset - haloWidth / fontScale) / sdfPx);

for (const segment of buffers.segments) {
segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, null, segment.vertexOffset);
gl.drawElements(gl.TRIANGLES, segment.primitiveLength * 3, gl.UNSIGNED_SHORT, segment.primitiveOffset * 3 * 2);
}
drawSymbolElements(buffers, layer, gl, program);
}

gl.uniform1f(program.u_gamma, gamma * gammaScale);
gl.uniform1f(program.u_gamma, gamma / gammaScale);
gl.uniform4fv(program.u_color, color);
gl.uniform1f(program.u_opacity, opacity);
gl.uniform1f(program.u_buffer, (256 - 64) / 256);
gl.uniform1f(program.u_pitch, tr.pitch / 360 * 2 * Math.PI);
gl.uniform1f(program.u_bearing, tr.bearing / 360 * 2 * Math.PI);
gl.uniform1f(program.u_aspect_ratio, tr.width / tr.height);
}

for (const segment of buffers.segments) {
segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, null, segment.vertexOffset);
gl.drawElements(gl.TRIANGLES, segment.primitiveLength * 3, gl.UNSIGNED_SHORT, segment.primitiveOffset * 3 * 2);
}
drawSymbolElements(buffers, layer, gl, program);
}

} else {
gl.uniform1f(program.u_opacity, opacity);
for (const segment of buffers.segments) {
segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, null, segment.vertexOffset);
gl.drawElements(gl.TRIANGLES, segment.primitiveLength * 3, gl.UNSIGNED_SHORT, segment.primitiveOffset * 3 * 2);
}
function drawSymbolElements(buffers, layer, gl, program) {
for (const segment of buffers.segments) {
segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, null, segment.vertexOffset);
gl.drawElements(gl.TRIANGLES, segment.primitiveLength * 3, gl.UNSIGNED_SHORT, segment.primitiveOffset * 3 * 2);
}
}

0 comments on commit 10d98cf

Please sign in to comment.