diff --git a/debug/image.html b/debug/image.html index 646e5d8671b..b5bf1400502 100644 --- a/debug/image.html +++ b/debug/image.html @@ -36,12 +36,15 @@ "id": "background", "type": "background", "paint": { - "background-color": "rgb(4,7,14)" + "background-color": "rgb(128,128,128)" } }, { "id": "image", "type": "raster", - "source": "image" + "source": "image", + "paint": { + "raster-resampling": "nearest" + } }] }; diff --git a/src/render/draw_raster.js b/src/render/draw_raster.js index 8f788414677..3454c34cef3 100644 --- a/src/render/draw_raster.js +++ b/src/render/draw_raster.js @@ -56,18 +56,20 @@ function drawRaster(painter: Painter, sourceCache: SourceCache, layer: RasterSty let parentScaleBy, parentTL; + const textureFilter = layer.paint.get('raster-resampling') === 'nearest' ? gl.NEAREST : gl.LINEAR; + context.activeTexture.set(gl.TEXTURE0); - tile.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE, gl.LINEAR_MIPMAP_NEAREST); + tile.texture.bind(textureFilter, gl.CLAMP_TO_EDGE, gl.LINEAR_MIPMAP_NEAREST); context.activeTexture.set(gl.TEXTURE1); if (parentTile) { - parentTile.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE, gl.LINEAR_MIPMAP_NEAREST); + parentTile.texture.bind(textureFilter, gl.CLAMP_TO_EDGE, gl.LINEAR_MIPMAP_NEAREST); parentScaleBy = Math.pow(2, parentTile.tileID.overscaledZ - tile.tileID.overscaledZ); parentTL = [tile.tileID.canonical.x * parentScaleBy % 1, tile.tileID.canonical.y * parentScaleBy % 1]; } else { - tile.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE, gl.LINEAR_MIPMAP_NEAREST); + tile.texture.bind(textureFilter, gl.CLAMP_TO_EDGE, gl.LINEAR_MIPMAP_NEAREST); } // cross-fade parameters diff --git a/src/style-spec/reference/v8.json b/src/style-spec/reference/v8.json index c404deed477..529e27c2cf0 100644 --- a/src/style-spec/reference/v8.json +++ b/src/style-spec/reference/v8.json @@ -5013,6 +5013,32 @@ }, "property-type": "data-constant" }, + "raster-resampling": { + "type": "enum", + "doc": "The resampling/interpolation method to use for overscaling, also known as texture magnification filter", + "values": { + "linear": { + "doc": "(Bi)linear filtering interpolates pixel values using the weighted average of the four closest original source pixels creating a smooth but blurry look when overscaled" + }, + "nearest": { + "doc": "Nearest neighbor filtering interpolates pixel values using the nearest original source pixel creating a sharp but pixelated look when overscaled" + } + }, + "default": "linear", + "sdk-support": { + "basic functionality": { + "js": "0.47.0" + }, + "data-driven styling": {} + }, + "expression": { + "interpolated": false, + "parameters": [ + "zoom" + ] + }, + "property-type": "data-constant" + }, "raster-fade-duration": { "type": "number", "default": 300, diff --git a/src/style/style_layer/raster_style_layer_properties.js b/src/style/style_layer/raster_style_layer_properties.js index aab591ac770..e0193d510b2 100644 --- a/src/style/style_layer/raster_style_layer_properties.js +++ b/src/style/style_layer/raster_style_layer_properties.js @@ -22,6 +22,7 @@ export type PaintProps = {| "raster-brightness-max": DataConstantProperty, "raster-saturation": DataConstantProperty, "raster-contrast": DataConstantProperty, + "raster-resampling": DataConstantProperty<"linear" | "nearest">, "raster-fade-duration": DataConstantProperty, |}; @@ -32,6 +33,7 @@ const paint: Properties = new Properties({ "raster-brightness-max": new DataConstantProperty(styleSpec["paint_raster"]["raster-brightness-max"]), "raster-saturation": new DataConstantProperty(styleSpec["paint_raster"]["raster-saturation"]), "raster-contrast": new DataConstantProperty(styleSpec["paint_raster"]["raster-contrast"]), + "raster-resampling": new DataConstantProperty(styleSpec["paint_raster"]["raster-resampling"]), "raster-fade-duration": new DataConstantProperty(styleSpec["paint_raster"]["raster-fade-duration"]), }); diff --git a/test/README.md b/test/README.md index f76c4692731..ed53f9218df 100644 --- a/test/README.md +++ b/test/README.md @@ -13,7 +13,7 @@ There are two test suites associated with Mapbox GL JS To run individual tests: - Unit tests: `yarn test-unit path/to/file.test.js` where the path begins within the `/test/unit/` directory - - Render tests: `yarn test-render render-test-name` + - Render tests: `yarn test-render render-test-name` (e.g. `yarn test-render background-color/default`) ## Writing Unit Tests diff --git a/test/integration/render-tests/image/raster-resampling/expected.png b/test/integration/render-tests/image/raster-resampling/expected.png new file mode 100644 index 00000000000..759c8e5c07e Binary files /dev/null and b/test/integration/render-tests/image/raster-resampling/expected.png differ diff --git a/test/integration/render-tests/image/raster-resampling/style.json b/test/integration/render-tests/image/raster-resampling/style.json new file mode 100644 index 00000000000..4bad88bbe2e --- /dev/null +++ b/test/integration/render-tests/image/raster-resampling/style.json @@ -0,0 +1,49 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 64, + "height": 64 + } + }, + "center": [ + -122.514526, + 37.562984 + ], + "zoom": 20, + "sources": { + "image": { + "type": "image", + "coordinates": [ + [ + -122.51596391201019, + 37.56238816766053 + ], + [ + -122.51467645168304, + 37.56410183312965 + ], + [ + -122.51309394836426, + 37.563391708549425 + ], + [ + -122.51423120498657, + 37.56161849366671 + ] + ], + "url": "local://image/0.png" + } + }, + "layers": [ + { + "id": "image", + "type": "raster", + "source": "image", + "paint": { + "raster-fade-duration": 0, + "raster-resampling": "nearest" + } + } + ] +} diff --git a/test/integration/render-tests/raster-resampling/default/expected.png b/test/integration/render-tests/raster-resampling/default/expected.png new file mode 100644 index 00000000000..4db0b165ef2 Binary files /dev/null and b/test/integration/render-tests/raster-resampling/default/expected.png differ diff --git a/test/integration/render-tests/raster-resampling/default/style.json b/test/integration/render-tests/raster-resampling/default/style.json new file mode 100644 index 00000000000..ec0fa9ef2af --- /dev/null +++ b/test/integration/render-tests/raster-resampling/default/style.json @@ -0,0 +1,33 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256 + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 20, + "sources": { + "satellite": { + "type": "raster", + "tiles": [ + "local://tiles/{z}-{x}-{y}.satellite.png" + ], + "maxzoom": 17, + "tileSize": 256 + } + }, + "layers": [ + { + "id": "raster", + "type": "raster", + "source": "satellite", + "paint": { + "raster-fade-duration": 0 + } + } + ] +} diff --git a/test/integration/render-tests/raster-resampling/function/expected.png b/test/integration/render-tests/raster-resampling/function/expected.png new file mode 100644 index 00000000000..f4f7bce7123 Binary files /dev/null and b/test/integration/render-tests/raster-resampling/function/expected.png differ diff --git a/test/integration/render-tests/raster-resampling/function/style.json b/test/integration/render-tests/raster-resampling/function/style.json new file mode 100644 index 00000000000..2ac91b44c55 --- /dev/null +++ b/test/integration/render-tests/raster-resampling/function/style.json @@ -0,0 +1,45 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256 + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 20, + "sources": { + "satellite": { + "type": "raster", + "tiles": [ + "local://tiles/{z}-{x}-{y}.satellite.png" + ], + "maxzoom": 17, + "tileSize": 256 + } + }, + "layers": [ + { + "id": "raster", + "type": "raster", + "source": "satellite", + "paint": { + "raster-fade-duration": 0, + "raster-resampling": { + "stops": [ + [ + 19, + "linear" + ], + [ + 20, + "nearest" + ] + ] + } + } + } + ] +} diff --git a/test/integration/render-tests/raster-resampling/literal/expected.png b/test/integration/render-tests/raster-resampling/literal/expected.png new file mode 100644 index 00000000000..f4f7bce7123 Binary files /dev/null and b/test/integration/render-tests/raster-resampling/literal/expected.png differ diff --git a/test/integration/render-tests/raster-resampling/literal/style.json b/test/integration/render-tests/raster-resampling/literal/style.json new file mode 100644 index 00000000000..daf15580f02 --- /dev/null +++ b/test/integration/render-tests/raster-resampling/literal/style.json @@ -0,0 +1,34 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256 + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 20, + "sources": { + "satellite": { + "type": "raster", + "tiles": [ + "local://tiles/{z}-{x}-{y}.satellite.png" + ], + "maxzoom": 17, + "tileSize": 256 + } + }, + "layers": [ + { + "id": "raster", + "type": "raster", + "source": "satellite", + "paint": { + "raster-fade-duration": 0, + "raster-resampling": "nearest" + } + } + ] +}