diff --git a/src/ol/render/webgl/MixedGeometryBatch.js b/src/ol/render/webgl/MixedGeometryBatch.js index 02e6894865a..51f8cc0c862 100644 --- a/src/ol/render/webgl/MixedGeometryBatch.js +++ b/src/ol/render/webgl/MixedGeometryBatch.js @@ -519,17 +519,22 @@ class MixedGeometryBatch { /** * @param {Feature|RenderFeature} feature Feature + * @param {import("../../proj.js").TransformFunction} [projectionTransform] Projection transform. */ - changeFeature(feature) { + changeFeature(feature, projectionTransform) { // the feature is not present in the batch; do not add it to avoid unexpected behaviors if (!this.uidToRef_.get(getUid(feature))) { return; } this.removeFeature(feature); - const geometry = feature.getGeometry(); + let geometry = feature.getGeometry(); if (!geometry) { return; } + if (projectionTransform) { + geometry = geometry.clone(); + geometry.applyTransform(projectionTransform); + } this.addGeometry_(geometry, feature); } diff --git a/src/ol/renderer/webgl/VectorLayer.js b/src/ol/renderer/webgl/VectorLayer.js index d968a5a30d6..09d91195831 100644 --- a/src/ol/renderer/webgl/VectorLayer.js +++ b/src/ol/renderer/webgl/VectorLayer.js @@ -211,7 +211,7 @@ class WebGLVectorLayerRenderer extends WebGLLayerRenderer { listen( source, VectorEventType.CHANGEFEATURE, - this.handleSourceFeatureChanged_, + this.handleSourceFeatureChanged_.bind(this, projectionTransform), this, ), listen( @@ -295,12 +295,13 @@ class WebGLVectorLayerRenderer extends WebGLLayerRenderer { } /** + * @param {import("../../proj.js").TransformFunction} projectionTransform Transform function. * @param {import("../../source/Vector.js").VectorSourceEvent} event Event. * @private */ - handleSourceFeatureChanged_(event) { + handleSourceFeatureChanged_(projectionTransform, event) { const feature = event.feature; - this.batch_.changeFeature(feature); + this.batch_.changeFeature(feature, projectionTransform); } /** diff --git a/src/ol/webgl/Helper.js b/src/ol/webgl/Helper.js index 8614c7e2d71..f8168a62406 100644 --- a/src/ol/webgl/Helper.js +++ b/src/ol/webgl/Helper.js @@ -446,6 +446,14 @@ class WebGLHelper extends Disposable { * @private */ this.startTime_ = Date.now(); + + /** + * @type {number} + * @private + */ + this.maxAttributeCount_ = this.gl_.getParameter( + this.gl_.MAX_VERTEX_ATTRIBS, + ); } /** @@ -894,6 +902,7 @@ class WebGLHelper extends Disposable { * @param {import("../Map.js").FrameState} [frameState] Frame state. */ useProgram(program, frameState) { + this.disableAllAttributes_(); const gl = this.gl_; gl.useProgram(program); this.currentProgram_ = program; @@ -1065,6 +1074,16 @@ class WebGLHelper extends Disposable { this.gl_.uniformMatrix4fv(this.getUniformLocation(uniform), false, value); } + /** + * Disable all vertex attributes. + * @private + */ + disableAllAttributes_() { + for (let i = 0; i < this.maxAttributeCount_; i++) { + this.gl_.disableVertexAttribArray(i); + } + } + /** * Will set the currently bound buffer to an attribute of the shader program. Used by `#enableAttributes` * internally. diff --git a/test/browser/spec/ol/render/webgl/MixedGeometryBatch.test.js b/test/browser/spec/ol/render/webgl/MixedGeometryBatch.test.js index fbeea68208b..2cf1dd2f313 100644 --- a/test/browser/spec/ol/render/webgl/MixedGeometryBatch.test.js +++ b/test/browser/spec/ol/render/webgl/MixedGeometryBatch.test.js @@ -8,6 +8,7 @@ import MultiPoint from '../../../../../../src/ol/geom/MultiPoint.js'; import MultiPolygon from '../../../../../../src/ol/geom/MultiPolygon.js'; import Point from '../../../../../../src/ol/geom/Point.js'; import Polygon from '../../../../../../src/ol/geom/Polygon.js'; +import {getTransform} from '../../../../../../src/ol/proj.js'; import RenderFeature from '../../../../../../src/ol/render/Feature.js'; import MixedGeometryBatch from '../../../../../../src/ol/render/webgl/MixedGeometryBatch.js'; import {getUid} from '../../../../../../src/ol/util.js'; @@ -1229,6 +1230,36 @@ describe('MixedGeometryBatch', function () { }); }); + describe('with projectionTransform', () => { + let geometry1, feature1, uid1, projectionTransform, transformedFlatCoordss; + + beforeEach(() => { + projectionTransform = getTransform('EPSG:4326', 'EPSG:3857'); + + geometry1 = new Point([135, 35]); + feature1 = new Feature({ + geometry: geometry1, + }); + + uid1 = getUid(feature1); + transformedFlatCoordss = [projectionTransform([135, 35])]; + + mixedBatch.addFeature(feature1, projectionTransform); + }); + + it('has the transformed flatCoords', () => { + expect(mixedBatch.pointBatch.entries[uid1].flatCoordss).to.eql( + transformedFlatCoordss, + ); + }); + it('has the same transformed flatCoords after changeFeature', () => { + mixedBatch.changeFeature(feature1, projectionTransform); + expect(mixedBatch.pointBatch.entries[uid1].flatCoordss).to.eql( + transformedFlatCoordss, + ); + }); + }); + describe('#clear', () => { beforeEach(() => { const feature1 = new Feature( diff --git a/test/browser/spec/ol/webgl/helper.test.js b/test/browser/spec/ol/webgl/helper.test.js index 365ec9c70f8..cd2a10788f7 100644 --- a/test/browser/spec/ol/webgl/helper.test.js +++ b/test/browser/spec/ol/webgl/helper.test.js @@ -479,4 +479,22 @@ describe('ol/webgl/WebGLHelper', function () { ]); }); }); + + describe('attributes disabling', () => { + let disableAttribSpy; + beforeEach(() => { + h = new WebGLHelper(); + disableAttribSpy = sinonSpy(h.getGL(), 'disableVertexAttribArray'); + const program = h.getProgram(FRAGMENT_SHADER, VERTEX_SHADER); + h.useProgram(program, SAMPLE_FRAMESTATE); + }); + it('all active attributes are disabled when enabling programs, disregarding of previous state', () => { + const gl = h.getGL(); + const max = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); + expect(disableAttribSpy.getCalls().length).to.eql(max); // each possible attribute is disabled + for (let i = 0; i < max; i++) { + expect(disableAttribSpy.getCall(i).args[0]).to.eql(i); + } + }); + }); }); diff --git a/test/rendering/cases/webgl-vector-geographic/expected.png b/test/rendering/cases/webgl-vector-geographic/expected.png index 58092a5ad09..df3c04d9c4e 100644 Binary files a/test/rendering/cases/webgl-vector-geographic/expected.png and b/test/rendering/cases/webgl-vector-geographic/expected.png differ diff --git a/test/rendering/cases/webgl-vector-geographic/main.js b/test/rendering/cases/webgl-vector-geographic/main.js index 086add0f90f..fb93e5a0fa8 100644 --- a/test/rendering/cases/webgl-vector-geographic/main.js +++ b/test/rendering/cases/webgl-vector-geographic/main.js @@ -1,6 +1,7 @@ import Map from '../../../../src/ol/Map.js'; import View from '../../../../src/ol/View.js'; import GeoJSON from '../../../../src/ol/format/GeoJSON.js'; +import Polygon from '../../../../src/ol/geom/Polygon.js'; import WebGLVectorLayer from '../../../../src/ol/layer/WebGLVector.js'; import {useGeographic} from '../../../../src/ol/proj.js'; import VectorSource from '../../../../src/ol/source/Vector.js'; @@ -12,6 +13,23 @@ const features = format.readFeatures({ type: 'FeatureCollection', features: [ { + // for case 1: initially placed geometries should be transformed properly + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [ + [ + [0, -65], + [100, 0], + [0, 65], + [-100, 0], + [0, -65], + ], + ], + }, + }, + { + // for case 2: geometries changed after initial rendering should be transformed properly too type: 'Feature', geometry: { type: 'Polygon', @@ -40,7 +58,7 @@ const vector = new WebGLVectorLayer({ }, }); -new Map({ +const map = new Map({ layers: [vector], target: 'map', view: new View({ @@ -49,7 +67,22 @@ new Map({ }), }); -render({ - message: - 'Geometries using geographic coordinates are transformed before rendering', +map.once('rendercomplete', function () { + // case2: update geometry after initial rendering + features[1].setGeometry( + new Polygon([ + [ + [-100, 65], + [0, 65], + [-100, 0], + [-100, 65], + ], + ]), + ); + map.renderSync(); + + render({ + message: + 'Geometries using geographic coordinates are always transformed properly', + }); });