diff --git a/src/ol/base/createmap.js b/src/ol/base/createmap.js index e0d90a3c66..ae2cbdc7f7 100644 --- a/src/ol/base/createmap.js +++ b/src/ol/base/createmap.js @@ -7,7 +7,7 @@ goog.require('ol.Map'); goog.require('ol.MapProperty'); goog.require('ol.Projection'); goog.require('ol.dom'); -goog.require('ol.dom.Map'); +goog.require('ol.dom.MapRenderer'); goog.require('ol.interaction.AltDragRotate'); goog.require('ol.interaction.CenterConstraint'); goog.require('ol.interaction.Constraints'); @@ -20,7 +20,7 @@ goog.require('ol.interaction.ResolutionConstraint'); goog.require('ol.interaction.RotationConstraint'); goog.require('ol.interaction.ShiftDragZoom'); goog.require('ol.webgl'); -goog.require('ol.webgl.Map'); +goog.require('ol.webgl.MapRenderer'); /** @@ -128,20 +128,26 @@ ol.createMap = function(target, opt_values, opt_rendererHints) { rendererHints = ol.DEFAULT_RENDERER_HINT; } - var i, rendererHint; + var i, rendererHint, rendererConstructor; for (i = 0; i < rendererHints.length; ++i) { rendererHint = rendererHints[i]; if (rendererHint == ol.RendererHint.DOM) { if (ol.ENABLE_DOM && ol.dom.isSupported()) { - return new ol.dom.Map(target, values); + rendererConstructor = ol.dom.MapRenderer; + break; } } else if (rendererHint == ol.RendererHint.WEBGL) { if (ol.ENABLE_WEBGL && ol.webgl.isSupported()) { - return new ol.webgl.Map(target, values); + rendererConstructor = ol.webgl.MapRenderer; + break; } } } - return null; + if (goog.isDef(rendererConstructor)) { + return new ol.Map(target, rendererConstructor, values); + } else { + return null; + } }; diff --git a/src/ol/base/layerrenderer.js b/src/ol/base/layerrenderer.js index f6c94f6abf..cc4074761a 100644 --- a/src/ol/base/layerrenderer.js +++ b/src/ol/base/layerrenderer.js @@ -11,18 +11,18 @@ goog.require('ol.Object'); /** * @constructor * @extends {ol.Object} - * @param {ol.Map} map Map. + * @param {ol.MapRenderer} mapRenderer Map renderer. * @param {ol.Layer} layer Layer. */ -ol.LayerRenderer = function(map, layer) { +ol.LayerRenderer = function(mapRenderer, layer) { goog.base(this); /** * @private - * @type {ol.Map} + * @type {ol.MapRenderer} */ - this.map_ = map; + this.mapRenderer_ = mapRenderer; /** * @private @@ -69,11 +69,19 @@ ol.LayerRenderer.prototype.getLayer = function() { }; +/** + * @return {ol.MapRenderer} Map renderer. + */ +ol.LayerRenderer.prototype.getMapRenderer = function() { + return this.mapRenderer_; +}; + + /** * @return {ol.Map} Map. */ ol.LayerRenderer.prototype.getMap = function() { - return this.map_; + return this.mapRenderer_.getMap(); }; diff --git a/src/ol/base/map.js b/src/ol/base/map.js index 2e433e45fe..26e1febc0e 100644 --- a/src/ol/base/map.js +++ b/src/ol/base/map.js @@ -2,7 +2,6 @@ // FIXME recheck layer/map projection compatability when projection changes // FIXME layer renderers should skip when they can't reproject // FIXME add tilt and height? -// FIXME split out renderer // FIXME add postrender event goog.provide('ol.Map'); @@ -27,7 +26,6 @@ goog.require('goog.fx.Dragger'); goog.require('goog.fx.anim'); goog.require('goog.fx.anim.Animated'); goog.require('goog.object'); -goog.require('goog.vec.Mat4'); goog.require('ol.Collection'); goog.require('ol.Color'); goog.require('ol.Coordinate'); @@ -71,11 +69,14 @@ ol.MapPaneZIndex = { * @constructor * @extends {ol.Object} * @param {Element} target Target. + * @param {function(new: ol.MapRenderer, Element, ol.Map)} rendererConstructor + * Renderer constructor. * @param {Object=} opt_values Values. * @param {goog.dom.ViewportSizeMonitor=} opt_viewportSizeMonitor * Viewport size monitor. */ -ol.Map = function(target, opt_values, opt_viewportSizeMonitor) { +ol.Map = function( + target, rendererConstructor, opt_values, opt_viewportSizeMonitor) { goog.base(this); @@ -93,21 +94,21 @@ ol.Map = function(target, opt_values, opt_viewportSizeMonitor) { /** * @private - * @type {goog.vec.Mat4.Number} + * @type {boolean} */ - this.coordinateToPixelMatrix_ = goog.vec.Mat4.createNumber(); - - /** - * @private - * @type {goog.vec.Mat4.Number} - */ - this.pixelToCoordinateMatrix_ = goog.vec.Mat4.createNumber(); + this.animating_ = false; /** * @private * @type {boolean} */ - this.matriciesDirty_ = true; + this.dirty_ = false; + + /** + * @private + * @type {number} + */ + this.freezeRenderingCount_ = 0; /** * @private @@ -148,22 +149,17 @@ ol.Map = function(target, opt_values, opt_viewportSizeMonitor) { this.registerDisposable(dragger); /** + * @type {ol.MapRenderer} * @private - * @type {goog.fx.anim.Animated} */ - this.animation_ = new ol.MapAnimation(this); + this.renderer_ = new rendererConstructor(target, this); + this.registerDisposable(this.renderer_); /** * @private - * @type {boolean} + * @type {ol.MapAnimation} */ - this.animating_ = false; - - /** - * @private - * @type {number} - */ - this.freezeRenderingCount_ = 0; + this.animation_ = new ol.MapAnimation(this.renderer_); /** * @private @@ -171,18 +167,6 @@ ol.Map = function(target, opt_values, opt_viewportSizeMonitor) { */ this.target_ = target; - /** - * @private - * @type {Array.} - */ - this.layersListenerKeys_ = null; - - /** - * @protected - * @type {Object.} - */ - this.layerRenderers = {}; - /** * @private * @type {goog.dom.ViewportSizeMonitor} @@ -193,34 +177,10 @@ ol.Map = function(target, opt_values, opt_viewportSizeMonitor) { goog.events.listen(this.viewportSizeMonitor_, goog.events.EventType.RESIZE, this.handleViewportResize, false, this); - goog.events.listen(this, - ol.Object.getChangedEventType(ol.MapProperty.BACKGROUND_COLOR), - this.handleBackgroundColorChanged, false, this); - - goog.events.listen( - this, ol.Object.getChangedEventType(ol.MapProperty.CENTER), - this.handleCenterChanged, false, this); - - goog.events.listen( - this, ol.Object.getChangedEventType(ol.MapProperty.LAYERS), - this.handleLayersChanged, false, this); - goog.events.listen( this, ol.Object.getChangedEventType(ol.MapProperty.PROJECTION), this.handleProjectionChanged, false, this); - goog.events.listen( - this, ol.Object.getChangedEventType(ol.MapProperty.RESOLUTION), - this.handleResolutionChanged, false, this); - - goog.events.listen( - this, ol.Object.getChangedEventType(ol.MapProperty.ROTATION), - this.handleRotationChanged, false, this); - - goog.events.listen( - this, ol.Object.getChangedEventType(ol.MapProperty.SIZE), - this.handleSizeChanged, false, this); - goog.events.listen( this, ol.Object.getChangedEventType(ol.MapProperty.USER_PROJECTION), this.handleUserProjectionChanged, false, this); @@ -229,20 +189,12 @@ ol.Map = function(target, opt_values, opt_viewportSizeMonitor) { this.setValues(opt_values); } + this.handleViewportResize(); + }; goog.inherits(ol.Map, ol.Object); -/** - * @param {ol.Layer} layer Layer. - * @protected - */ -ol.Map.prototype.addLayer = function(layer) { - var layerRenderer = this.createLayerRenderer(layer); - this.setLayerRenderer(layer, layerRenderer); -}; - - /** * @private */ @@ -256,25 +208,8 @@ ol.Map.prototype.animate_ = function() { /** * @return {boolean} Can rotate. */ -ol.Map.prototype.canRotate = goog.functions.FALSE; - - -/** - * @param {ol.Layer} layer Layer. - * @protected - * @return {ol.LayerRenderer} layerRenderer Layer renderer. - */ -ol.Map.prototype.createLayerRenderer = goog.abstractMethod; - - -/** - * @inheritDoc - */ -ol.Map.prototype.disposeInternal = function() { - goog.object.forEach(this.layerRenderers, function(layerRenderer) { - goog.dispose(layerRenderer); - }); - goog.base(this, 'disposeInternal'); +ol.Map.prototype.canRotate = function() { + return this.renderer_.canRotate(); }; @@ -300,22 +235,6 @@ ol.Map.prototype.fitUserExtent = function(userExtent) { }; -/** - * @param {function(this: T, ol.Layer, ol.LayerRenderer, number)} f Function. - * @param {T=} opt_obj Object. - * @template T - */ -ol.Map.prototype.forEachReadyVisibleLayer = function(f, opt_obj) { - var layers = this.getLayers(); - layers.forEach(function(layer, index) { - if (layer.isReady() && layer.getVisible()) { - var layerRenderer = this.getLayerRenderer(layer); - f.call(opt_obj, layer, layerRenderer, index); - } - }, this); -}; - - /** */ ol.Map.prototype.freezeRendering = function() { @@ -354,10 +273,7 @@ goog.exportProperty( */ ol.Map.prototype.getCoordinateFromPixel = function(pixel) { if (this.isDef()) { - this.updateMatrices_(); - var vec3 = [pixel.x, pixel.y, 0]; - goog.vec.Mat4.multVec3(this.pixelToCoordinateMatrix_, vec3, vec3); - return new ol.Coordinate(vec3[0], vec3[1]); + return this.renderer_.getCoordinateFromPixel(pixel); } else { return undefined; } @@ -395,19 +311,6 @@ goog.exportProperty( ol.Map.prototype.getInteractions); -/** - * @param {ol.Layer} layer Layer. - * @protected - * @return {ol.LayerRenderer} Layer renderer. - */ -ol.Map.prototype.getLayerRenderer = function(layer) { - var key = goog.getUid(layer); - var layerRenderer = this.layerRenderers[key]; - goog.asserts.assert(goog.isDef(layerRenderer)); - return layerRenderer; -}; - - /** * @return {ol.Collection} Layers. */ @@ -422,10 +325,7 @@ ol.Map.prototype.getLayers = function() { */ ol.Map.prototype.getPixelFromCoordinate = function(coordinate) { if (this.isDef()) { - this.updateMatrices_(); - var vec3 = [coordinate.x, coordinate.y, 0]; - goog.vec.Mat4.multVec3(this.coordinateToPixelMatrix_, vec3, vec3); - return new ol.Pixel(vec3[0], vec3[1]); + return this.renderer_.getPixelFromCoordinate(coordinate); } else { return undefined; } @@ -568,11 +468,6 @@ goog.exportProperty( ol.Map.prototype.getUserProjection); -/** - */ -ol.Map.prototype.handleBackgroundColorChanged = goog.nullFunction; - - /** * @param {goog.events.BrowserEvent} browserEvent Browser event. * @param {string=} opt_type Type. @@ -590,14 +485,6 @@ ol.Map.prototype.handleBrowserEvent = function(browserEvent, opt_type) { }; -/** - * @protected - */ -ol.Map.prototype.handleCenterChanged = function() { - this.matriciesDirty_ = true; -}; - - /** * @param {goog.fx.DragEvent} dragEvent Drag event. */ @@ -607,52 +494,6 @@ ol.Map.prototype.handleDraggerEvent = function(dragEvent) { }; -/** - * @param {ol.CollectionEvent} collectionEvent Collection event. - * @protected - */ -ol.Map.prototype.handleLayersAdd = function(collectionEvent) { - var layer = /** @type {ol.Layer} */ collectionEvent.elem; - this.addLayer(layer); -}; - - -/** - * @protected - */ -ol.Map.prototype.handleLayersChanged = function() { - var layerRenderers = goog.object.getValues(this.layerRenderers); - goog.array.forEach(layerRenderers, function(layerRenderer) { - this.removeLayerRenderer(layerRenderer); - }, this); - this.layerRenderers = {}; - if (!goog.isNull(this.layersListenerKeys_)) { - goog.array.forEach(this.layersListenerKeys_, goog.events.unlistenByKey); - this.layersListenerKeys_ = null; - } - var layers = this.getLayers(); - if (goog.isDefAndNotNull(layers)) { - layers.forEach(this.addLayer, this); - this.layersListenerKeys_ = [ - goog.events.listen(layers, ol.CollectionEventType.ADD, - this.handleLayersAdd, false, this), - goog.events.listen(layers, ol.CollectionEventType.REMOVE, - this.handleLayersRemove, false, this) - ]; - } -}; - - -/** - * @param {ol.CollectionEvent} collectionEvent Collection event. - * @protected - */ -ol.Map.prototype.handleLayersRemove = function(collectionEvent) { - var layer = /** @type {ol.Layer} */ collectionEvent.elem; - this.removeLayer(layer); -}; - - /** * @protected */ @@ -661,30 +502,6 @@ ol.Map.prototype.handleProjectionChanged = function() { }; -/** - * @protected - */ -ol.Map.prototype.handleResolutionChanged = function() { - this.matriciesDirty_ = true; -}; - - -/** - * @protected - */ -ol.Map.prototype.handleRotationChanged = function() { - this.matriciesDirty_ = true; -}; - - -/** - * @protected - */ -ol.Map.prototype.handleSizeChanged = function() { - this.matriciesDirty_ = true; -}; - - /** * @protected */ @@ -731,38 +548,12 @@ ol.Map.prototype.recalculateTransforms_ = function() { }; -/** - * @param {ol.Layer} layer Layer. - * @protected - */ -ol.Map.prototype.removeLayer = function(layer) { - goog.dispose(this.removeLayerRenderer(layer)); -}; - - -/** - * @param {ol.Layer} layer Layer. - * @return {ol.LayerRenderer} Layer renderer. - * @protected - */ -ol.Map.prototype.removeLayerRenderer = function(layer) { - var key = goog.getUid(layer); - if (key in this.layerRenderers) { - var layerRenderer = this.layerRenderers[key]; - delete this.layerRenderers[key]; - return layerRenderer; - } else { - return null; - } -}; - - /** */ ol.Map.prototype.render = function() { if (!this.animating_) { if (this.freezeRenderingCount_ === 0) { - if (this.renderInternal()) { + if (this.renderer_.render()) { this.animate_(); } } else { @@ -772,22 +563,6 @@ ol.Map.prototype.render = function() { }; -/** - * @protected - * @return {boolean} Animating. - */ -ol.Map.prototype.renderInternal = function() { - this.dirty_ = false; - var animate = false; - this.forEachReadyVisibleLayer(function(layer, layerRenderer) { - if (layerRenderer.render()) { - animate = true; - } - }); - return animate; -}; - - /** * @param {ol.Color} backgroundColor Background color. */ @@ -824,18 +599,6 @@ goog.exportProperty( ol.Map.prototype.setInteractions); -/** - * @param {ol.Layer} layer Layer. - * @param {ol.LayerRenderer} layerRenderer Layer renderer. - * @protected - */ -ol.Map.prototype.setLayerRenderer = function(layer, layerRenderer) { - var key = goog.getUid(layer); - goog.asserts.assert(!(key in this.layerRenderers)); - this.layerRenderers[key] = layerRenderer; -}; - - /** * @export * @param {ol.Collection} layers Layers. @@ -935,7 +698,7 @@ ol.Map.prototype.unfreezeRendering = function() { goog.asserts.assert(this.freezeRenderingCount_ > 0); if (--this.freezeRenderingCount_ === 0) { if (!this.animating_ && this.dirty_) { - if (this.renderInternal()) { + if (this.renderer_.render()) { this.animate_(); } } @@ -943,50 +706,6 @@ ol.Map.prototype.unfreezeRendering = function() { }; -/** - * @private - */ -ol.Map.prototype.updateMatrices_ = function() { - - if (this.matriciesDirty_) { - - var center = /** @type {!ol.Coordinate} */ this.getCenter(); - var resolution = /** @type {number} */ this.getResolution(); - var rotation = this.getRotation(); - var size = /** @type {!ol.Size} */ this.getSize(); - - goog.vec.Mat4.makeIdentity(this.coordinateToPixelMatrix_); - goog.vec.Mat4.translate(this.coordinateToPixelMatrix_, - size.width / 2, - size.height / 2, - 0); - goog.vec.Mat4.scale(this.coordinateToPixelMatrix_, - 1 / resolution, - -1 / resolution, - 1); - if (this.canRotate() && goog.isDef(rotation)) { - goog.vec.Mat4.rotate(this.coordinateToPixelMatrix_, - -rotation, - 0, - 0, - 1); - } - goog.vec.Mat4.translate(this.coordinateToPixelMatrix_, - -center.x, - -center.y, - 0); - - var inverted = goog.vec.Mat4.invert( - this.coordinateToPixelMatrix_, this.pixelToCoordinateMatrix_); - goog.asserts.assert(inverted); - - this.matriciesDirty_ = false; - - } - -}; - - /** * @param {function(this: T)} f Function. * @param {T=} opt_obj Object. @@ -1006,15 +725,15 @@ ol.Map.prototype.withFrozenRendering = function(f, opt_obj) { /** * @constructor * @implements {goog.fx.anim.Animated} - * @param {!ol.Map} map Map. + * @param {!ol.MapRenderer} renderer Map renderer. */ -ol.MapAnimation = function(map) { +ol.MapAnimation = function(renderer) { /** * @private - * @type {ol.Map} + * @type {ol.MapRenderer} */ - this.map_ = map; + this.renderer_ = renderer; }; @@ -1023,7 +742,7 @@ ol.MapAnimation = function(map) { * @inheritDoc */ ol.MapAnimation.prototype.onAnimationFrame = function() { - if (!this.map_.renderInternal()) { + if (!this.renderer_.render()) { goog.fx.anim.unregisterAnimation(this); } }; diff --git a/src/ol/base/maprenderer.js b/src/ol/base/maprenderer.js new file mode 100644 index 0000000000..e9db1b7a3e --- /dev/null +++ b/src/ol/base/maprenderer.js @@ -0,0 +1,376 @@ +goog.provide('ol.MapRenderer'); + +goog.require('goog.Disposable'); +goog.require('goog.events'); +goog.require('goog.fx.anim'); +goog.require('goog.fx.anim.Animated'); +goog.require('goog.vec.Mat4'); +goog.require('ol.Map'); +goog.require('ol.MapProperty'); + + + +/** + * @constructor + * @extends {goog.Disposable} + * @param {Element} target Target. + * @param {ol.Map} map Map. + */ +ol.MapRenderer = function(target, map) { + + goog.base(this); + + /** + * @private + * @type {Element} + */ + this.target_ = target; + + /** + * @protected + * @type {ol.Map} + */ + this.map = map; + + /** + * @protected + * @type {Object.} + */ + this.layerRenderers = {}; + + /** + * @private + * @type {Array.} + */ + this.layersListenerKeys_ = null; + + /** + * @private + * @type {goog.vec.Mat4.Number} + */ + this.coordinateToPixelMatrix_ = goog.vec.Mat4.createNumber(); + + /** + * @private + * @type {goog.vec.Mat4.Number} + */ + this.pixelToCoordinateMatrix_ = goog.vec.Mat4.createNumber(); + + /** + * @private + * @type {boolean} + */ + this.matricesDirty_ = true; + + /** + * @private + * @type {Array.} + */ + this.mapListenerKeys_ = [ + goog.events.listen( + map, ol.Object.getChangedEventType(ol.MapProperty.BACKGROUND_COLOR), + this.handleBackgroundColorChanged, false, this), + + goog.events.listen( + map, ol.Object.getChangedEventType(ol.MapProperty.CENTER), + this.handleCenterChanged, false, this), + + goog.events.listen( + map, ol.Object.getChangedEventType(ol.MapProperty.LAYERS), + this.handleLayersChanged, false, this), + + goog.events.listen( + map, ol.Object.getChangedEventType(ol.MapProperty.RESOLUTION), + this.handleResolutionChanged, false, this), + + goog.events.listen( + map, ol.Object.getChangedEventType(ol.MapProperty.ROTATION), + this.handleRotationChanged, false, this), + + goog.events.listen( + map, ol.Object.getChangedEventType(ol.MapProperty.SIZE), + this.handleSizeChanged, false, this) + ]; + +}; +goog.inherits(ol.MapRenderer, goog.Disposable); + + +/** + * @inheritDoc + */ +ol.MapRenderer.prototype.disposeInternal = function() { + goog.object.forEach(this.layerRenderers, function(layerRenderer) { + goog.dispose(layerRenderer); + }); + goog.array.forEach(this.mapListenerKeys_, goog.events.unlistenByKey); + if (!goog.isNull(this.layersListenerKeys_)) { + goog.array.forEach(this.layersListenerKeys_, goog.events.unlistenByKey); + } + goog.base(this, 'disposeInternal'); +}; + + +/** + * @param {function(this: T, ol.Layer, ol.LayerRenderer, number)} f Function. + * @param {T=} opt_obj Object. + * @template T + */ +ol.MapRenderer.prototype.forEachReadyVisibleLayer = function(f, opt_obj) { + var layers = this.map.getLayers(); + layers.forEach(function(layer, index) { + if (layer.isReady() && layer.getVisible()) { + var layerRenderer = this.getLayerRenderer(layer); + f.call(opt_obj, layer, layerRenderer, index); + } + }, this); +}; + + +/** + * @return {ol.Map} Map. + */ +ol.MapRenderer.prototype.getMap = function() { + return this.map; +}; + + +/** + * @param {ol.Layer} layer Layer. + * @protected + * @return {ol.LayerRenderer} Layer renderer. + */ +ol.MapRenderer.prototype.getLayerRenderer = function(layer) { + var key = goog.getUid(layer); + var layerRenderer = this.layerRenderers[key]; + goog.asserts.assert(goog.isDef(layerRenderer)); + return layerRenderer; +}; + + +/** + * @param {ol.Layer} layer Layer. + * @param {ol.LayerRenderer} layerRenderer Layer renderer. + * @protected + */ +ol.MapRenderer.prototype.setLayerRenderer = function(layer, layerRenderer) { + var key = goog.getUid(layer); + goog.asserts.assert(!(key in this.layerRenderers)); + this.layerRenderers[key] = layerRenderer; +}; + + +/** + * @return {boolean} Can rotate. + */ +ol.MapRenderer.prototype.canRotate = goog.functions.FALSE; + + +/** + */ +ol.MapRenderer.prototype.handleBackgroundColorChanged = goog.nullFunction; + + +/** + * @protected + */ +ol.MapRenderer.prototype.handleCenterChanged = function() { + this.matricesDirty_ = true; +}; + + +/** + * @protected + */ +ol.MapRenderer.prototype.handleLayersChanged = function() { + var layerRenderers = goog.object.getValues(this.layerRenderers); + goog.array.forEach(layerRenderers, function(layerRenderer) { + this.removeLayerRenderer(layerRenderer); + }, this); + this.layerRenderers = {}; + if (!goog.isNull(this.layersListenerKeys_)) { + goog.array.forEach(this.layersListenerKeys_, goog.events.unlistenByKey); + this.layersListenerKeys_ = null; + } + var layers = this.map.getLayers(); + if (goog.isDefAndNotNull(layers)) { + layers.forEach(this.addLayer, this); + this.layersListenerKeys_ = [ + goog.events.listen(layers, ol.CollectionEventType.ADD, + this.handleLayersAdd, false, this), + goog.events.listen(layers, ol.CollectionEventType.REMOVE, + this.handleLayersRemove, false, this) + ]; + } +}; + + +/** + * @param {ol.CollectionEvent} collectionEvent Collection event. + * @protected + */ +ol.MapRenderer.prototype.handleLayersAdd = function(collectionEvent) { + var layer = /** @type {ol.Layer} */ collectionEvent.elem; + this.addLayer(layer); +}; + + +/** + * @param {ol.Layer} layer Layer. + * @protected + */ +ol.MapRenderer.prototype.addLayer = function(layer) { + var layerRenderer = this.createLayerRenderer(layer); + this.setLayerRenderer(layer, layerRenderer); +}; + + +/** + * @param {ol.Layer} layer Layer. + * @protected + * @return {ol.LayerRenderer} layerRenderer Layer renderer. + */ +ol.MapRenderer.prototype.createLayerRenderer = goog.abstractMethod; + + +/** + * @param {ol.CollectionEvent} collectionEvent Collection event. + * @protected + */ +ol.MapRenderer.prototype.handleLayersRemove = function(collectionEvent) { + var layer = /** @type {ol.Layer} */ collectionEvent.elem; + this.removeLayer(layer); +}; + + +/** + * @param {ol.Layer} layer Layer. + * @protected + */ +ol.MapRenderer.prototype.removeLayer = function(layer) { + goog.dispose(this.removeLayerRenderer(layer)); +}; + + +/** + * @param {ol.Layer} layer Layer. + * @return {ol.LayerRenderer} Layer renderer. + * @protected + */ +ol.MapRenderer.prototype.removeLayerRenderer = function(layer) { + var key = goog.getUid(layer); + if (key in this.layerRenderers) { + var layerRenderer = this.layerRenderers[key]; + delete this.layerRenderers[key]; + return layerRenderer; + } else { + return null; + } +}; + + +/** + * @protected + */ +ol.MapRenderer.prototype.handleResolutionChanged = function() { + this.matricesDirty_ = true; +}; + + +/** + * @protected + */ +ol.MapRenderer.prototype.handleRotationChanged = function() { + this.matricesDirty_ = true; +}; + + +/** + * @protected + */ +ol.MapRenderer.prototype.handleSizeChanged = function() { + this.matricesDirty_ = true; +}; + + +/** + * @return {boolean} Animating. + */ +ol.MapRenderer.prototype.render = function() { + var animate = false; + this.forEachReadyVisibleLayer(function(layer, layerRenderer) { + if (layerRenderer.render()) { + animate = true; + } + }); + return animate; +}; + + +/** + * @private + */ +ol.MapRenderer.prototype.updateMatrices_ = function() { + + if (this.matricesDirty_) { + + var map = this.map; + var center = /** @type {!ol.Coordinate} */ map.getCenter(); + var resolution = /** @type {number} */ map.getResolution(); + var rotation = map.getRotation(); + var size = /** @type {!ol.Size} */ map.getSize(); + + goog.vec.Mat4.makeIdentity(this.coordinateToPixelMatrix_); + goog.vec.Mat4.translate(this.coordinateToPixelMatrix_, + size.width / 2, + size.height / 2, + 0); + goog.vec.Mat4.scale(this.coordinateToPixelMatrix_, + 1 / resolution, + -1 / resolution, + 1); + if (this.canRotate() && goog.isDef(rotation)) { + goog.vec.Mat4.rotate(this.coordinateToPixelMatrix_, + -rotation, + 0, + 0, + 1); + } + goog.vec.Mat4.translate(this.coordinateToPixelMatrix_, + -center.x, + -center.y, + 0); + + var inverted = goog.vec.Mat4.invert( + this.coordinateToPixelMatrix_, this.pixelToCoordinateMatrix_); + goog.asserts.assert(inverted); + + this.matricesDirty_ = false; + + } + +}; + + +/** + * @param {ol.Pixel} pixel Pixel. + * @return {ol.Coordinate} Coordinate. + */ +ol.MapRenderer.prototype.getCoordinateFromPixel = function(pixel) { + this.updateMatrices_(); + var vec3 = [pixel.x, pixel.y, 0]; + goog.vec.Mat4.multVec3(this.pixelToCoordinateMatrix_, vec3, vec3); + return new ol.Coordinate(vec3[0], vec3[1]); +}; + + +/** + * @param {ol.Coordinate} coordinate Coordinate. + * @return {ol.Pixel} Pixel. + */ +ol.MapRenderer.prototype.getPixelFromCoordinate = function(coordinate) { + this.updateMatrices_(); + var vec3 = [coordinate.x, coordinate.y, 0]; + goog.vec.Mat4.multVec3(this.coordinateToPixelMatrix_, vec3, vec3); + return new ol.Pixel(vec3[0], vec3[1]); +}; diff --git a/src/ol/dom/layerrenderer.js b/src/ol/dom/layerrenderer.js index 679e676868..72352f7e30 100644 --- a/src/ol/dom/layerrenderer.js +++ b/src/ol/dom/layerrenderer.js @@ -8,12 +8,12 @@ goog.require('ol.LayerRenderer'); /** * @constructor * @extends {ol.LayerRenderer} - * @param {ol.dom.Map} map Map. + * @param {ol.MapRenderer} mapRenderer Map renderer. * @param {ol.Layer} layer Layer. * @param {!Element} target Target. */ -ol.dom.LayerRenderer = function(map, layer, target) { - goog.base(this, map, layer); +ol.dom.LayerRenderer = function(mapRenderer, layer, target) { + goog.base(this, mapRenderer, layer); /** * @type {!Element} @@ -38,10 +38,10 @@ goog.inherits(ol.dom.LayerRenderer, ol.LayerRenderer); /** * @override - * @return {ol.dom.Map} Map. + * @return {ol.MapRenderer} Map renderer. */ -ol.dom.LayerRenderer.prototype.getMap = function() { - return /** @type {ol.dom.Map} */ goog.base(this, 'getMap'); +ol.dom.LayerRenderer.prototype.getMapRenderer = function() { + return /** @type {ol.dom.MapRenderer} */ goog.base(this, 'getMapRenderer'); }; diff --git a/src/ol/dom/map.js b/src/ol/dom/maprenderer.js similarity index 79% rename from src/ol/dom/map.js rename to src/ol/dom/maprenderer.js index 9949836481..cd42503188 100644 --- a/src/ol/dom/map.js +++ b/src/ol/dom/maprenderer.js @@ -1,4 +1,4 @@ -goog.provide('ol.dom.Map'); +goog.provide('ol.dom.MapRenderer'); goog.require('goog.asserts'); goog.require('goog.dom'); @@ -6,6 +6,7 @@ goog.require('goog.dom.TagName'); goog.require('goog.style'); goog.require('ol.Coordinate'); goog.require('ol.Map'); +goog.require('ol.MapRenderer'); goog.require('ol.TileLayer'); goog.require('ol.dom.TileLayerRenderer'); @@ -13,13 +14,13 @@ goog.require('ol.dom.TileLayerRenderer'); /** * @constructor - * @extends {ol.Map} + * @extends {ol.MapRenderer} * @param {Element} target Target. - * @param {Object.=} opt_values Values. + * @param {ol.Map} map Map. */ -ol.dom.Map = function(target, opt_values) { +ol.dom.MapRenderer = function(target, map) { - goog.base(this, target); + goog.base(this, target, map); /** * @type {!Element} @@ -61,27 +62,20 @@ ol.dom.Map = function(target, opt_values) { * @private */ this.layersPaneOffset_ = null; - - if (goog.isDef(opt_values)) { - this.setValues(opt_values); - } - - this.handleViewportResize(); - }; -goog.inherits(ol.dom.Map, ol.Map); +goog.inherits(ol.dom.MapRenderer, ol.MapRenderer); /** * Reset the layers pane to its initial position. * @private */ -ol.dom.Map.prototype.resetLayersPane_ = function() { +ol.dom.MapRenderer.prototype.resetLayersPane_ = function() { var offset = new ol.Coordinate(0, 0); goog.style.setPosition(this.layersPane_, offset); this.layersPaneOffset_ = offset; - this.renderedCenter_ = this.getCenter(); + this.renderedCenter_ = this.map.getCenter(); this.setOrigin_(); }; @@ -91,10 +85,10 @@ ol.dom.Map.prototype.resetLayersPane_ = function() { * Set the origin for each layer renderer. * @private */ -ol.dom.Map.prototype.setOrigin_ = function() { - var center = this.getCenter(); - var resolution = this.getResolution(); - var targetSize = this.getSize(); +ol.dom.MapRenderer.prototype.setOrigin_ = function() { + var center = this.map.getCenter(); + var resolution = this.map.getResolution(); + var targetSize = this.map.getSize(); var targetWidth = targetSize.width; var targetHeight = targetSize.height; var origin = new ol.Coordinate( @@ -110,10 +104,10 @@ ol.dom.Map.prototype.setOrigin_ = function() { * Move the layers pane. * @private */ -ol.dom.Map.prototype.shiftLayersPane_ = function() { - var center = this.getCenter(); +ol.dom.MapRenderer.prototype.shiftLayersPane_ = function() { + var center = this.map.getCenter(); var oldCenter = this.renderedCenter_; - var resolution = this.getResolution(); + var resolution = this.map.getResolution(); var dx = Math.round((oldCenter.x - center.x) / resolution); var dy = Math.round((center.y - oldCenter.y) / resolution); if (!(dx === 0 && dy === 0)) { @@ -129,7 +123,7 @@ ol.dom.Map.prototype.shiftLayersPane_ = function() { /** * @inheritDoc */ -ol.dom.Map.prototype.createLayerRenderer = function(layer) { +ol.dom.MapRenderer.prototype.createLayerRenderer = function(layer) { if (layer instanceof ol.TileLayer) { @@ -154,7 +148,7 @@ ol.dom.Map.prototype.createLayerRenderer = function(layer) { /** * @inheritDoc */ -ol.dom.Map.prototype.handleCenterChanged = function() { +ol.dom.MapRenderer.prototype.handleCenterChanged = function() { goog.base(this, 'handleCenterChanged'); // FIXME: shiftLayersPane_ and resetLayersPane_ should be called // elsewhere as we may be frozen here @@ -170,7 +164,7 @@ ol.dom.Map.prototype.handleCenterChanged = function() { /** * @inheritDoc */ -ol.dom.Map.prototype.handleResolutionChanged = function() { +ol.dom.MapRenderer.prototype.handleResolutionChanged = function() { goog.base(this, 'handleResolutionChanged'); // FIXME: resetLayersPane_ should be called // elsewhere as we may be frozen here diff --git a/src/ol/dom/tilelayerrenderer.js b/src/ol/dom/tilelayerrenderer.js index a969ff2647..d60b4bad37 100644 --- a/src/ol/dom/tilelayerrenderer.js +++ b/src/ol/dom/tilelayerrenderer.js @@ -13,12 +13,12 @@ goog.require('ol.dom.LayerRenderer'); /** * @constructor * @extends {ol.dom.LayerRenderer} - * @param {ol.dom.Map} map Map. + * @param {ol.MapRenderer} mapRenderer Map renderer. * @param {ol.TileLayer} tileLayer Tile layer. * @param {!Element} target Target. */ -ol.dom.TileLayerRenderer = function(map, tileLayer, target) { - goog.base(this, map, tileLayer, target); +ol.dom.TileLayerRenderer = function(mapRenderer, tileLayer, target) { + goog.base(this, mapRenderer, tileLayer, target); /** * @type {Object} diff --git a/src/ol/webgl/layerrenderer.js b/src/ol/webgl/layerrenderer.js index 357de29eac..59ca120d7a 100644 --- a/src/ol/webgl/layerrenderer.js +++ b/src/ol/webgl/layerrenderer.js @@ -9,11 +9,11 @@ goog.require('ol.LayerRenderer'); /** * @constructor * @extends {ol.LayerRenderer} - * @param {ol.webgl.Map} map Map. + * @param {ol.MapRenderer} mapRenderer Map renderer. * @param {ol.Layer} layer Layer. */ -ol.webgl.LayerRenderer = function(map, layer) { - goog.base(this, map, layer); +ol.webgl.LayerRenderer = function(mapRenderer, layer) { + goog.base(this, mapRenderer, layer); }; goog.inherits(ol.webgl.LayerRenderer, ol.LayerRenderer); @@ -32,21 +32,12 @@ ol.webgl.LayerRenderer.prototype.dispatchChangeEvent = function() { ol.webgl.LayerRenderer.prototype.getTexture = goog.abstractMethod; -/** - * @return {WebGLRenderingContext} GL. - */ -ol.webgl.LayerRenderer.prototype.getGL = function() { - var map = /** @type {ol.webgl.Map} */ this.getMap(); - return map.getGL(); -}; - - /** * @override - * @return {ol.webgl.Map} Map. + * @return {ol.MapRenderer} MapRenderer. */ -ol.webgl.LayerRenderer.prototype.getMap = function() { - return /** @type {ol.webgl.Map} */ goog.base(this, 'getMap'); +ol.webgl.LayerRenderer.prototype.getMapRenderer = function() { + return /** @type {ol.webgl.MapRenderer} */ goog.base(this, 'getMapRenderer'); }; diff --git a/src/ol/webgl/map.js b/src/ol/webgl/maprenderer.js similarity index 89% rename from src/ol/webgl/map.js rename to src/ol/webgl/maprenderer.js index 2a923431c0..a923626336 100644 --- a/src/ol/webgl/map.js +++ b/src/ol/webgl/maprenderer.js @@ -4,7 +4,7 @@ // FIXME defer cleanup until post-render // FIXME check against gl.getParameter(webgl.MAX_TEXTURE_SIZE) -goog.provide('ol.webgl.Map'); +goog.provide('ol.webgl.MapRenderer'); goog.provide('ol.webgl.map.shader'); goog.require('goog.debug.Logger'); @@ -134,13 +134,13 @@ goog.addSingletonGetter(ol.webgl.map.shader.Vertex); /** * @constructor - * @extends {ol.Map} + * @extends {ol.MapRenderer} * @param {Element} target Target. - * @param {Object.=} opt_values Values. + * @param {ol.Map} map Map. */ -ol.webgl.Map = function(target, opt_values) { +ol.webgl.MapRenderer = function(target, map) { - goog.base(this, target); + goog.base(this, target, map); /** * @private @@ -232,21 +232,16 @@ ol.webgl.Map = function(target, opt_values) { */ this.layerRendererChangeListenKeys_ = {}; - if (goog.isDef(opt_values)) { - this.setValues(opt_values); - } - - this.handleViewportResize(); this.handleWebGLContextRestored(); }; -goog.inherits(ol.webgl.Map, ol.Map); +goog.inherits(ol.webgl.MapRenderer, ol.MapRenderer); /** * @inheritDoc */ -ol.webgl.Map.prototype.addLayer = function(layer) { +ol.webgl.MapRenderer.prototype.addLayer = function(layer) { goog.base(this, 'addLayer', layer); if (layer.getVisible()) { this.render(); @@ -259,7 +254,7 @@ ol.webgl.Map.prototype.addLayer = function(layer) { * @param {number} magFilter Mag filter. * @param {number} minFilter Min filter. */ -ol.webgl.Map.prototype.bindImageTexture = +ol.webgl.MapRenderer.prototype.bindImageTexture = function(image, magFilter, minFilter) { var gl = this.getGL(); var imageKey = image.src; @@ -301,13 +296,13 @@ ol.webgl.Map.prototype.bindImageTexture = /** * @inheritDoc */ -ol.webgl.Map.prototype.canRotate = goog.functions.TRUE; +ol.webgl.MapRenderer.prototype.canRotate = goog.functions.TRUE; /** * @inheritDoc */ -ol.webgl.Map.prototype.createLayerRenderer = function(layer) { +ol.webgl.MapRenderer.prototype.createLayerRenderer = function(layer) { var gl = this.getGL(); if (layer instanceof ol.TileLayer) { return new ol.webgl.TileLayerRenderer(this, layer); @@ -321,7 +316,7 @@ ol.webgl.Map.prototype.createLayerRenderer = function(layer) { /** * @inheritDoc */ -ol.webgl.Map.prototype.disposeInternal = function() { +ol.webgl.MapRenderer.prototype.disposeInternal = function() { var gl = this.getGL(); if (!gl.isContextLost()) { goog.object.forEach(this.programCache_, function(program) { @@ -341,7 +336,7 @@ ol.webgl.Map.prototype.disposeInternal = function() { /** * @return {WebGLRenderingContext} GL. */ -ol.webgl.Map.prototype.getGL = function() { +ol.webgl.MapRenderer.prototype.getGL = function() { return this.gl_; }; @@ -351,7 +346,7 @@ ol.webgl.Map.prototype.getGL = function() { * @param {ol.webgl.shader.Vertex} vertexShaderObject Vertex shader. * @return {WebGLProgram} Program. */ -ol.webgl.Map.prototype.getProgram = function( +ol.webgl.MapRenderer.prototype.getProgram = function( fragmentShaderObject, vertexShaderObject) { var programKey = goog.getUid(fragmentShaderObject) + '/' + goog.getUid(vertexShaderObject); @@ -381,7 +376,7 @@ ol.webgl.Map.prototype.getProgram = function( * @param {ol.webgl.Shader} shaderObject Shader object. * @return {WebGLShader} Shader. */ -ol.webgl.Map.prototype.getShader = function(shaderObject) { +ol.webgl.MapRenderer.prototype.getShader = function(shaderObject) { var shaderKey = goog.getUid(shaderObject); if (shaderKey in this.shaderCache_) { return this.shaderCache_[shaderKey]; @@ -407,8 +402,8 @@ ol.webgl.Map.prototype.getShader = function(shaderObject) { /** * @inheritDoc */ -ol.webgl.Map.prototype.handleBackgroundColorChanged = function() { - var backgroundColor = this.getBackgroundColor(); +ol.webgl.MapRenderer.prototype.handleBackgroundColorChanged = function() { + var backgroundColor = this.getMap().getBackgroundColor(); this.clearColor_ = new ol.Color( backgroundColor.r / 255, backgroundColor.g / 255, @@ -421,7 +416,7 @@ ol.webgl.Map.prototype.handleBackgroundColorChanged = function() { /** * @inheritDoc */ -ol.webgl.Map.prototype.handleCenterChanged = function() { +ol.webgl.MapRenderer.prototype.handleCenterChanged = function() { goog.base(this, 'handleCenterChanged'); this.render(); }; @@ -431,7 +426,7 @@ ol.webgl.Map.prototype.handleCenterChanged = function() { * @param {goog.events.Event} event Event. * @protected */ -ol.webgl.Map.prototype.handleLayerRendererChange = function(event) { +ol.webgl.MapRenderer.prototype.handleLayerRendererChange = function(event) { this.render(); }; @@ -439,7 +434,7 @@ ol.webgl.Map.prototype.handleLayerRendererChange = function(event) { /** * @inheritDoc */ -ol.webgl.Map.prototype.handleResolutionChanged = function() { +ol.webgl.MapRenderer.prototype.handleResolutionChanged = function() { goog.base(this, 'handleResolutionChanged'); this.render(); }; @@ -448,7 +443,7 @@ ol.webgl.Map.prototype.handleResolutionChanged = function() { /** * @inheritDoc */ -ol.webgl.Map.prototype.handleRotationChanged = function() { +ol.webgl.MapRenderer.prototype.handleRotationChanged = function() { goog.base(this, 'handleRotationChanged'); this.render(); }; @@ -457,9 +452,9 @@ ol.webgl.Map.prototype.handleRotationChanged = function() { /** * @inheritDoc */ -ol.webgl.Map.prototype.handleSizeChanged = function() { +ol.webgl.MapRenderer.prototype.handleSizeChanged = function() { goog.base(this, 'handleSizeChanged'); - var size = this.getSize(); + var size = this.getMap().getSize(); if (!goog.isDef(size)) { return; } @@ -477,7 +472,7 @@ ol.webgl.Map.prototype.handleSizeChanged = function() { * @param {goog.events.Event} event Event. * @protected */ -ol.webgl.Map.prototype.handleWebGLContextLost = function(event) { +ol.webgl.MapRenderer.prototype.handleWebGLContextLost = function(event) { if (goog.DEBUG) { ol.webgl.map.logger.info('WebGLContextLost'); } @@ -496,7 +491,7 @@ ol.webgl.Map.prototype.handleWebGLContextLost = function(event) { /** * @protected */ -ol.webgl.Map.prototype.handleWebGLContextRestored = function() { +ol.webgl.MapRenderer.prototype.handleWebGLContextRestored = function() { if (goog.DEBUG) { ol.webgl.map.logger.info('WebGLContextRestored'); } @@ -514,7 +509,7 @@ ol.webgl.Map.prototype.handleWebGLContextRestored = function() { * @param {Image} image Image. * @return {boolean} Is image texture loaded. */ -ol.webgl.Map.prototype.isImageTextureLoaded = function(image) { +ol.webgl.MapRenderer.prototype.isImageTextureLoaded = function(image) { return image.src in this.textureCache_[image.src]; }; @@ -522,15 +517,15 @@ ol.webgl.Map.prototype.isImageTextureLoaded = function(image) { /** * @inheritDoc */ -ol.webgl.Map.prototype.renderInternal = function() { +ol.webgl.MapRenderer.prototype.render = function() { - if (!this.isDef()) { + if (!this.getMap().isDef()) { return false; } - var size = this.getSize(); + var size = this.getMap().getSize(); - var animate = goog.base(this, 'renderInternal'); + var animate = goog.base(this, 'render'); var gl = this.getGL(); @@ -600,7 +595,7 @@ ol.webgl.Map.prototype.renderInternal = function() { /** * @inheritDoc */ -ol.webgl.Map.prototype.removeLayer = function(layer) { +ol.webgl.MapRenderer.prototype.removeLayer = function(layer) { goog.base(this, 'removeLayer', layer); if (layer.getVisible()) { this.render(); @@ -611,7 +606,7 @@ ol.webgl.Map.prototype.removeLayer = function(layer) { /** * @inheritDoc */ -ol.webgl.Map.prototype.removeLayerRenderer = function(layer) { +ol.webgl.MapRenderer.prototype.removeLayerRenderer = function(layer) { var layerRenderer = goog.base(this, 'removeLayerRenderer', layer); if (!goog.isNull(layerRenderer)) { var layerKey = goog.getUid(layer); @@ -625,7 +620,8 @@ ol.webgl.Map.prototype.removeLayerRenderer = function(layer) { /** * @inheritDoc */ -ol.webgl.Map.prototype.setLayerRenderer = function(layer, layerRenderer) { +ol.webgl.MapRenderer.prototype.setLayerRenderer = function( + layer, layerRenderer) { goog.base(this, 'setLayerRenderer', layer, layerRenderer); var layerKey = goog.getUid(layer); this.layerRendererChangeListenKeys_[layerKey] = goog.events.listen( diff --git a/src/ol/webgl/tilelayerrenderer.js b/src/ol/webgl/tilelayerrenderer.js index 5aba0439fa..de57ee598b 100644 --- a/src/ol/webgl/tilelayerrenderer.js +++ b/src/ol/webgl/tilelayerrenderer.js @@ -76,12 +76,12 @@ goog.addSingletonGetter(ol.webgl.tilelayerrenderer.shader.Vertex); /** * @constructor * @extends {ol.webgl.LayerRenderer} - * @param {ol.webgl.Map} map Map. + * @param {ol.MapRenderer} mapRenderer Map renderer. * @param {ol.TileLayer} tileLayer Tile layer. */ -ol.webgl.TileLayerRenderer = function(map, tileLayer) { +ol.webgl.TileLayerRenderer = function(mapRenderer, tileLayer) { - goog.base(this, map, tileLayer); + goog.base(this, mapRenderer, tileLayer); /** * @private @@ -149,7 +149,8 @@ goog.inherits(ol.webgl.TileLayerRenderer, ol.webgl.LayerRenderer); * @protected */ ol.webgl.TileLayerRenderer.prototype.disposeInternal = function() { - var gl = this.getGL(); + var mapRenderer = this.getMapRenderer(); + var gl = mapRenderer.getGL(); if (!gl.isContextLost()) { gl.deleteBuffer(this.arrayBuffer_); gl.deleteFramebuffer(this.framebuffer_); @@ -166,7 +167,8 @@ ol.webgl.TileLayerRenderer.prototype.disposeInternal = function() { ol.webgl.TileLayerRenderer.prototype.bindFramebuffer_ = function(framebufferDimension) { - var gl = this.getGL(); + var mapRenderer = this.getMapRenderer(); + var gl = mapRenderer.getGL(); if (!goog.isDef(this.framebufferDimension_) || this.framebufferDimension_ != framebufferDimension) { @@ -249,9 +251,10 @@ ol.webgl.TileLayerRenderer.prototype.handleWebGLContextLost = function() { */ ol.webgl.TileLayerRenderer.prototype.render = function() { - var gl = this.getGL(); - + var mapRenderer = this.getMapRenderer(); var map = this.getMap(); + var gl = mapRenderer.getGL(); + goog.asserts.assert(map.isDef()); var mapCenter = map.getCenter(); var mapExtent = map.getExtent(); @@ -293,7 +296,8 @@ ol.webgl.TileLayerRenderer.prototype.render = function() { gl.clear(goog.webgl.COLOR_BUFFER_BIT); gl.disable(goog.webgl.BLEND); - var program = map.getProgram(this.fragmentShader_, this.vertexShader_); + var program = mapRenderer.getProgram( + this.fragmentShader_, this.vertexShader_); gl.useProgram(program); if (goog.isNull(this.locations_)) { this.locations_ = { @@ -385,7 +389,7 @@ ol.webgl.TileLayerRenderer.prototype.render = function() { framebufferExtentSize.height - 1; goog.vec.Vec4.setFromValues(uTileOffset, sx, sy, tx, ty); gl.uniform4fv(this.locations_.uTileOffset, uTileOffset); - map.bindImageTexture( + mapRenderer.bindImageTexture( tile.getImage(), goog.webgl.LINEAR, goog.webgl.LINEAR); gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4); }, this);