diff --git a/examples/synthetic-points.js b/examples/synthetic-points.js index 447cc7d930..c26a5615b8 100644 --- a/examples/synthetic-points.js +++ b/examples/synthetic-points.js @@ -18,7 +18,7 @@ for (var i = 0; i < count; ++i) { 'geometry': new ol.geom.Point( [2 * e * Math.random() - e, 2 * e * Math.random() - e]), 'i': i, - 'size': i % 2 ? 10 : 20 + 'size': 20 }); } diff --git a/src/ol/render/webgl/webglreplay.js b/src/ol/render/webgl/webglreplay.js index c86225faf7..b977824bad 100644 --- a/src/ol/render/webgl/webglreplay.js +++ b/src/ol/render/webgl/webglreplay.js @@ -41,6 +41,12 @@ ol.render.webgl.Replay = function(tolerance) { */ this.indicesBuffer = null; + /** + * @protected + * @type {WebGLTexture} + */ + this.texture = null; + /** * @private * @type {ol.Extent} @@ -50,66 +56,6 @@ ol.render.webgl.Replay = function(tolerance) { }; -/** - * @param {Array.} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {boolean} close Close. - * @return {number} My end. - * @protected - */ -ol.render.webgl.Replay.prototype.appendFlatCoordinates = - function(flatCoordinates, offset, end, stride, close) { - var numIndices = this.indices.length; - var numVertices = this.vertices.length; - var i, x, y, n; - var oy = 0.05; - var ox = 0.01; - for (i = offset; i < end; i += stride) { - x = flatCoordinates[i]; - y = flatCoordinates[i + 1]; - - n = numVertices / 4; - - // create 4 vertices per coordinate - - this.vertices[numVertices++] = x; - this.vertices[numVertices++] = y; - this.vertices[numVertices++] = -ox; - this.vertices[numVertices++] = -oy; - - this.vertices[numVertices++] = x; - this.vertices[numVertices++] = y; - this.vertices[numVertices++] = ox; - this.vertices[numVertices++] = -oy; - - this.vertices[numVertices++] = x; - this.vertices[numVertices++] = y; - this.vertices[numVertices++] = ox; - this.vertices[numVertices++] = oy; - - this.vertices[numVertices++] = x; - this.vertices[numVertices++] = y; - this.vertices[numVertices++] = -ox; - this.vertices[numVertices++] = oy; - - this.indices[numIndices++] = n; - this.indices[numIndices++] = n + 1; - this.indices[numIndices++] = n + 2; - this.indices[numIndices++] = n; - this.indices[numIndices++] = n + 2; - this.indices[numIndices++] = n + 3; - } - - if (close) { - // FIXME - goog.asserts.fail(); - } - return numVertices; -}; - - /** * @param {ol.webgl.Context} context Context. */ @@ -120,30 +66,43 @@ ol.render.webgl.Replay.prototype.finish = goog.nullFunction; * @param {ol.webgl.Context} context Context. * @param {number} positionAttribLocation Attribute location for positions. * @param {number} offsetsAttribLocation Attribute location for offsets. - * @param {WebGLUniformLocation} projectionMatrixLocation Projection - * matrix location. + * @param {number} texCoordAttribLocation Attribute location for texCoord. + * @param {WebGLUniformLocation} projectionMatrixLocation Proj matrix location. + * @param {WebGLUniformLocation} sizeMatrixLocation Size matrix location. * @param {number} pixelRatio Pixel ratio. + * @param {Array.} size Size. * @param {goog.vec.Mat4.Number} transform Transform. * @param {Object} skippedFeaturesHash Ids of features to skip. * @return {T|undefined} Callback result. * @template T */ -ol.render.webgl.Replay.prototype.replay = - function(context, positionAttribLocation, offsetsAttribLocation, - projectionMatrixLocation, pixelRatio, transform, - skippedFeaturesHash) { +ol.render.webgl.Replay.prototype.replay = function(context, + positionAttribLocation, offsetsAttribLocation, texCoordAttribLocation, + projectionMatrixLocation, sizeMatrixLocation, + pixelRatio, size, transform, skippedFeaturesHash) { var gl = context.getGL(); gl.bindBuffer(goog.webgl.ARRAY_BUFFER, this.verticesBuffer); + gl.enableVertexAttribArray(positionAttribLocation); gl.vertexAttribPointer(positionAttribLocation, 2, goog.webgl.FLOAT, - false, 16, 0); + false, 24, 0); + gl.enableVertexAttribArray(offsetsAttribLocation); gl.vertexAttribPointer(offsetsAttribLocation, 2, goog.webgl.FLOAT, - false, 16, 8); + false, 24, 8); + + gl.enableVertexAttribArray(texCoordAttribLocation); + gl.vertexAttribPointer(texCoordAttribLocation, 2, goog.webgl.FLOAT, + false, 24, 16); + + gl.bindTexture(goog.webgl.TEXTURE_2D, this.texture); + + gl.uniformMatrix4fv(projectionMatrixLocation, false, transform); + gl.uniformMatrix2fv(sizeMatrixLocation, false, + new Float32Array([1 / size[0], 0.0, 0.0, 1 / size[1]])); gl.bindBuffer(goog.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer); - gl.uniformMatrix4fv(projectionMatrixLocation, false, transform); gl.drawElements(goog.webgl.TRIANGLES, this.indices.length, goog.webgl.UNSIGNED_SHORT, 0); }; @@ -248,6 +207,24 @@ ol.render.webgl.ImageReplay = function(tolerance) { goog.base(this, tolerance); + /** + * @private + * @type {number|undefined} + */ + this.height_ = undefined; + + /** + * @private + * @type {HTMLCanvasElement|HTMLVideoElement|Image} + */ + this.image_ = null; + + /** + * @private + * @type {number|undefined} + */ + this.width_ = undefined; + }; goog.inherits(ol.render.webgl.ImageReplay, ol.render.webgl.Replay); @@ -257,13 +234,63 @@ goog.inherits(ol.render.webgl.ImageReplay, ol.render.webgl.Replay); * @param {number} offset Offset. * @param {number} end End. * @param {number} stride Stride. - * @private * @return {number} My end. + * @private */ ol.render.webgl.ImageReplay.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) { - return this.appendFlatCoordinates( - flatCoordinates, offset, end, stride, false); + goog.asserts.assert(goog.isDef(this.width_)); + goog.asserts.assert(goog.isDef(this.height_)); + var numIndices = this.indices.length; + var numVertices = this.vertices.length; + var i, x, y, n; + var ox = this.width_; + var oy = this.height_; + for (i = offset; i < end; i += stride) { + x = flatCoordinates[i]; + y = flatCoordinates[i + 1]; + + n = numVertices / 6; + + // create 4 vertices per coordinate + + this.vertices[numVertices++] = x; + this.vertices[numVertices++] = y; + this.vertices[numVertices++] = -ox; + this.vertices[numVertices++] = -oy; + this.vertices[numVertices++] = 1; + this.vertices[numVertices++] = 1; + + this.vertices[numVertices++] = x; + this.vertices[numVertices++] = y; + this.vertices[numVertices++] = ox; + this.vertices[numVertices++] = -oy; + this.vertices[numVertices++] = 0; + this.vertices[numVertices++] = 1; + + this.vertices[numVertices++] = x; + this.vertices[numVertices++] = y; + this.vertices[numVertices++] = ox; + this.vertices[numVertices++] = oy; + this.vertices[numVertices++] = 0; + this.vertices[numVertices++] = 0; + + this.vertices[numVertices++] = x; + this.vertices[numVertices++] = y; + this.vertices[numVertices++] = -ox; + this.vertices[numVertices++] = oy; + this.vertices[numVertices++] = 1; + this.vertices[numVertices++] = 0; + + this.indices[numIndices++] = n; + this.indices[numIndices++] = n + 1; + this.indices[numIndices++] = n + 2; + this.indices[numIndices++] = n; + this.indices[numIndices++] = n + 2; + this.indices[numIndices++] = n + 3; + } + + return numVertices; }; @@ -306,6 +333,23 @@ ol.render.webgl.ImageReplay.prototype.finish = function(context) { gl.bindBuffer(goog.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer); gl.bufferData(goog.webgl.ELEMENT_ARRAY_BUFFER, new Uint16Array(this.indices), goog.webgl.STATIC_DRAW); + + this.texture = gl.createTexture(); + gl.bindTexture(goog.webgl.TEXTURE_2D, this.texture); + gl.texParameteri(goog.webgl.TEXTURE_2D, + goog.webgl.TEXTURE_WRAP_S, goog.webgl.CLAMP_TO_EDGE); + gl.texParameteri(goog.webgl.TEXTURE_2D, + goog.webgl.TEXTURE_WRAP_T, goog.webgl.CLAMP_TO_EDGE); + gl.texParameteri(goog.webgl.TEXTURE_2D, + goog.webgl.TEXTURE_MIN_FILTER, goog.webgl.NEAREST); + gl.texParameteri(goog.webgl.TEXTURE_2D, + goog.webgl.TEXTURE_MAG_FILTER, goog.webgl.NEAREST); + gl.texImage2D(goog.webgl.TEXTURE_2D, 0, goog.webgl.RGBA, goog.webgl.RGBA, + goog.webgl.UNSIGNED_BYTE, this.image_); + + this.image_ = null; + this.width_ = undefined; + this.height_ = undefined; }; @@ -321,6 +365,15 @@ ol.render.webgl.Replay.prototype.getExtent = function() { * @inheritDoc */ ol.render.webgl.ImageReplay.prototype.setImageStyle = function(imageStyle) { + if (goog.isNull(this.image_)) { + var image = imageStyle.getImage(1); + goog.asserts.assert(!goog.isNull(image)); + var size = imageStyle.getSize(); + goog.asserts.assert(!goog.isNull(size)); + this.image_ = image; + this.width_ = size[0]; + this.height_ = size[1]; + } }; @@ -387,28 +440,30 @@ ol.render.webgl.ReplayGroup.prototype.isEmpty = function() { * @param {ol.webgl.Context} context Context. * @param {number} positionAttribLocation Attribute location for positions. * @param {number} offsetsAttribLocation Attribute location for offsets. - * @param {WebGLUniformLocation} projectionMatrixLocation Projection - * matrix location. + * @param {number} texCoordAttribLocation Attribute location for texCoord. + * @param {WebGLUniformLocation} projectionMatrixLocation Proj matrix location. + * @param {WebGLUniformLocation} sizeMatrixLocation Size matrix location. * @param {ol.Extent} extent Extent. * @param {number} pixelRatio Pixel ratio. + * @param {Array.} size Size. * @param {goog.vec.Mat4.Number} transform Transform. * @param {Object} skippedFeaturesHash Ids of features to skip. * @return {T|undefined} Callback result. * @template T */ -ol.render.webgl.ReplayGroup.prototype.replay = function( - context, positionAttribLocation, offsetsAttribLocation, - projectionMatrixLocation, extent, pixelRatio, transform, - skippedFeaturesHash) { +ol.render.webgl.ReplayGroup.prototype.replay = function(context, + positionAttribLocation, offsetsAttribLocation, texCoordAttribLocation, + projectionMatrixLocation, sizeMatrixLocation, + extent, pixelRatio, size, transform, skippedFeaturesHash) { var i, ii, replay, result; for (i = 0, ii = ol.render.REPLAY_ORDER.length; i < ii; ++i) { replay = this.replays_[ol.render.REPLAY_ORDER[i]]; if (goog.isDef(replay) && ol.extent.intersects(extent, replay.getExtent())) { - result = replay.replay( - context, positionAttribLocation, offsetsAttribLocation, - projectionMatrixLocation, pixelRatio, transform, - skippedFeaturesHash); + result = replay.replay(context, + positionAttribLocation, offsetsAttribLocation, texCoordAttribLocation, + projectionMatrixLocation, sizeMatrixLocation, + pixelRatio, size, transform, skippedFeaturesHash); if (result) { return result; } diff --git a/src/ol/renderer/webgl/webglvectorlayer.glsl b/src/ol/renderer/webgl/webglvectorlayer.glsl index 1154bf2fb3..53e57efbda 100644 --- a/src/ol/renderer/webgl/webglvectorlayer.glsl +++ b/src/ol/renderer/webgl/webglvectorlayer.glsl @@ -3,20 +3,26 @@ //! COMMON +varying vec2 v_texCoord; //! VERTEX attribute vec2 a_position; +attribute vec2 a_texCoord; attribute vec2 a_offsets; uniform mat4 u_projectionMatrix; +uniform mat2 u_sizeMatrix; void main(void) { - gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.) + vec4(a_offsets, 0., 0.); + vec2 offsets = u_sizeMatrix * a_offsets; + gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.) + vec4(offsets, 0., 0.); + v_texCoord = a_texCoord; } //! FRAGMENT +uniform sampler2D u_image; void main(void) { - gl_FragColor = vec4(1.0, 1.0, 0.0, 1); + gl_FragColor = texture2D(u_image, v_texCoord); } diff --git a/src/ol/renderer/webgl/webglvectorlayerrenderer.js b/src/ol/renderer/webgl/webglvectorlayerrenderer.js index a85b6d1efc..cb67b0174b 100644 --- a/src/ol/renderer/webgl/webglvectorlayerrenderer.js +++ b/src/ol/renderer/webgl/webglvectorlayerrenderer.js @@ -115,8 +115,10 @@ ol.renderer.webgl.VectorLayer.prototype.composeFrame = replayGroup.replay(context, this.locations_.a_position, this.locations_.a_offsets, + this.locations_.a_texCoord, this.locations_.u_projectionMatrix, - frameState.extent, frameState.pixelRatio, + this.locations_.u_sizeMatrix, + frameState.extent, frameState.pixelRatio, frameState.size, this.projectionMatrix, frameState.skippedFeatureUids); } diff --git a/src/ol/renderer/webgl/webglvectorlayershader.js b/src/ol/renderer/webgl/webglvectorlayershader.js index 4559a8a4fe..f3226c8963 100644 --- a/src/ol/renderer/webgl/webglvectorlayershader.js +++ b/src/ol/renderer/webgl/webglvectorlayershader.js @@ -21,14 +21,14 @@ goog.addSingletonGetter(ol.renderer.webgl.vectorlayer.shader.Fragment); * @const * @type {string} */ -ol.renderer.webgl.vectorlayer.shader.Fragment.DEBUG_SOURCE = 'precision mediump float;\n\n\nvoid main(void) {\n gl_FragColor = vec4(1.0, 1.0, 0.0, 1);\n}\n'; +ol.renderer.webgl.vectorlayer.shader.Fragment.DEBUG_SOURCE = 'precision mediump float;\nvarying vec2 v_texCoord;\n\nuniform sampler2D u_image;\n\nvoid main(void) {\n gl_FragColor = texture2D(u_image, v_texCoord);\n}\n'; /** * @const * @type {string} */ -ol.renderer.webgl.vectorlayer.shader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;void main(void){gl_FragColor=vec4(1.0,1.0,0.0,1);}'; +ol.renderer.webgl.vectorlayer.shader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;uniform sampler2D g;void main(void){gl_FragColor=texture2D(g,a);}'; /** @@ -57,14 +57,14 @@ goog.addSingletonGetter(ol.renderer.webgl.vectorlayer.shader.Vertex); * @const * @type {string} */ -ol.renderer.webgl.vectorlayer.shader.Vertex.DEBUG_SOURCE = '\nattribute vec2 a_position;\nattribute vec2 a_offsets;\n\nuniform mat4 u_projectionMatrix;\n\nvoid main(void) {\n gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.) + vec4(a_offsets, 0., 0.);\n}\n\n\n'; +ol.renderer.webgl.vectorlayer.shader.Vertex.DEBUG_SOURCE = 'varying vec2 v_texCoord;\n\nattribute vec2 a_position;\nattribute vec2 a_texCoord;\nattribute vec2 a_offsets;\n\nuniform mat4 u_projectionMatrix;\nuniform mat2 u_sizeMatrix;\n\nvoid main(void) {\n vec2 offsets = u_sizeMatrix * a_offsets;\n gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.) + vec4(offsets, 0., 0.);\n v_texCoord = a_texCoord;\n}\n\n\n'; /** * @const * @type {string} */ -ol.renderer.webgl.vectorlayer.shader.Vertex.OPTIMIZED_SOURCE = 'attribute vec2 a;attribute vec2 b;uniform mat4 c;void main(void){gl_Position=c*vec4(a,0.,1.)+vec4(b,0.,0.);}'; +ol.renderer.webgl.vectorlayer.shader.Vertex.OPTIMIZED_SOURCE = 'varying vec2 a;attribute vec2 b;attribute vec2 c;attribute vec2 d;uniform mat4 e;uniform mat2 f;void main(void){vec2 offsets=f*d;gl_Position=e*vec4(b,0.,1.)+vec4(offsets,0.,0.);a=c;}'; /** @@ -85,21 +85,39 @@ ol.renderer.webgl.vectorlayer.shader.Vertex.SOURCE = goog.DEBUG ? */ ol.renderer.webgl.vectorlayer.shader.Locations = function(gl, program) { + /** + * @type {WebGLUniformLocation} + */ + this.u_image = gl.getUniformLocation( + program, goog.DEBUG ? 'u_image' : 'g'); + /** * @type {WebGLUniformLocation} */ this.u_projectionMatrix = gl.getUniformLocation( - program, goog.DEBUG ? 'u_projectionMatrix' : 'c'); + program, goog.DEBUG ? 'u_projectionMatrix' : 'e'); + + /** + * @type {WebGLUniformLocation} + */ + this.u_sizeMatrix = gl.getUniformLocation( + program, goog.DEBUG ? 'u_sizeMatrix' : 'f'); /** * @type {number} */ this.a_offsets = gl.getAttribLocation( - program, goog.DEBUG ? 'a_offsets' : 'b'); + program, goog.DEBUG ? 'a_offsets' : 'd'); /** * @type {number} */ this.a_position = gl.getAttribLocation( - program, goog.DEBUG ? 'a_position' : 'a'); + program, goog.DEBUG ? 'a_position' : 'b'); + + /** + * @type {number} + */ + this.a_texCoord = gl.getAttribLocation( + program, goog.DEBUG ? 'a_texCoord' : 'c'); };