diff --git a/src/ol/render/webgl/BatchRenderer.js b/src/ol/render/webgl/BatchRenderer.js index a19dff4360..3de9c69305 100644 --- a/src/ol/render/webgl/BatchRenderer.js +++ b/src/ol/render/webgl/BatchRenderer.js @@ -8,6 +8,7 @@ import { create as createTransform, makeInverse as makeInverseTransform, multiply as multiplyTransform, + translate as translateTransform, } from '../../transform.js'; /** @@ -89,11 +90,12 @@ class AbstractBatchRenderer { * @param {import("./MixedGeometryBatch.js").GeometryBatch} batch Geometry batch * @param {import("../../transform.js").Transform} currentTransform Transform * @param {import("../../PluggableMap.js").FrameState} frameState Frame state. + * @param {number} offsetX X offset */ - render(batch, currentTransform, frameState) { + render(batch, currentTransform, frameState, offsetX) { // multiply the current projection transform with the invert of the one used to fill buffers - // FIXME: this should probably be done directly in the layer renderer this.helper_.makeProjectionTransform(frameState, currentTransform); + translateTransform(currentTransform, offsetX, 0); multiplyTransform(currentTransform, batch.invertVerticesBufferTransform); // enable program, buffers and attributes diff --git a/src/ol/renderer/webgl/VectorLayer.js b/src/ol/renderer/webgl/VectorLayer.js index f8c3eebe13..507af098ef 100644 --- a/src/ol/renderer/webgl/VectorLayer.js +++ b/src/ol/renderer/webgl/VectorLayer.js @@ -11,7 +11,7 @@ import VectorEventType from '../../source/VectorEventType.js'; import ViewHint from '../../ViewHint.js'; import WebGLLayerRenderer from './Layer.js'; import {DefaultUniform} from '../../webgl/Helper.js'; -import {buffer, createEmpty, equals} from '../../extent.js'; +import {buffer, createEmpty, equals, getWidth} from '../../extent.js'; import {create as createTransform} from '../../transform.js'; import {create as createWebGLWorker} from '../../worker/webgl.js'; import {listen, unlistenByKey} from '../../events.js'; @@ -226,21 +226,42 @@ class WebGLVectorLayerRenderer extends WebGLLayerRenderer { renderFrame(frameState) { const gl = this.helper.getGL(); this.preRender(gl, frameState); - this.polygonRenderer_.render( - this.batch_.polygonBatch, - this.currentTransform_, - frameState - ); - this.lineStringRenderer_.render( - this.batch_.lineStringBatch, - this.currentTransform_, - frameState - ); - this.pointRenderer_.render( - this.batch_.pointBatch, - this.currentTransform_, - frameState - ); + + const layer = this.getLayer(); + const vectorSource = layer.getSource(); + const projection = frameState.viewState.projection; + const multiWorld = vectorSource.getWrapX() && projection.canWrapX(); + const projectionExtent = projection.getExtent(); + const extent = frameState.extent; + const worldWidth = multiWorld ? getWidth(projectionExtent) : null; + const endWorld = multiWorld + ? Math.ceil((extent[2] - projectionExtent[2]) / worldWidth) + 1 + : 1; + let world = multiWorld + ? Math.floor((extent[0] - projectionExtent[0]) / worldWidth) + : 0; + + do { + this.polygonRenderer_.render( + this.batch_.polygonBatch, + this.currentTransform_, + frameState, + world * worldWidth + ); + this.lineStringRenderer_.render( + this.batch_.lineStringBatch, + this.currentTransform_, + frameState, + world * worldWidth + ); + this.pointRenderer_.render( + this.batch_.pointBatch, + this.currentTransform_, + frameState, + world * worldWidth + ); + } while (++world < endWorld); + this.helper.finalizeDraw(frameState); const canvas = this.helper.getCanvas(); diff --git a/test/browser/spec/ol/render/webgl/batchrenderer.test.js b/test/browser/spec/ol/render/webgl/batchrenderer.test.js index 7d47eaad3d..fa00eee520 100644 --- a/test/browser/spec/ol/render/webgl/batchrenderer.test.js +++ b/test/browser/spec/ol/render/webgl/batchrenderer.test.js @@ -10,7 +10,10 @@ import PolygonBatchRenderer from '../../../../../../src/ol/render/webgl/PolygonB import WebGLHelper from '../../../../../../src/ol/webgl/Helper.js'; import {FLOAT} from '../../../../../../src/ol/webgl.js'; import {WebGLWorkerMessageType} from '../../../../../../src/ol/render/webgl/constants.js'; -import {create as createTransform} from '../../../../../../src/ol/transform.js'; +import { + create as createTransform, + translate as translateTransform, +} from '../../../../../../src/ol/transform.js'; import {create as createWebGLWorker} from '../../../../../../src/ol/worker/webgl.js'; const POINT_VERTEX_SHADER = `precision mediump float; @@ -133,6 +136,8 @@ describe('Batch renderers', function () { }); }); describe('#render (from parent)', function () { + let transform; + const offsetX = 12; beforeEach(function () { sinon.spy(helper, 'makeProjectionTransform'); sinon.spy(helper, 'useProgram'); @@ -140,16 +145,25 @@ describe('Batch renderers', function () { sinon.spy(helper, 'enableAttributes'); sinon.spy(helper, 'drawElements'); - const transform = createTransform(); + transform = createTransform(); batchRenderer.render( mixedBatch.pointBatch, transform, - SAMPLE_FRAMESTATE + SAMPLE_FRAMESTATE, + offsetX ); }); it('computes current transform', function () { expect(helper.makeProjectionTransform.calledOnce).to.be(true); }); + it('includes the X offset in the transform used for rendering', function () { + const expected = helper.makeProjectionTransform( + SAMPLE_FRAMESTATE, + createTransform() + ); + translateTransform(expected, offsetX, 0); + expect(transform).to.eql(expected); + }); it('computes sets up render parameters', function () { expect(helper.useProgram.calledOnce).to.be(true); expect(helper.enableAttributes.calledOnce).to.be(true);