Skip to content

Commit

Permalink
Enable property functions for {text,icon}-{color,halo-color} (#4186)
Browse files Browse the repository at this point in the history
* Enable property functions for {text,icon}-color

* Update expected images for {icon,text}-color render tests

* Add render tests for {icon,text}-halo-color property functions

* Drop unneeded feature map
  • Loading branch information
anandthakker authored Feb 7, 2017
1 parent bce7afc commit 8f58879
Show file tree
Hide file tree
Showing 14 changed files with 343 additions and 20 deletions.
24 changes: 18 additions & 6 deletions src/data/bucket/symbol_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,19 @@ const layoutVertexArrayType = createVertexArrayType([
const symbolInterfaces = {
glyph: {
layoutVertexArrayType: layoutVertexArrayType,
elementArrayType: elementArrayType
elementArrayType: elementArrayType,
paintAttributes: [
{name: 'a_fill_color', property: 'text-color', type: 'Uint8'},
{name: 'a_halo_color', property: 'text-halo-color', type: 'Uint8'}
]
},
icon: {
layoutVertexArrayType: layoutVertexArrayType,
elementArrayType: elementArrayType
elementArrayType: elementArrayType,
paintAttributes: [
{name: 'a_fill_color', property: 'icon-color', type: 'Uint8'},
{name: 'a_halo_color', property: 'icon-halo-color', type: 'Uint8'}
]
},
collisionBox: {
layoutVertexArrayType: createVertexArrayType([
Expand Down Expand Up @@ -447,7 +455,7 @@ class SymbolBucket {
this.symbolInstances.sort((a, b) => {
const aRotated = (sin * a.anchor.x + cos * a.anchor.y) | 0;
const bRotated = (sin * b.anchor.x + cos * b.anchor.y) | 0;
return (aRotated - bRotated) || (b.index - a.index);
return (aRotated - bRotated) || (b.featureIndex - a.featureIndex);
});
}

Expand Down Expand Up @@ -497,14 +505,14 @@ class SymbolBucket {
if (hasText) {
collisionTile.insertCollisionFeature(textCollisionFeature, glyphScale, layout['text-ignore-placement']);
if (glyphScale <= maxScale) {
this.addSymbols(this.arrays.glyph, symbolInstance.glyphQuads, glyphScale, layout['text-keep-upright'], textAlongLine, collisionTile.angle, symbolInstance.writingModes);
this.addSymbols(this.arrays.glyph, symbolInstance.glyphQuads, glyphScale, layout['text-keep-upright'], textAlongLine, collisionTile.angle, symbolInstance.featureProperties, symbolInstance.writingModes);
}
}

if (hasIcon) {
collisionTile.insertCollisionFeature(iconCollisionFeature, iconScale, layout['icon-ignore-placement']);
if (iconScale <= maxScale) {
this.addSymbols(this.arrays.icon, symbolInstance.iconQuads, iconScale, layout['icon-keep-upright'], iconAlongLine, collisionTile.angle);
this.addSymbols(this.arrays.icon, symbolInstance.iconQuads, iconScale, layout['icon-keep-upright'], iconAlongLine, collisionTile.angle, symbolInstance.featureProperties);
}
}

Expand All @@ -513,7 +521,7 @@ class SymbolBucket {
if (showCollisionBoxes) this.addToDebugBuffers(collisionTile);
}

addSymbols(arrays, quads, scale, keepUpright, alongLine, placementAngle, writingModes) {
addSymbols(arrays, quads, scale, keepUpright, alongLine, placementAngle, featureProperties, writingModes) {
const elementArray = arrays.elementArray;
const layoutVertexArray = arrays.layoutVertexArray;

Expand Down Expand Up @@ -561,6 +569,8 @@ class SymbolBucket {
segment.vertexLength += 4;
segment.primitiveLength += 2;
}

arrays.populatePaintArrays(featureProperties);
}

addToDebugBuffers(collisionTile) {
Expand Down Expand Up @@ -652,6 +662,8 @@ class SymbolBucket {
glyphQuads,
iconQuads,
anchor,
featureIndex,
featureProperties,
writingModes
});
}
Expand Down
10 changes: 9 additions & 1 deletion src/data/program_configuration.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict';

const assert = require('assert');
const createVertexArrayType = require('./vertex_array_type');
const util = require('../util/util');

Expand Down Expand Up @@ -34,6 +35,7 @@ class ProgramConfiguration {

for (const attributeConfig of attributes) {
const attribute = normalizePaintAttribute(attributeConfig, layer);
assert(/^a_/.test(attribute.name));
const name = attribute.name.slice(2);

if (layer.isPaintValueFeatureConstant(attribute.property)) {
Expand Down Expand Up @@ -210,7 +212,13 @@ function getPaintAttributeValue(attribute, layer, globalProperties, featurePrope
}

function normalizePaintAttribute(attribute, layer) {
const name = attribute.property.replace(`${layer.type}-`, '').replace(/-/g, '_');
let name = attribute.name;

// by default, construct the shader variable name for paint attribute
// `layertype-some-property` as `some_property`
if (!name) {
name = attribute.property.replace(`${layer.type}-`, '').replace(/-/g, '_');
}
const isColor = layer._paintSpecifications[attribute.property].type === 'color';

return util.extend({
Expand Down
26 changes: 15 additions & 11 deletions src/render/draw_symbol.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ function drawSymbols(painter, sourceCache, layer, coords) {
layer.paint['icon-halo-width'],
layer.paint['icon-halo-color'],
layer.paint['icon-halo-blur'],
layer.paint['icon-opacity'],
layer.paint['icon-color']
layer.paint['icon-opacity']
);

drawLayerSymbols(painter, sourceCache, layer, coords, true,
Expand All @@ -60,8 +59,7 @@ function drawSymbols(painter, sourceCache, layer, coords) {
layer.paint['text-halo-width'],
layer.paint['text-halo-color'],
layer.paint['text-halo-blur'],
layer.paint['text-opacity'],
layer.paint['text-color']
layer.paint['text-opacity']
);

if (sourceCache.map.showCollisionBoxes) {
Expand All @@ -70,7 +68,7 @@ function drawSymbols(painter, sourceCache, layer, coords) {
}

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

if (!isText && painter.style.sprite && !painter.style.sprite.loaded())
return;
Expand All @@ -96,11 +94,14 @@ function drawLayerSymbols(painter, sourceCache, layer, coords, isText, translate
if (!bucket) continue;
const buffers = isText ? bucket.buffers.glyph : bucket.buffers.icon;
if (!buffers || !buffers.segments.length) continue;
const layerData = buffers.layerData[layer.id];
const programConfiguration = layerData.programConfiguration;

const isSDF = isText || bucket.sdfIcons;

if (!program || bucket.fontstack !== prevFontstack) {
program = painter.useProgram(isSDF ? 'symbolSDF' : 'symbolIcon');
program = painter.useProgram(isSDF ? 'symbolSDF' : 'symbolIcon', programConfiguration);
programConfiguration.setUniforms(gl, program, layer, {zoom: painter.transform.zoom});

setSymbolDrawState(program, painter, isText, isSDF, rotateWithMap, pitchWithMap, bucket.fontstack, size,
bucket.iconsNeedLinear, isText ? bucket.adjustedTextSize : bucket.adjustedIconSize, opacity);
Expand All @@ -112,7 +113,7 @@ function drawLayerSymbols(painter, sourceCache, layer, coords, isText, translate
painter.translatePosMatrix(coord.posMatrix, tile, translate, translateAnchor));

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

prevFontstack = bucket.fontstack;
}
Expand Down Expand Up @@ -164,7 +165,7 @@ function setSymbolDrawState(program, painter, isText, isSDF, rotateWithMap, pitc
}

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

const gl = painter.gl;
const tr = painter.transform;
Expand All @@ -184,23 +185,26 @@ function drawTileSymbols(program, painter, layer, tile, buffers, isText, isSDF,

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_buffer, (haloOffset - haloWidth / fontScale) / sdfPx);
gl.uniform1f(program.u_is_halo, 1);

drawSymbolElements(buffers, layer, gl, program);
}

gl.uniform1f(program.u_is_halo, 0);
gl.uniform1f(program.u_gamma, gamma / gammaScale);
gl.uniform4fv(program.u_color, color);
gl.uniform1f(program.u_buffer, (256 - 64) / 256);
}

drawSymbolElements(buffers, layer, gl, program);
}

function drawSymbolElements(buffers, layer, gl, program) {
const layerData = buffers.layerData[layer.id];
const paintVertexBuffer = layerData && layerData.paintVertexBuffer;

for (const segment of buffers.segments) {
segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, null, segment.vertexOffset);
segment.vaos[layer.id].bind(gl, program, buffers.layoutVertexBuffer, buffers.elementBuffer, paintVertexBuffer, segment.vertexOffset);
gl.drawElements(gl.TRIANGLES, segment.primitiveLength * 3, gl.UNSIGNED_SHORT, segment.primitiveOffset * 3 * 2);
}
}
15 changes: 13 additions & 2 deletions src/shaders/symbol_sdf.fragment.glsl
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#pragma mapbox: define lowp vec4 fill_color
#pragma mapbox: define lowp vec4 halo_color
uniform bool u_is_halo;

uniform sampler2D u_texture;
uniform sampler2D u_fadetexture;
uniform lowp vec4 u_color;
uniform lowp float u_opacity;
uniform lowp float u_buffer;
uniform lowp float u_gamma;
Expand All @@ -10,12 +13,20 @@ varying vec2 v_fade_tex;
varying float v_gamma_scale;

void main() {
#pragma mapbox: initialize lowp vec4 fill_color
#pragma mapbox: initialize lowp vec4 halo_color

lowp vec4 color = fill_color;
if (u_is_halo) {
color = halo_color;
}

lowp float dist = texture2D(u_texture, v_tex).a;
lowp float fade_alpha = texture2D(u_fadetexture, v_fade_tex).a;
lowp float gamma = u_gamma * v_gamma_scale;
lowp float alpha = smoothstep(u_buffer - gamma, u_buffer + gamma, dist) * fade_alpha;

gl_FragColor = u_color * (alpha * u_opacity);
gl_FragColor = color * (alpha * u_opacity);

#ifdef OVERDRAW_INSPECTOR
gl_FragColor = vec4(1.0);
Expand Down
5 changes: 5 additions & 0 deletions src/shaders/symbol_sdf.vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ attribute vec2 a_offset;
attribute vec2 a_texture_pos;
attribute vec4 a_data;

#pragma mapbox: define lowp vec4 fill_color
#pragma mapbox: define lowp vec4 halo_color

// matrix is for the vertex position.
uniform mat4 u_matrix;
Expand All @@ -24,6 +26,9 @@ varying vec2 v_fade_tex;
varying float v_gamma_scale;

void main() {
#pragma mapbox: initialize lowp vec4 fill_color
#pragma mapbox: initialize lowp vec4 halo_color

vec2 a_tex = a_texture_pos.xy;
mediump float a_labelminzoom = a_data[0];
mediump vec2 a_zoom = a_data.pq;
Expand Down
4 changes: 4 additions & 0 deletions src/style-spec/reference/v8.json
Original file line number Diff line number Diff line change
Expand Up @@ -2498,6 +2498,7 @@
"default": "#000000",
"function": "interpolated",
"zoom-function": true,
"property-function": true,
"transition": true,
"doc": "The color of the icon. This can only be used with sdf icons.",
"requires": [
Expand All @@ -2518,6 +2519,7 @@
"default": "rgba(0, 0, 0, 0)",
"function": "interpolated",
"zoom-function": true,
"property-function": true,
"transition": true,
"doc": "The color of the icon's halo. Icon halos can only be used with SDF icons.",
"requires": [
Expand Down Expand Up @@ -2659,6 +2661,7 @@
"default": "#000000",
"function": "interpolated",
"zoom-function": true,
"property-function": true,
"transition": true,
"requires": [
"text-field"
Expand All @@ -2678,6 +2681,7 @@
"default": "rgba(0, 0, 0, 0)",
"function": "interpolated",
"zoom-function": true,
"property-function": true,
"transition": true,
"doc": "The color of the text's halo, which helps it stand out from backgrounds.",
"requires": [
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"version": 8,
"metadata": {
"test": {
"width": 64,
"height": 64
}
},
"sources": {
"geojson": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": { "x": 0 },
"geometry": {
"type": "Point",
"coordinates": [
0,
-10
]
}
},
{
"type": "Feature",
"properties": { "x": 1 },
"geometry": {
"type": "Point",
"coordinates": [
0,
10
]
}
}
]
}
}
},
"sprite": "local://sprites/sprite",
"layers": [
{
"id": "symbol",
"type": "symbol",
"source": "geojson",
"layout": {
"icon-image": "dot.sdf"
},
"paint": {
"icon-color": {
"property": "x",
"stops": [
[
0,
"blue"
],
[
1,
"red"
]
]
}
}
}
]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 8f58879

Please sign in to comment.