diff --git a/build/generate-struct-arrays.js b/build/generate-struct-arrays.js index 77b6dee2fd8..a0ad45b0f8c 100644 --- a/build/generate-struct-arrays.js +++ b/build/generate-struct-arrays.js @@ -76,13 +76,13 @@ function createStructArrayType(name: string, layout: StructArrayLayout, includeS } } -function createStructArrayLayoutType({members, size}) { +function createStructArrayLayoutType({members, size, alignment}) { const usedTypes = new Set(['Uint8']); members = normalizeMembers(members, usedTypes); // combine consecutive 'members' with same underlying type, summing their // component counts - members = members.reduce((memo, member) => { + if (!alignment || alignment === 1) members = members.reduce((memo, member) => { if (memo.length > 0 && memo[memo.length - 1].type === member.type) { const last = memo[memo.length - 1]; return memo.slice(0, -1).concat(util.extend({}, last, { @@ -154,7 +154,7 @@ createStructArrayType('feature_index', createLayout([ { type: 'Uint16', name: 'sourceLayerIndex' }, // the bucket the feature appears in { type: 'Uint16', name: 'bucketIndex' } -], 4), true); +]), true); // triangle index array createStructArrayType('triangle_index', createLayout([ @@ -192,7 +192,7 @@ createStructArrayLayoutType(createLayout([{ const layouts = Object.keys(layoutCache).map(k => layoutCache[k]); fs.writeFileSync('src/data/array_types.js', - `// This file is generated. Edit build/generate-struct-arrays.js, then run \`node build/generate-struct-arrays.js\`. + `// This file is generated. Edit build/generate-struct-arrays.js, then run \`yarn run codegen\`. // @flow const assert = require('assert'); diff --git a/package.json b/package.json index ad7b2517e11..4ffee255987 100644 --- a/package.json +++ b/package.json @@ -154,7 +154,8 @@ "test-flow": "node build/generate-flow-typed-style-spec && flow .", "test-flow-cov": "flow-coverage-report -i 'src/**/*.js' -t html", "test-cov": "nyc --require=flow-remove-types/register --reporter=text-summary --reporter=lcov --cache run-s test-unit test-expressions test-query test-render", - "prepublish": "in-publish && run-s build-dev build-min || not-in-publish" + "prepublish": "in-publish && run-s build-dev build-min || not-in-publish", + "codegen": "node build/generate-style-code.js && flow-node build/generate-struct-arrays.js" }, "files": [ "build/", diff --git a/src/data/array_types.js b/src/data/array_types.js index 4d86ebafe3c..fa105d1061e 100644 --- a/src/data/array_types.js +++ b/src/data/array_types.js @@ -1,4 +1,4 @@ -// This file is generated. Edit build/generate-struct-arrays.js, then run `node build/generate-struct-arrays.js`. +// This file is generated. Edit build/generate-struct-arrays.js, then run `yarn run codegen`. // @flow const assert = require('assert'); @@ -72,11 +72,12 @@ register('StructArrayLayout4i8', StructArrayLayout4i8); /** * Implementation of the StructArray layout: - * [0]: Int16[6] + * [0]: Int16[2] + * [4]: Int16[4] * * @private */ -class StructArrayLayout6i16 extends StructArray { +class StructArrayLayout2i4i12 extends StructArray { uint8: Uint8Array; int16: Int16Array; @@ -88,7 +89,7 @@ class StructArrayLayout6i16 extends StructArray { emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number) { const i = this.length; this.resize(i + 1); - const o2 = i * 8; + const o2 = i * 6; this.int16[o2 + 0] = v0; this.int16[o2 + 1] = v1; this.int16[o2 + 2] = v2; @@ -100,8 +101,8 @@ class StructArrayLayout6i16 extends StructArray { } -StructArrayLayout6i16.prototype.bytesPerElement = 16; -register('StructArrayLayout6i16', StructArrayLayout6i16); +StructArrayLayout2i4i12.prototype.bytesPerElement = 12; +register('StructArrayLayout2i4i12', StructArrayLayout2i4i12); /** @@ -290,11 +291,13 @@ register('StructArrayLayout6i1ul2ui2i24', StructArrayLayout6i1ul2ui2i24); /** * Implementation of the StructArray layout: - * [0]: Int16[6] + * [0]: Int16[2] + * [4]: Int16[2] + * [8]: Int16[2] * * @private */ -class StructArrayLayout6i12 extends StructArray { +class StructArrayLayout2i2i2i12 extends StructArray { uint8: Uint8Array; int16: Int16Array; @@ -318,8 +321,8 @@ class StructArrayLayout6i12 extends StructArray { } -StructArrayLayout6i12.prototype.bytesPerElement = 12; -register('StructArrayLayout6i12', StructArrayLayout6i12); +StructArrayLayout2i2i2i12.prototype.bytesPerElement = 12; +register('StructArrayLayout2i2i2i12', StructArrayLayout2i2i2i12); /** @@ -472,7 +475,7 @@ register('StructArrayLayout3i6', StructArrayLayout3i6); * * @private */ -class StructArrayLayout1ul2ui12 extends StructArray { +class StructArrayLayout1ul2ui8 extends StructArray { uint8: Uint8Array; uint32: Uint32Array; uint16: Uint16Array; @@ -486,8 +489,8 @@ class StructArrayLayout1ul2ui12 extends StructArray { emplaceBack(v0: number, v1: number, v2: number) { const i = this.length; this.resize(i + 1); - const o4 = i * 3; - const o2 = i * 6; + const o4 = i * 2; + const o2 = i * 4; this.uint32[o4 + 0] = v0; this.uint16[o2 + 2] = v1; this.uint16[o2 + 3] = v2; @@ -496,8 +499,8 @@ class StructArrayLayout1ul2ui12 extends StructArray { } -StructArrayLayout1ul2ui12.prototype.bytesPerElement = 12; -register('StructArrayLayout1ul2ui12', StructArrayLayout1ul2ui12); +StructArrayLayout1ul2ui8.prototype.bytesPerElement = 8; +register('StructArrayLayout1ul2ui8', StructArrayLayout1ul2ui8); /** @@ -825,11 +828,11 @@ class FeatureIndexStruct extends Struct { set featureIndex(x) { this._structArray.uint32[this._pos4 + 0] = x; } get sourceLayerIndex() { return this._structArray.uint16[this._pos2 + 2]; } set sourceLayerIndex(x) { this._structArray.uint16[this._pos2 + 2] = x; } - get bucketIndex() { return this._structArray.uint16[this._pos2 + 4]; } - set bucketIndex(x) { this._structArray.uint16[this._pos2 + 4] = x; } + get bucketIndex() { return this._structArray.uint16[this._pos2 + 3]; } + set bucketIndex(x) { this._structArray.uint16[this._pos2 + 3] = x; } } -FeatureIndexStruct.prototype.size = 12; +FeatureIndexStruct.prototype.size = 8; export type FeatureIndex = FeatureIndexStruct; @@ -837,7 +840,7 @@ export type FeatureIndex = FeatureIndexStruct; /** * @private */ -class FeatureIndexArray extends StructArrayLayout1ul2ui12 { +class FeatureIndexArray extends StructArrayLayout1ul2ui8 { /** * Return the FeatureIndexStruct at the given location in the array. * @param {number} index The index of the element. @@ -854,18 +857,18 @@ register('FeatureIndexArray', FeatureIndexArray); module.exports = { StructArrayLayout2i4, StructArrayLayout4i8, - StructArrayLayout6i16, + StructArrayLayout2i4i12, StructArrayLayout4i4ub12, StructArrayLayout4i4ui16, StructArrayLayout3f12, StructArrayLayout1ul4, StructArrayLayout6i1ul2ui2i24, - StructArrayLayout6i12, + StructArrayLayout2i2i2i12, StructArrayLayout2ub4, StructArrayLayout2i2ui3ul3ui2f2ub40, StructArrayLayout1f4, StructArrayLayout3i6, - StructArrayLayout1ul2ui12, + StructArrayLayout1ul2ui8, StructArrayLayout3ui6, StructArrayLayout2ui4, StructArrayLayout2f8, @@ -874,14 +877,14 @@ module.exports = { RasterBoundsArray: StructArrayLayout4i8, CircleLayoutArray: StructArrayLayout2i4, FillLayoutArray: StructArrayLayout2i4, - FillExtrusionLayoutArray: StructArrayLayout6i16, + FillExtrusionLayoutArray: StructArrayLayout2i4i12, HeatmapLayoutArray: StructArrayLayout2i4, LineLayoutArray: StructArrayLayout4i4ub12, SymbolLayoutArray: StructArrayLayout4i4ui16, SymbolDynamicLayoutArray: StructArrayLayout3f12, SymbolOpacityArray: StructArrayLayout1ul4, - CollisionBoxLayoutArray: StructArrayLayout6i12, - CollisionCircleLayoutArray: StructArrayLayout6i12, + CollisionBoxLayoutArray: StructArrayLayout2i2i2i12, + CollisionCircleLayoutArray: StructArrayLayout2i2i2i12, CollisionVertexArray: StructArrayLayout2ub4, TriangleIndexArray: StructArrayLayout3ui6, LineIndexArray: StructArrayLayout2ui4, diff --git a/src/data/bucket/fill_extrusion_attributes.js b/src/data/bucket/fill_extrusion_attributes.js index d64c4b3c0f8..41a8efc6c59 100644 --- a/src/data/bucket/fill_extrusion_attributes.js +++ b/src/data/bucket/fill_extrusion_attributes.js @@ -2,6 +2,5 @@ const {createLayout} = require('../../util/struct_array'); module.exports = createLayout([ {name: 'a_pos', components: 2, type: 'Int16'}, - {name: 'a_normal', components: 3, type: 'Int16'}, - {name: 'a_edgedistance', components: 1, type: 'Int16'} + {name: 'a_normal_ed', components: 4, type: 'Int16'}, ], 4); diff --git a/src/data/bucket/fill_extrusion_bucket.js b/src/data/bucket/fill_extrusion_bucket.js index 485b5f6aded..8759106c238 100644 --- a/src/data/bucket/fill_extrusion_bucket.js +++ b/src/data/bucket/fill_extrusion_bucket.js @@ -32,12 +32,11 @@ function addVertex(vertexArray, x, y, nx, ny, nz, t, e) { // a_pos x, y, - // a_normal + // a_normal_ed: 3-component normal and 1-component edgedistance Math.floor(nx * FACTOR) * 2 + t, ny * FACTOR * 2, nz * FACTOR * 2, - - // a_edgedistance + // edgedistance (used for wrapping patterns around extrusion sides) Math.round(e) ); } @@ -107,7 +106,6 @@ class FillExtrusionBucket implements Bucket { for (const ring of polygon) { numVertices += ring.length; } - let segment = this.segments.prepareSegment(4, this.layoutVertexArray, this.indexArray); for (const ring of polygon) { @@ -115,6 +113,10 @@ class FillExtrusionBucket implements Bucket { continue; } + if (isEntirelyOutside(ring)) { + continue; + } + let edgeDistance = 0; for (let p = 0; p < ring.length; p++) { @@ -129,11 +131,13 @@ class FillExtrusionBucket implements Bucket { } const perp = p1.sub(p2)._perp()._unit(); + const dist = p2.dist(p1); + if (edgeDistance + dist > 32768) edgeDistance = 0; addVertex(this.layoutVertexArray, p1.x, p1.y, perp.x, perp.y, 0, 0, edgeDistance); addVertex(this.layoutVertexArray, p1.x, p1.y, perp.x, perp.y, 0, 1, edgeDistance); - edgeDistance += p2.dist(p1); + edgeDistance += dist; addVertex(this.layoutVertexArray, p2.x, p2.y, perp.x, perp.y, 0, 0, edgeDistance); addVertex(this.layoutVertexArray, p2.x, p2.y, perp.x, perp.y, 0, 1, edgeDistance); @@ -203,3 +207,10 @@ function isBoundaryEdge(p1, p2) { return (p1.x === p2.x && (p1.x < 0 || p1.x > EXTENT)) || (p1.y === p2.y && (p1.y < 0 || p1.y > EXTENT)); } + +function isEntirelyOutside(ring) { + return ring.every(p => p.x < 0) || + ring.every(p => p.x > EXTENT) || + ring.every(p => p.y < 0) || + ring.every(p => p.y > EXTENT); +} diff --git a/src/shaders/fill_extrusion.vertex.glsl b/src/shaders/fill_extrusion.vertex.glsl index 43fc78c11f3..f375d580545 100644 --- a/src/shaders/fill_extrusion.vertex.glsl +++ b/src/shaders/fill_extrusion.vertex.glsl @@ -4,8 +4,7 @@ uniform lowp vec3 u_lightpos; uniform lowp float u_lightintensity; attribute vec2 a_pos; -attribute vec3 a_normal; -attribute float a_edgedistance; +attribute vec4 a_normal_ed; varying vec4 v_color; @@ -19,11 +18,12 @@ void main() { #pragma mapbox: initialize lowp float height #pragma mapbox: initialize highp vec4 color + vec3 normal = a_normal_ed.xyz; + base = max(0.0, base); height = max(0.0, height); - float ed = a_edgedistance; // use each attrib in order to not trip a VAO assert - float t = mod(a_normal.x, 2.0); + float t = mod(normal.x, 2.0); gl_Position = u_matrix * vec4(a_pos, t > 0.0 ? height : base, 1); @@ -37,7 +37,7 @@ void main() { color += ambientlight; // Calculate cos(theta), where theta is the angle between surface normal and diffuse light ray - float directional = clamp(dot(a_normal / 16384.0, u_lightpos), 0.0, 1.0); + float directional = clamp(dot(normal / 16384.0, u_lightpos), 0.0, 1.0); // Adjust directional so that // the range of values for highlight/shading is narrower @@ -46,7 +46,7 @@ void main() { directional = mix((1.0 - u_lightintensity), max((1.0 - colorvalue + u_lightintensity), 1.0), directional); // Add gradient along z axis of side surfaces - if (a_normal.y != 0.0) { + if (normal.y != 0.0) { directional *= clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - u_lightintensity), 1.0); } diff --git a/src/shaders/fill_extrusion_pattern.vertex.glsl b/src/shaders/fill_extrusion_pattern.vertex.glsl index 4cbdfaa3789..253800c8611 100644 --- a/src/shaders/fill_extrusion_pattern.vertex.glsl +++ b/src/shaders/fill_extrusion_pattern.vertex.glsl @@ -13,8 +13,7 @@ uniform lowp vec3 u_lightpos; uniform lowp float u_lightintensity; attribute vec2 a_pos; -attribute vec3 a_normal; -attribute float a_edgedistance; +attribute vec4 a_normal_ed; varying vec2 v_pos_a; varying vec2 v_pos_b; @@ -28,26 +27,29 @@ void main() { #pragma mapbox: initialize lowp float base #pragma mapbox: initialize lowp float height + vec3 normal = a_normal_ed.xyz; + float edgedistance = a_normal_ed.w; + base = max(0.0, base); height = max(0.0, height); - float t = mod(a_normal.x, 2.0); + float t = mod(normal.x, 2.0); float z = t > 0.0 ? height : base; gl_Position = u_matrix * vec4(a_pos, z, 1); - vec2 pos = a_normal.x == 1.0 && a_normal.y == 0.0 && a_normal.z == 16384.0 + vec2 pos = normal.x == 1.0 && normal.y == 0.0 && normal.z == 16384.0 ? a_pos // extrusion top - : vec2(a_edgedistance, z * u_height_factor); // extrusion side + : vec2(edgedistance, z * u_height_factor); // extrusion side v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, pos); v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, pos); v_lighting = vec4(0.0, 0.0, 0.0, 1.0); - float directional = clamp(dot(a_normal / 16383.0, u_lightpos), 0.0, 1.0); + float directional = clamp(dot(normal / 16383.0, u_lightpos), 0.0, 1.0); directional = mix((1.0 - u_lightintensity), max((0.5 + u_lightintensity), 1.0), directional); - if (a_normal.y != 0.0) { + if (normal.y != 0.0) { directional *= clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - u_lightintensity), 1.0); } diff --git a/src/style/style_layer/background_style_layer_properties.js b/src/style/style_layer/background_style_layer_properties.js index d86d3d2d897..ae5677589a2 100644 --- a/src/style/style_layer/background_style_layer_properties.js +++ b/src/style/style_layer/background_style_layer_properties.js @@ -1,4 +1,4 @@ -// This file is generated. Edit build/generate-style-code.js, then run `node build/generate-style-code.js`. +// This file is generated. Edit build/generate-style-code.js, then run `yarn run codegen`. // @flow /* eslint-disable */ diff --git a/src/style/style_layer/circle_style_layer_properties.js b/src/style/style_layer/circle_style_layer_properties.js index 17788b25910..27e63fbcc85 100644 --- a/src/style/style_layer/circle_style_layer_properties.js +++ b/src/style/style_layer/circle_style_layer_properties.js @@ -1,4 +1,4 @@ -// This file is generated. Edit build/generate-style-code.js, then run `node build/generate-style-code.js`. +// This file is generated. Edit build/generate-style-code.js, then run `yarn run codegen`. // @flow /* eslint-disable */ diff --git a/src/style/style_layer/fill_extrusion_style_layer_properties.js b/src/style/style_layer/fill_extrusion_style_layer_properties.js index 785f2e9a6cd..7a0189092f4 100644 --- a/src/style/style_layer/fill_extrusion_style_layer_properties.js +++ b/src/style/style_layer/fill_extrusion_style_layer_properties.js @@ -1,4 +1,4 @@ -// This file is generated. Edit build/generate-style-code.js, then run `node build/generate-style-code.js`. +// This file is generated. Edit build/generate-style-code.js, then run `yarn run codegen`. // @flow /* eslint-disable */ diff --git a/src/style/style_layer/fill_style_layer_properties.js b/src/style/style_layer/fill_style_layer_properties.js index cc428ca8502..da8783d4ad1 100644 --- a/src/style/style_layer/fill_style_layer_properties.js +++ b/src/style/style_layer/fill_style_layer_properties.js @@ -1,4 +1,4 @@ -// This file is generated. Edit build/generate-style-code.js, then run `node build/generate-style-code.js`. +// This file is generated. Edit build/generate-style-code.js, then run `yarn run codegen`. // @flow /* eslint-disable */ diff --git a/src/style/style_layer/heatmap_style_layer_properties.js b/src/style/style_layer/heatmap_style_layer_properties.js index 53bdae8c5c0..9b7f51da842 100644 --- a/src/style/style_layer/heatmap_style_layer_properties.js +++ b/src/style/style_layer/heatmap_style_layer_properties.js @@ -1,4 +1,4 @@ -// This file is generated. Edit build/generate-style-code.js, then run `node build/generate-style-code.js`. +// This file is generated. Edit build/generate-style-code.js, then run `yarn run codegen`. // @flow /* eslint-disable */ diff --git a/src/style/style_layer/hillshade_style_layer_properties.js b/src/style/style_layer/hillshade_style_layer_properties.js index 24578df822e..382b2bf7872 100644 --- a/src/style/style_layer/hillshade_style_layer_properties.js +++ b/src/style/style_layer/hillshade_style_layer_properties.js @@ -1,4 +1,4 @@ -// This file is generated. Edit build/generate-style-code.js, then run `node build/generate-style-code.js`. +// This file is generated. Edit build/generate-style-code.js, then run `yarn run codegen`. // @flow /* eslint-disable */ diff --git a/src/style/style_layer/layer_properties.js.ejs b/src/style/style_layer/layer_properties.js.ejs index 5cd90983daf..b154ccea78f 100644 --- a/src/style/style_layer/layer_properties.js.ejs +++ b/src/style/style_layer/layer_properties.js.ejs @@ -3,7 +3,7 @@ const layoutProperties = locals.layoutProperties; const paintProperties = locals.paintProperties; -%> -// This file is generated. Edit build/generate-style-code.js, then run `node build/generate-style-code.js`. +// This file is generated. Edit build/generate-style-code.js, then run `yarn run codegen`. // @flow /* eslint-disable */ diff --git a/src/style/style_layer/line_style_layer_properties.js b/src/style/style_layer/line_style_layer_properties.js index 48b9a747793..8e89efc77b8 100644 --- a/src/style/style_layer/line_style_layer_properties.js +++ b/src/style/style_layer/line_style_layer_properties.js @@ -1,4 +1,4 @@ -// This file is generated. Edit build/generate-style-code.js, then run `node build/generate-style-code.js`. +// This file is generated. Edit build/generate-style-code.js, then run `yarn run codegen`. // @flow /* eslint-disable */ diff --git a/src/style/style_layer/raster_style_layer_properties.js b/src/style/style_layer/raster_style_layer_properties.js index cf66430a380..bbe853bf4a9 100644 --- a/src/style/style_layer/raster_style_layer_properties.js +++ b/src/style/style_layer/raster_style_layer_properties.js @@ -1,4 +1,4 @@ -// This file is generated. Edit build/generate-style-code.js, then run `node build/generate-style-code.js`. +// This file is generated. Edit build/generate-style-code.js, then run `yarn run codegen`. // @flow /* eslint-disable */ diff --git a/src/style/style_layer/symbol_style_layer_properties.js b/src/style/style_layer/symbol_style_layer_properties.js index 98957edd994..705e76373d5 100644 --- a/src/style/style_layer/symbol_style_layer_properties.js +++ b/src/style/style_layer/symbol_style_layer_properties.js @@ -1,4 +1,4 @@ -// This file is generated. Edit build/generate-style-code.js, then run `node build/generate-style-code.js`. +// This file is generated. Edit build/generate-style-code.js, then run `yarn run codegen`. // @flow /* eslint-disable */ diff --git a/src/util/struct_array.js b/src/util/struct_array.js index 5c48c932645..5233908840f 100644 --- a/src/util/struct_array.js +++ b/src/util/struct_array.js @@ -57,7 +57,8 @@ export type StructArrayMember = { export type StructArrayLayout = { members: Array, - size: number + size: number, + alignment: ?number } export type SerializedStructArray = { @@ -224,7 +225,8 @@ function createLayout( return { members: layoutMembers, - size + size, + alignment }; } diff --git a/test/unit/util/struct_array.test.js b/test/unit/util/struct_array.test.js index 7ce85cd3b66..0550bea40c4 100644 --- a/test/unit/util/struct_array.test.js +++ b/test/unit/util/struct_array.test.js @@ -2,7 +2,7 @@ 'use strict'; const test = require('mapbox-gl-js-test').test; -const {StructArrayLayout3i6} = require('../../../src/data/array_types'); +const {StructArrayLayout3i6, FeatureIndexArray} = require('../../../src/data/array_types'); test('StructArray', (t) => { class TestArray extends StructArrayLayout3i6 {} @@ -83,3 +83,40 @@ test('StructArray', (t) => { t.end(); }); + +test('FeatureIndexArray', (t) => { + class TestArray extends FeatureIndexArray {} + + t.test('array constructs itself', (t) => { + const array = new TestArray(); + t.equal(array.length, 0); + t.ok(array.arrayBuffer); + t.end(); + }); + + t.test('emplace and retrieve', (t) => { + const array = new TestArray(); + t.equal(0, array.emplaceBack(1, 7, 3)); + t.equal(1, array.emplaceBack(4, 2, 5)); + + t.equal(array.length, 2); + + const elem0 = array.get(0); + t.ok(elem0); + + t.equal(elem0.featureIndex, 1, 'returns correct featureIndex'); + t.equal(elem0.sourceLayerIndex, 7, 'returns correct sourceLayerIndex'); + t.equal(elem0.bucketIndex, 3, 'returns correct bucketIndex'); + + const elem1 = array.get(1); + t.ok(elem1); + + t.equal(elem1.featureIndex, 4, 'returns correct featureIndex'); + t.equal(elem1.sourceLayerIndex, 2, 'returns correct sourceLayerIndex'); + t.equal(elem1.bucketIndex, 5, 'returns correct bucketIndex'); + + t.end(); + }); + + t.end(); +});