Skip to content

Commit

Permalink
Circles: meet v8.
Browse files Browse the repository at this point in the history
This is a manual redo of #1241 on top of the v8 branch.
  • Loading branch information
tmcw authored and Lucas Wojciechowski committed Aug 7, 2015
1 parent 677a327 commit 571b843
Show file tree
Hide file tree
Showing 12 changed files with 2,401 additions and 2 deletions.
2,192 changes: 2,192 additions & 0 deletions debug/bright-v8.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions debug/random.geojson

Large diffs are not rendered by default.

17 changes: 16 additions & 1 deletion debug/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ var map = new mapboxgl.Map({
container: 'map',
zoom: 12.5,
center: [38.888, -77.01866],
style: 'bright-v7-types.json',
style: 'bright-v8.json',
hash: true
});

Expand All @@ -26,6 +26,21 @@ map.on('style.load', function() {
"line-width": "@motorway_width"
}
}, 'country_label_1');

map.addSource('geojson-random-points', {
"type": "geojson",
"data": "/debug/random.geojson"
});

map.addLayer({
"id": "random-points",
"type": "circle",
"source": "geojson-random-points",
"paint": {
"circle-radius": 5,
"circle-color": "#f0f"
}
}, 'random-points');
});

map.on('click', function(e) {
Expand Down
4 changes: 4 additions & 0 deletions js/data/buffer/buffer_set.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ var GlyphElementBuffer = require('./triangle_element_buffer');
var IconVertexBuffer = require('./icon_vertex_buffer');
var IconElementBuffer = require('./triangle_element_buffer');
var CollisionBoxVertexBuffer = require('./collision_box_vertex_buffer');
var CircleVertexBuffer = require('./circle_vertex_buffer');
var CircleElementBuffer = require('./triangle_element_buffer');

module.exports = function(bufferset) {
bufferset = bufferset || {};
Expand All @@ -18,6 +20,8 @@ module.exports = function(bufferset) {
glyphElement: new GlyphElementBuffer(bufferset.glyphElement),
iconVertex: new IconVertexBuffer(bufferset.iconVertex),
iconElement: new IconElementBuffer(bufferset.iconElement),
circleVertex: new CircleVertexBuffer(bufferset.circleVertex),
circleElement: new CircleElementBuffer(bufferset.circleElement),
fillVertex: new FillVertexBuffer(bufferset.fillVertex),
fillElement: new FillElementBuffer(bufferset.fillElement),
outlineElement: new OutlineElementBuffer(bufferset.outlineElement),
Expand Down
41 changes: 41 additions & 0 deletions js/data/buffer/circle_vertex_buffer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

var util = require('../../util/util');
var Buffer = require('./buffer');

module.exports = CircleVertexBuffer;

/**
* This contains the data that displays circle markers on the map,
* including their centerpoint
*/
function CircleVertexBuffer(buffer) {
Buffer.call(this, buffer);
}

CircleVertexBuffer.prototype = util.inherit(Buffer, {
defaultLength: 2048 * 16,

itemSize: 4, // 2 bytes per short * 4 of them

add: function(x, y, extrudeX, extrudeY) {
var pos = this.pos,
pos2 = pos / 2;

this.resize();

// pack the extrusion of -1 or 1 into one short
this.shorts[pos2 + 0] = (x * 2) + ((extrudeX + 1) / 2);
this.shorts[pos2 + 1] = (y * 2) + ((extrudeY + 1) / 2);

this.pos += this.itemSize;
},

bind: function(gl, shader, offset) {
Buffer.prototype.bind.call(this, gl);

gl.vertexAttribPointer(shader.a_pos, 2,
gl.SHORT, false,
this.itemSize, offset + 0);
}
});
56 changes: 56 additions & 0 deletions js/data/circle_bucket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use strict';

var ElementGroups = require('./element_groups');

module.exports = CircleBucket;

/**
* A container for all circle data
*
* Circles are represented by two triangles.
*
* Each corner has a pos that is the center of the circle and an extrusion
* vector that is where it points.
*/
function CircleBucket(buffers) {
this.buffers = buffers;
this.elementGroups = new ElementGroups(
buffers.circleVertex,
buffers.circleElement);
}

CircleBucket.prototype.addFeatures = function() {
for (var i = 0; i < this.features.length; i++) {
var geometries = this.features[i].loadGeometry()[0];
for (var j = 0; j < geometries.length; j++) {
this.elementGroups.makeRoomFor(6);
var x = geometries[j].x,
y = geometries[j].y;

var idx = this.buffers.circleVertex.index -
this.elementGroups.current.vertexStartIndex;

// this geometry will be of the Point type, and we'll derive
// two triangles from it.
//
// ┌─────────┐
// │ 4 3 │
// │ │
// │ 1 2 │
// └─────────┘
//
this.buffers.circleVertex.add(x, y, -1, -1); // 1
this.buffers.circleVertex.add(x, y, 1, -1); // 2
this.buffers.circleVertex.add(x, y, 1, 1); // 3
this.buffers.circleVertex.add(x, y, -1, 1); // 4

// 1, 2, 3
// 1, 4, 3
this.elementGroups.elementBuffer.add(idx, idx + 1, idx + 2);
this.elementGroups.elementBuffer.add(idx, idx + 3, idx + 2);

this.elementGroups.current.vertexLength += 4;
this.elementGroups.current.elementLength += 2;
}
}
};
4 changes: 3 additions & 1 deletion js/data/create_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = createBucket;
var LineBucket = require('./line_bucket');
var FillBucket = require('./fill_bucket');
var SymbolBucket = require('./symbol_bucket');
var CircleBucket = require('./circle_bucket');
var LayoutProperties = require('../style/layout_properties');
var featureFilter = require('feature-filter');
var StyleDeclarationSet = require('../style/style_declaration_set');
Expand All @@ -21,7 +22,8 @@ function createBucket(layer, buffers, z, overscaling, collisionDebug) {
var BucketClass =
layer.type === 'line' ? LineBucket :
layer.type === 'fill' ? FillBucket :
layer.type === 'symbol' ? SymbolBucket : null;
layer.type === 'symbol' ? SymbolBucket :
layer.type === 'circle' ? CircleBucket : null;

var bucket = new BucketClass(buffers, new LayoutProperties[layer.type](layout), overscaling, z, collisionDebug);

Expand Down
49 changes: 49 additions & 0 deletions js/render/draw_circle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';

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;

var elementGroups = tile.elementGroups[layer.ref || layer.id];
if (!elementGroups) return;

var gl = painter.gl;

// 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, tile.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
// are inversely related.
var antialias = 1 / browser.devicePixelRatio / layer.paint['circle-radius'];

gl.uniform4fv(shader.u_color, layer.paint['circle-color']);
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;

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

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);
}
5 changes: 5 additions & 0 deletions js/render/painter.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ Painter.prototype.setup = function() {
['a_pos', 'a_texture_pos'],
['u_matrix', 'u_brightness_low', 'u_brightness_high', 'u_saturation_factor', 'u_spin_weights', 'u_contrast_factor', 'u_opacity0', 'u_opacity1', 'u_image0', 'u_image1', 'u_tl_parent', 'u_scale_parent', 'u_buffer_scale']);

this.circleShader = gl.initializeShader('circle',
['a_pos'],
['u_matrix', 'u_exmatrix', 'u_blur', 'u_size', 'u_color']);

this.lineShader = gl.initializeShader('line',
['a_pos', 'a_data'],
['u_matrix', 'u_linewidth', 'u_color', 'u_ratio', 'u_blur', 'u_extra', 'u_antialiasingmatrix']);
Expand Down Expand Up @@ -226,6 +230,7 @@ Painter.prototype.bindDefaultFramebuffer = function() {

var draw = {
symbol: require('./draw_symbol'),
circle: require('./draw_circle'),
line: require('./draw_line'),
fill: require('./draw_fill'),
raster: require('./draw_raster'),
Expand Down
1 change: 1 addition & 0 deletions js/render/shaders.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
"debug": glify('../../shaders/debug.*.glsl'),
"dot": glify('../../shaders/dot.*.glsl'),
"fill": glify('../../shaders/fill.*.glsl'),
"circle": glify('../../shaders/circle.*.glsl'),
"gaussian": glify('../../shaders/gaussian.*.glsl'),
"line": glify('../../shaders/line.*.glsl'),
"linepattern": glify('../../shaders/linepattern.*.glsl'),
Expand Down
10 changes: 10 additions & 0 deletions shaders/circle.fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
uniform vec4 u_color;
uniform float u_blur;
uniform float u_size;

varying vec2 v_extrude;

void main() {
float t = smoothstep(1.0 - u_blur, 1.0, length(v_extrude));
gl_FragColor = u_color * (1.0 - t);
}
23 changes: 23 additions & 0 deletions shaders/circle.vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// set by gl_util
uniform float u_size;

attribute vec2 a_pos;

uniform mat4 u_matrix;
uniform mat4 u_exmatrix;

varying vec2 v_extrude;

void main(void) {
// unencode the extrusion vector that we snuck into the a_pos vector
v_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0);

vec4 extrude = u_exmatrix * vec4(v_extrude * u_size, 0, 0);
// multiply a_pos by 0.5, since we had it * 2 in order to sneak
// in extrusion data
gl_Position = u_matrix * vec4(a_pos * 0.5, 0, 1);

// gl_Position is divided by gl_Position.w after this shader runs.
// Multiply the extrude by it so that it isn't affected by it.
gl_Position += extrude * gl_Position.w;
}

0 comments on commit 571b843

Please sign in to comment.