perf: Support nearest pixel or bicubic on quad interpolation.
MODIFY
src/canvas/quadFeature.js
src/canvas/quadFeature.js
@@ -138,6 +138,14 @@ var canvas_quadFeature = function (arg) {
var oldAlpha = context2d.globalAlpha;
var opacity = oldAlpha;
+ var nearestPixel = m_this.nearestPixel();
+ if (nearestPixel !== undefined) {
+ if (nearestPixel !== true && util.isNonNullFinite(nearestPixel)) {
+ const curZoom = m_this.layer().map().zoom();
+ nearestPixel = curZoom >= nearestPixel;
+ }
+ context2d.imageSmoothingEnabled = !nearestPixel;
+ }
$.each([m_quads.imgQuads, m_quads.vidQuads], function (listidx, quadlist) {
if (!quadlist) {
return;
@@ -193,6 +201,7 @@ var canvas_quadFeature = function (arg) {
context2d.globalAlpha = oldAlpha;
}
context2d.setTransform(1, 0, 0, 1, 0, 0);
+ context2d.imageSmoothingEnabled = true;
};
/**

MODIFY
src/canvas/tileLayer.js
src/canvas/tileLayer.js
@@ -69,6 +69,7 @@ var canvas_tileLayer = function () {
*/
this._update = function (request) {
s_update.call(m_this, request);
+ m_quadFeature.nearestPixel(m_this.nearestPixel());
m_this._addBaseQuadToTiles(m_quadFeature, m_tiles);
return m_this;
};

MODIFY
src/map.js
src/map.js
@@ -1964,6 +1964,9 @@ var map = function (arg) {
return m_this;
};
+ /* Report the current version on the map object. */
+ this._version = require('./version');
+
/**
* Draw a layer image to a canvas context. The layer's opacity and transform
* are applied. This is used as part of making a screenshot.

MODIFY
src/pixelmapLayer.js
src/pixelmapLayer.js
@@ -96,6 +96,7 @@ var pixelmapLayer = function (arg) {
this._init = function () {
// Call super class init
s_init.apply(m_this, arguments);
+ m_this.nearestPixel(true, true);
const pixelmapArgs = {quadFeature: m_this.features()[0]};
if (arg.style) {

MODIFY
src/quadFeature.js
src/quadFeature.js
@@ -47,6 +47,10 @@ var feature = require('./feature');
* call `cacheUpdate` on the data item or for all data.
* @property {geo.quadFeature.styleSpec} [style] Style object with default
* style options.
+ * @property {boolean|number} [nearestPixel] If true, image quads are
+ * rendered with near-neighbor sampling. If false, with interpolated
+ * sampling. If a number, interpolate at that zoom level or below and
+ * nearest neighbor at that zoom level or above.
*/
/**
@@ -106,6 +110,7 @@ var quadFeature = function (arg) {
var m_this = this,
s_init = this._init,
m_cacheQuads,
+ m_nearestPixel = arg.nearestPixel,
m_nextQuadId = 0,
m_images = [],
m_videos = [],
@@ -677,6 +682,25 @@ var quadFeature = function (arg) {
return null;
};
+ /**
+ * Get/Set nearestPixel value.
+ *
+ * @param {boolean|number} [val] If not specified, return the current value.
+ * If true, image quads are rendered with near-neighbor sampling. If
+ * false, with interpolated sampling. If a number, interpolate at that
+ * zoom level or below and nearest neighbor at that zoom level or above.
+ * @returns {boolean|number|this}
+ */
+ this.nearestPixel = function (val) {
+ if (val === undefined) {
+ return m_nearestPixel;
+ } else {
+ m_nearestPixel = val;
+ m_this.modified();
+ }
+ return m_this;
+ };
+
/**
* Initialize.
*

MODIFY
src/tileLayer.js
src/tileLayer.js
@@ -81,6 +81,10 @@ var featureLayer = require('./featureLayer');
* any tile layers. If specified, this uses the quad defaults, so this is a
* ``geo.quadFeature.position`` object with, typically, an ``image`` property
* added to it. The quad positions are in the map gcs coordinates.
+ * @property {boolean|number} [nearestPixel] If true, image quads are
+ * rendered with near-neighbor sampling. If false, with interpolated
+ * sampling. If a number, interpolate at that zoom level or below and
+ * nearest neighbor at that zoom level or above.
*/
/**
@@ -228,6 +232,7 @@ var tileLayer = function (arg) {
m_reference,
m_exited,
m_lastBaseQuad,
+ m_nearestPixel = arg.nearestPixel,
m_this = this;
// copy the options into a private variable
@@ -1682,6 +1687,31 @@ var tileLayer = function (arg) {
return m_this;
};
+ /**
+ * Get/Set nearestPixel value.
+ *
+ * @param {boolean|number} [val] If not specified, return the current value.
+ * If true, image quads are rendered with near-neighbor sampling. If
+ * false, with interpolated sampling. If a number, interpolate at that
+ * zoom level or below and nearest neighbor at that zoom level or above.
+ * @param {boolean} [skipUpdate] If specifying val and this value is truthy,
+ * don't update the layer or mark it as modified.
+ * @returns {boolean|number|this}
+ */
+ this.nearestPixel = function (val, skipUpdate) {
+ if (val === undefined) {
+ return m_nearestPixel;
+ }
+ if (m_nearestPixel !== val) {
+ m_nearestPixel = val;
+ if (!skipUpdate) {
+ m_this.modified();
+ m_this._update();
+ }
+ }
+ return m_this;
+ };
+
/**
* Get/set the baseQuad.
*

MODIFY
src/webgl/pixelmapFeature.js
src/webgl/pixelmapFeature.js
@@ -134,7 +134,8 @@ var webgl_pixelmapFeature = function (arg) {
m_quadFeature = m_this.layer().createFeature('quad', {
selectionAPI: false,
gcs: m_this.gcs(),
- visible: m_this.visible(undefined, true)
+ visible: m_this.visible(undefined, true),
+ nearestPixel: true
});
m_quadFeatureInit = false;
}
@@ -153,11 +154,6 @@ var webgl_pixelmapFeature = function (arg) {
prog.addUniform(lutHeight);
};
m_quadFeature._hookRenderImageQuads = (renderState, quads) => {
- quads.forEach((quad) => {
- if (quad.image && quad.texture && !quad.texture.nearestPixel()) {
- quad.texture.setNearestPixel(true);
- }
- });
m_lookupTable.bind(renderState, quads);
};
if (m_quadFeatureInit === false) {
@@ -188,6 +184,7 @@ var webgl_pixelmapFeature = function (arg) {
if (arg.quadFeature) {
m_quadFeature = arg.quadFeature;
+ m_quadFeature.nearestPixel(true);
}
this._init(arg);
return this;

MODIFY
src/webgl/quadFeature.js
src/webgl/quadFeature.js
@@ -2,6 +2,7 @@ var inherit = require('../inherit');
var registerFeature = require('../registry').registerFeature;
var quadFeature = require('../quadFeature');
var timestamp = require('../timestamp');
+var util = require('../util');
let _memoryCheckLargestTested = 4096 * 4096;
@@ -364,6 +365,18 @@ var webgl_quadFeature = function (arg) {
cropsrc = {x0: 0, y0: 0, x1: 1, y1: 1}, quadcropsrc,
w, h, quadw, quadh;
+ let nearestPixel = m_this.nearestPixel();
+ if (nearestPixel !== undefined) {
+ if (nearestPixel !== true && util.isNonNullFinite(nearestPixel)) {
+ const curZoom = m_this.layer().map().zoom();
+ nearestPixel = curZoom >= nearestPixel;
+ }
+ m_quads.imgQuads.forEach((quad) => {
+ if (quad.image && quad.texture && quad.texture.nearestPixel() !== nearestPixel) {
+ quad.texture.setNearestPixel(nearestPixel);
+ }
+ });
+ }
if (m_this._hookRenderImageQuads) {
m_this._hookRenderImageQuads(renderState, m_quads.imgQuads);
}

MODIFY
src/webgl/tileLayer.js
src/webgl/tileLayer.js
@@ -171,6 +171,7 @@ var webgl_tileLayer = function () {
*/
this._update = function (request) {
s_update.call(m_this, request);
+ m_quadFeature.nearestPixel(m_this.nearestPixel());
m_this._addBaseQuadToTiles(m_quadFeature, m_tiles);
return m_this;
};

MODIFY
tests/cases/osmLayer.js
tests/cases/osmLayer.js
@@ -185,11 +185,25 @@ describe('geo.core.osmLayer', function () {
it('destroy', destroy_map);
});
describe('webgl', function () {
+ var layer;
it('creation', function () {
map = create_map();
- map.createLayer('osm', {renderer: 'webgl', url: '/testdata/white.jpg'});
+ layer = map.createLayer('osm', {renderer: 'webgl', url: '/testdata/white.jpg'});
expect(map.node().find('.webgl-canvas').length).toBe(1);
});
+ it('nearestPixel', function () {
+ mockAnimationFrame();
+ map.zoom(1);
+ stepAnimationFrame();
+ expect(layer.nearestPixel()).toBe(undefined);
+ layer.nearestPixel(0).draw();
+ stepAnimationFrame();
+ expect(layer.nearestPixel()).toBe(0);
+ layer.nearestPixel(2).draw();
+ stepAnimationFrame();
+ expect(layer.nearestPixel()).toBe(2);
+ unmockAnimationFrame();
+ });
it('destruction', destroy_map);
});
describe('switch renderer', function () {

MODIFY
tests/cases/tileLayer.js
tests/cases/tileLayer.js
@@ -485,6 +485,22 @@ describe('geo.tileLayer', function () {
// we don't test setting it here, as we have too much mocked to carry
// through. The setting test is done in the osmLayer tests.
});
+ it('nearestPixel', function () {
+ var m = map(), layer;
+ opts.map = m;
+ layer = geo.tileLayer(opts);
+ expect(layer.nearestPixel()).toBe(undefined);
+ layer.nearestPixel(4, true);
+ expect(layer.nearestPixel()).toBe(4);
+ layer.nearestPixel(6, true);
+ expect(layer.nearestPixel()).toBe(6);
+ layer.nearestPixel(6, true);
+ expect(layer.nearestPixel()).toBe(6);
+ layer.nearestPixel(true, true);
+ expect(layer.nearestPixel()).toBe(true);
+ layer.nearestPixel(false, true);
+ expect(layer.nearestPixel()).toBe(false);
+ });
});
describe('Public utility methods', function () {
describe('isValid', function () {

perf: Support nearest pixel or bicubic on quad interpolation.