diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | gyp/cache-sqlite.gypi | 3 | ||||
-rw-r--r-- | include/mbgl/platform/platform.hpp | 4 | ||||
-rw-r--r-- | platform/default/sqlite_cache.cpp | 2 | ||||
-rwxr-xr-x | scripts/travis_before_install.sh | 3 | ||||
-rw-r--r-- | src/mbgl/geometry/sprite_atlas.cpp | 111 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/map/sprite.cpp | 7 | ||||
-rw-r--r-- | src/mbgl/map/sprite.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/util/compression.cpp (renamed from platform/default/compression.cpp) | 2 | ||||
-rw-r--r-- | src/mbgl/util/compression.hpp (renamed from platform/default/compression.hpp) | 0 | ||||
-rw-r--r-- | src/mbgl/util/scaling.cpp | 111 | ||||
-rw-r--r-- | src/mbgl/util/scaling.hpp | 23 | ||||
-rw-r--r-- | test/fixtures/sprites/atlas_reference.bin | bin | 0 -> 8137 bytes | |||
-rw-r--r-- | test/fixtures/sprites/atlas_reference.png | bin | 0 -> 9109 bytes | |||
-rw-r--r-- | test/fixtures/sprites/bright.bin | bin | 0 -> 68824 bytes | |||
-rw-r--r-- | test/fixtures/sprites/convert_sprite.js | 19 | ||||
-rw-r--r-- | test/miscellaneous/bilinear.cpp | 53 | ||||
-rw-r--r-- | test/test.gyp | 1 |
19 files changed, 283 insertions, 61 deletions
diff --git a/.gitignore b/.gitignore index 59c180c5de..d8959d4f3b 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ /ios/app/build /test/build /test/node_modules +/test/fixtures/*/*_actual.* /include/mbgl/shader/shaders.hpp /src/shader/shaders_gl.cpp /src/shader/shaders_gles2.cpp diff --git a/gyp/cache-sqlite.gypi b/gyp/cache-sqlite.gypi index 53af8dab59..a9d21924c2 100644 --- a/gyp/cache-sqlite.gypi +++ b/gyp/cache-sqlite.gypi @@ -10,12 +10,11 @@ '../platform/default/sqlite_cache.cpp', '../platform/default/sqlite3.hpp', '../platform/default/sqlite3.cpp', - '../platform/default/compression.hpp', - '../platform/default/compression.cpp', ], 'include_dirs': [ '../include', + '../src', ], 'variables': { diff --git a/include/mbgl/platform/platform.hpp b/include/mbgl/platform/platform.hpp index ea630c0956..ac90d0d3d0 100644 --- a/include/mbgl/platform/platform.hpp +++ b/include/mbgl/platform/platform.hpp @@ -24,10 +24,10 @@ const std::string &applicationRoot(); const std::string &assetRoot(); // Shows an alpha image with the specified dimensions in a named window. -void show_debug_image(std::string name, const char *data, size_t width, size_t height); +void showDebugImage(std::string name, const char *data, size_t width, size_t height); // Shows an alpha image with the specified dimensions in a named window. -void show_color_debug_image(std::string name, const char *data, size_t logical_width, size_t logical_height, size_t width, size_t height); +void showColorDebugImage(std::string name, const char *data, size_t logical_width, size_t logical_height, size_t width, size_t height); } } diff --git a/platform/default/sqlite_cache.cpp b/platform/default/sqlite_cache.cpp index 522b23f22c..b8d47159ce 100644 --- a/platform/default/sqlite_cache.cpp +++ b/platform/default/sqlite_cache.cpp @@ -5,10 +5,10 @@ #include <mbgl/util/util.hpp> #include <mbgl/util/async_queue.hpp> #include <mbgl/util/variant.hpp> +#include <mbgl/util/compression.hpp> #include <mbgl/platform/log.hpp> #include "sqlite3.hpp" -#include "compression.hpp" #include <uv.h> diff --git a/scripts/travis_before_install.sh b/scripts/travis_before_install.sh index 7b0b7ea873..f837e74161 100755 --- a/scripts/travis_before_install.sh +++ b/scripts/travis_before_install.sh @@ -31,6 +31,9 @@ if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then x11proto-xf86vidmode-dev libxxf86vm-dev \ libxcursor-dev libxinerama-dev \ llvm-3.4 # required for mesa + + mapbox_time "install_mesa" \ + mason install mesa 10.4.3 fi mapbox_time "install_awscli" \ diff --git a/src/mbgl/geometry/sprite_atlas.cpp b/src/mbgl/geometry/sprite_atlas.cpp index 077550ff74..dce772f2e4 100644 --- a/src/mbgl/geometry/sprite_atlas.cpp +++ b/src/mbgl/geometry/sprite_atlas.cpp @@ -5,6 +5,7 @@ #include <mbgl/util/math.hpp> #include <mbgl/util/std.hpp> #include <mbgl/util/constants.hpp> +#include <mbgl/util/scaling.hpp> #include <mbgl/map/sprite.hpp> @@ -66,34 +67,6 @@ bool SpriteAtlas::resize(const float newRatio) { return dirty; } -void copy_bitmap(const uint32_t *src, const int src_stride, const int src_x, const int src_y, - uint32_t *dst, const int dst_stride, const int dst_height, const int dst_x, const int dst_y, - const int width, const int height, const bool wrap) { - if (wrap) { - - for (int y = -1; y <= height; y++) { - int dst_y_wrapped = (y + dst_y + dst_height) % dst_height; - int src_y_wrapped = ((y + height) % height) + src_y; - int srcI = src_y_wrapped * src_stride + src_x; - int dstI = dst_y_wrapped * dst_stride; - for (int x = -1; x <= width; x++) { - int dst_x_wrapped = (x + dst_x + dst_stride) % dst_stride; - int src_x_wrapped = (x + width) % width; - dst[dstI + dst_x_wrapped] = src[srcI + src_x_wrapped]; - } - } - - } else { - dst += dst_y * dst_stride + dst_x; - src += src_y * src_stride + src_x; - for (int y = 0; y < height; y++, src += src_stride, dst += dst_stride) { - for (int x = 0; x < width; x++) { - dst[x] = src[x]; - } - } - } -} - Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(const size_t pixel_width, const size_t pixel_height) { // Increase to next number divisible by 4, but at least 1. // This is so we can scale down the texture coordinates and pack them @@ -176,25 +149,53 @@ void SpriteAtlas::allocate() { void SpriteAtlas::copy(const Rect<dimension>& dst, const SpritePosition& src, const bool wrap) { if (!sprite->raster) return; - const uint32_t *src_img = reinterpret_cast<const uint32_t *>(sprite->raster->getData()); - if (!src_img) return; + + const uint32_t *srcData = reinterpret_cast<const uint32_t *>(sprite->raster->getData()); + if (!srcData) return; + const vec2<uint32_t> srcSize { sprite->raster->getWidth(), sprite->raster->getHeight() }; + const Rect<uint32_t> srcPos { src.x, src.y, src.width, src.height }; + allocate(); - uint32_t *dst_img = reinterpret_cast<uint32_t *>(data); - - copy_bitmap( - /* source buffer */ src_img, - /* source stride */ sprite->raster->getWidth(), - /* source x */ src.x, - /* source y */ src.y, - /* dest buffer */ dst_img, - /* dest stride */ width * pixelRatio, - /* dest height */ height * pixelRatio, - /* dest x */ dst.x * pixelRatio, - /* dest y */ dst.y * pixelRatio, - /* icon dimension */ src.width, - /* icon dimension */ src.height, - /* wrap padding */ wrap - ); + uint32_t *dstData = reinterpret_cast<uint32_t *>(data); + const vec2<uint32_t> dstSize { static_cast<unsigned int>(width * pixelRatio), + static_cast<unsigned int>(height * pixelRatio) }; + const Rect<uint32_t> dstPos { static_cast<uint32_t>(dst.x * pixelRatio), + static_cast<uint32_t>(dst.y * pixelRatio), + static_cast<uint32_t>(dst.originalW * pixelRatio), + static_cast<uint32_t>(dst.originalH * pixelRatio) }; + + util::bilinearScale(srcData, srcSize, srcPos, dstData, dstSize, dstPos); + + // Add borders around the copied image if required. + if (wrap) { + // We're copying from the same image so we don't have to scale again. + const uint32_t border = 1; + // Left border + if (dstPos.x >= border) { + util::nearestNeighborScale( + dstData, dstSize, { dstPos.x + dstPos.w - border - 1, dstPos.y, border, dstPos.h }, + dstData, dstSize, { dstPos.x - border, dstPos.y, border, dstPos.h }); + } + // Right border + util::nearestNeighborScale(dstData, dstSize, { dstPos.x, dstPos.y, border, dstPos.h }, + dstData, dstSize, + { dstPos.x + dstPos.w, dstPos.y, border, dstPos.h }); + + // Top border + if (dstPos.y >= border) { + util::nearestNeighborScale( + dstData, dstSize, { dstPos.x - border, dstPos.y + dstPos.h - border - 1, + dstPos.w + 2 * border, border }, + dstData, dstSize, + { dstPos.x - border, dstPos.y - border, dstPos.w + 2 * border, border }); + } + + // Bottom border + util::nearestNeighborScale( + dstData, dstSize, { dstPos.x - border, dstPos.y, dstPos.w + 2 * border, border }, + dstData, dstSize, + { dstPos.x - border, dstPos.y + dstPos.h, dstPos.w + 2 * border, border }); + } dirty = true; } @@ -236,8 +237,10 @@ void SpriteAtlas::bind(bool linear) { #ifndef GL_ES_VERSION_2_0 MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); #endif - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)); + // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures. + // We use those when the pixelRatio isn't a power of two, e.g. on iPhone 6 Plus. + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); first = true; } else { MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); @@ -255,7 +258,7 @@ void SpriteAtlas::bind(bool linear) { allocate(); if (first) { - glTexImage2D( + MBGL_CHECK_ERROR(glTexImage2D( GL_TEXTURE_2D, // GLenum target 0, // GLint level GL_RGBA, // GLint internalformat @@ -265,9 +268,9 @@ void SpriteAtlas::bind(bool linear) { GL_RGBA, // GLenum format GL_UNSIGNED_BYTE, // GLenum type data // const GLvoid * data - ); + )); } else { - glTexSubImage2D( + MBGL_CHECK_ERROR(glTexSubImage2D( GL_TEXTURE_2D, // GLenum target 0, // GLint level 0, // GLint xoffset @@ -277,12 +280,14 @@ void SpriteAtlas::bind(bool linear) { GL_RGBA, // GLenum format GL_UNSIGNED_BYTE, // GLenum type data // const GLvoid *pixels - ); + )); } dirty = false; - // platform::show_color_debug_image("Sprite Atlas", reinterpret_cast<const char *>(data), width, height, width * pixelRatio, height * pixelRatio); +#ifndef GL_ES_VERSION_2_0 + // platform::showColorDebugImage("Sprite Atlas", reinterpret_cast<const char *>(data), width * pixelRatio, height * pixelRatio, width * pixelRatio, height * pixelRatio); +#endif } }; diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 29521f9499..d12afc9143 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -374,7 +374,7 @@ std::string Map::getStyleJSON() const { util::ptr<Sprite> Map::getSprite() { const float pixelRatio = state.getPixelRatio(); const std::string &sprite_url = style->getSpriteURL(); - if (!sprite || sprite->pixelRatio != pixelRatio) { + if (!sprite || !sprite->hasPixelRatio(pixelRatio)) { sprite = Sprite::Create(sprite_url, pixelRatio, *env); } diff --git a/src/mbgl/map/sprite.cpp b/src/mbgl/map/sprite.cpp index 114e8f45f5..8883ee092d 100644 --- a/src/mbgl/map/sprite.cpp +++ b/src/mbgl/map/sprite.cpp @@ -32,7 +32,7 @@ util::ptr<Sprite> Sprite::Create(const std::string &base_url, float pixelRatio, Sprite::Sprite(const Key &, const std::string& base_url, float pixelRatio_) : valid(base_url.length() > 0), - pixelRatio(pixelRatio_), + pixelRatio(pixelRatio_ > 1 ? 2 : 1), spriteURL(base_url + (pixelRatio_ > 1 ? "@2x" : "") + ".png"), jsonURL(base_url + (pixelRatio_ > 1 ? "@2x" : "") + ".json"), raster(), @@ -41,6 +41,11 @@ Sprite::Sprite(const Key &, const std::string& base_url, float pixelRatio_) future(promise.get_future()) { } +bool Sprite::hasPixelRatio(float ratio) const { + return pixelRatio == (ratio > 1 ? 2 : 1); +} + + void Sprite::waitUntilLoaded() const { future.wait(); } diff --git a/src/mbgl/map/sprite.hpp b/src/mbgl/map/sprite.hpp index cb0c274dee..6c1b3ba8e3 100644 --- a/src/mbgl/map/sprite.hpp +++ b/src/mbgl/map/sprite.hpp @@ -43,6 +43,8 @@ public: const SpritePosition &getSpritePosition(const std::string& name) const; + bool hasPixelRatio(float ratio) const; + void waitUntilLoaded() const; bool isLoaded() const; diff --git a/platform/default/compression.cpp b/src/mbgl/util/compression.cpp index c8b38e742f..3a1658b8f6 100644 --- a/platform/default/compression.cpp +++ b/src/mbgl/util/compression.cpp @@ -87,7 +87,7 @@ std::string decompress(const std::string &raw) { inflateEnd(&inflate_stream); if (code != Z_STREAM_END) { - throw std::runtime_error(inflate_stream.msg); + throw std::runtime_error(inflate_stream.msg ? inflate_stream.msg : "decompression error"); } return result; diff --git a/platform/default/compression.hpp b/src/mbgl/util/compression.hpp index a33b2476a7..a33b2476a7 100644 --- a/platform/default/compression.hpp +++ b/src/mbgl/util/compression.hpp diff --git a/src/mbgl/util/scaling.cpp b/src/mbgl/util/scaling.cpp new file mode 100644 index 0000000000..a554b2e137 --- /dev/null +++ b/src/mbgl/util/scaling.cpp @@ -0,0 +1,111 @@ +#include "scaling.hpp" + +namespace { + +using namespace mbgl; + +inline uint8_t bilinearInterpolate(uint8_t tl, uint8_t tr, uint8_t bl, uint8_t br, double dx, double dy) { + const double t = dx * (tr - tl) + tl; + const double b = dx * (br - bl) + bl; + return t + dy * (b - t); +} + +template <size_t i> +inline const uint8_t& b(const uint32_t& w) { + return reinterpret_cast<const uint8_t*>(&w)[i]; +} + +template <size_t i> +inline uint8_t& b(uint32_t& w) { + return reinterpret_cast<uint8_t*>(&w)[i]; +} + +vec2<double> getFactor(const Rect<uint32_t>& srcPos, const Rect<uint32_t>& dstPos) { + return { + double(srcPos.w) / dstPos.w, + double(srcPos.h) / dstPos.h + }; +} + +vec2<uint32_t> getBounds(const vec2<uint32_t>& srcSize, const Rect<uint32_t>& srcPos, + const vec2<uint32_t>& dstSize, const Rect<uint32_t>& dstPos, + const vec2<double>& factor) { + if (srcPos.x > srcSize.x || srcPos.y > srcSize.y || + dstPos.x > dstSize.x || dstPos.y > dstSize.y) { + // Source or destination position is out of range. + return { 0, 0 }; + } + + // Make sure we don't read/write values out of range. + return { std::min(uint32_t(double(srcSize.x - srcPos.x) / factor.x), + std::min(dstSize.x - dstPos.x, dstPos.w)), + std::min(uint32_t(double(srcSize.y - srcPos.y) / factor.y), + std::min(dstSize.y - dstPos.y, dstPos.h)) }; +} +} + +namespace mbgl { +namespace util { + +void bilinearScale(const uint32_t* srcData, const vec2<uint32_t>& srcSize, + const Rect<uint32_t>& srcPos, uint32_t* dstData, const vec2<uint32_t>& dstSize, + const Rect<uint32_t>& dstPos) { + const auto factor = getFactor(srcPos, dstPos); + const auto bounds = getBounds(srcSize, srcPos, dstSize, dstPos, factor); + + double fractSrcY = srcPos.y; + double fractSrcX; + uint32_t x, y; + size_t i = dstSize.x * dstPos.y + dstPos.x; + for (y = 0; y < bounds.y; y++) { + fractSrcX = srcPos.x; + const uint32_t srcY0 = fractSrcY; + const uint32_t srcY1 = std::min(srcY0 + 1, srcSize.y - 1); + for (x = 0; x < bounds.x; x++) { + const uint32_t srcX0 = fractSrcX; + const uint32_t srcX1 = std::min(srcX0 + 1, srcSize.x - 1); + + const uint32_t tl = srcData[srcSize.x * srcY0 + srcX0]; + const uint32_t tr = srcData[srcSize.x * srcY0 + srcX1]; + const uint32_t bl = srcData[srcSize.x * srcY1 + srcX0]; + const uint32_t br = srcData[srcSize.x * srcY1 + srcX1]; + + const double dx = fractSrcX - srcX0; + const double dy = fractSrcY - srcY0; + uint32_t& dst = dstData[i + x]; + b<0>(dst) = bilinearInterpolate(b<0>(tl), b<0>(tr), b<0>(bl), b<0>(br), dx, dy); + b<1>(dst) = bilinearInterpolate(b<1>(tl), b<1>(tr), b<1>(bl), b<1>(br), dx, dy); + b<2>(dst) = bilinearInterpolate(b<2>(tl), b<2>(tr), b<2>(bl), b<2>(br), dx, dy); + b<3>(dst) = bilinearInterpolate(b<3>(tl), b<3>(tr), b<3>(bl), b<3>(br), dx, dy); + fractSrcX += factor.x; + } + i += dstSize.x; + fractSrcY += factor.y; + } +} + +void nearestNeighborScale(const uint32_t* srcData, const vec2<uint32_t>& srcSize, + const Rect<uint32_t>& srcPos, uint32_t* dstData, + const vec2<uint32_t>& dstSize, const Rect<uint32_t>& dstPos) { + const auto factor = getFactor(srcPos, dstPos); + const auto bounds = getBounds(srcSize, srcPos, dstSize, dstPos, factor); + + double fractSrcY = srcPos.y; + double fractSrcX; + size_t i = dstSize.x * dstPos.y + dstPos.x; + uint32_t srcY; + uint32_t x, y; + for (y = 0; y < bounds.y; y++) { + fractSrcX = srcPos.x; + srcY = srcSize.x * uint32_t(fractSrcY); + for (x = 0; x < bounds.x; x++) { + dstData[i + x] = srcData[srcY + uint32_t(fractSrcX)]; + fractSrcX += factor.x; + } + i += dstSize.x; + fractSrcY += factor.y; + } +} + +} +}
\ No newline at end of file diff --git a/src/mbgl/util/scaling.hpp b/src/mbgl/util/scaling.hpp new file mode 100644 index 0000000000..d2625e9219 --- /dev/null +++ b/src/mbgl/util/scaling.hpp @@ -0,0 +1,23 @@ +#ifndef MBGL_UTIL_SCALING +#define MBGL_UTIL_SCALING + + +#include <mbgl/util/vec.hpp> +#include <mbgl/util/rect.hpp> + +#include <cstdint> + +namespace mbgl { +namespace util { + +void bilinearScale(const uint32_t* srcData, const vec2<uint32_t>& srcSize, + const Rect<uint32_t>& srcPos, uint32_t* dstData, const vec2<uint32_t>& dstSize, + const Rect<uint32_t>& dstPos); + +void nearestNeighborScale(const uint32_t* srcData, const vec2<uint32_t>& srcSize, + const Rect<uint32_t>& srcPos, uint32_t* dstData, + const vec2<uint32_t>& dstSize, const Rect<uint32_t>& dstPos); +} +} + +#endif diff --git a/test/fixtures/sprites/atlas_reference.bin b/test/fixtures/sprites/atlas_reference.bin Binary files differnew file mode 100644 index 0000000000..57eb28bd93 --- /dev/null +++ b/test/fixtures/sprites/atlas_reference.bin diff --git a/test/fixtures/sprites/atlas_reference.png b/test/fixtures/sprites/atlas_reference.png Binary files differnew file mode 100644 index 0000000000..86fad30983 --- /dev/null +++ b/test/fixtures/sprites/atlas_reference.png diff --git a/test/fixtures/sprites/bright.bin b/test/fixtures/sprites/bright.bin Binary files differnew file mode 100644 index 0000000000..3aee130074 --- /dev/null +++ b/test/fixtures/sprites/bright.bin diff --git a/test/fixtures/sprites/convert_sprite.js b/test/fixtures/sprites/convert_sprite.js new file mode 100644 index 0000000000..ba4ff5c29f --- /dev/null +++ b/test/fixtures/sprites/convert_sprite.js @@ -0,0 +1,19 @@ +// Converts a PNG image to a custom "image format" that has a uint32_t width/height prefix and then +// raw RGBA data. We can't use the built-in PNG reading routines because they are reading +// premultiplied images by default. + +var fs = require('fs'); +var zlib = require('zlib'); +var PNG = require('png-js'); +var png = PNG.load('styles/sprites/bright.png'); +png.decodePixels(function(data) { + var result = new Buffer(8 + data.length); + result.writeUInt32BE(png.width, 0); + result.writeUInt32BE(png.height, 4); + data.copy(result, 8); + + zlib.deflate(result, function(err, data) { + if (err) throw err; + fs.writeFileSync('test/fixtures/sprites/bright.bin', data); + }); +}); diff --git a/test/miscellaneous/bilinear.cpp b/test/miscellaneous/bilinear.cpp new file mode 100644 index 0000000000..b7730303a0 --- /dev/null +++ b/test/miscellaneous/bilinear.cpp @@ -0,0 +1,53 @@ +#include "../fixtures/util.hpp" +#include <mbgl/util/compression.hpp> +#include <mbgl/util/scaling.hpp> +#include <mbgl/util/image.hpp> +#include <mbgl/util/io.hpp> +#include <mbgl/util/std.hpp> + +#include <algorithm> +#include <cstring> + +using namespace mbgl; + +TEST(Bilinear, Scaling) { + // We're reading from a custom "image format" that has a uint32_t width/height prefix and then + // raw RGBA data. We can't use the built-in PNG reading routines because they are reading + // premultiplied images by default. + const std::string sprite = util::decompress(util::read_file("test/fixtures/sprites/bright.bin")); + const uint8_t *src = reinterpret_cast<const uint8_t *>(sprite.data()); + ASSERT_GT(sprite.length(), 8u); + const uint32_t width = src[0] << 24 | src[1] << 16 | src[2] << 8 | src[3]; + const uint32_t height = src[4] << 24 | src[5] << 16 | src[6] << 8 | src[7]; + ASSERT_EQ(sprite.length(), 2 * sizeof(uint32_t) + width * height * sizeof(uint32_t)); + + const uint32_t *srcData = reinterpret_cast<const uint32_t *>(src + 8); + const vec2<uint32_t> srcSize { width, height }; + const vec2<uint32_t> dstSize { 128, 128 }; + auto dst = util::make_unique<uint32_t[]>(dstSize.x * dstSize.y); + uint32_t *dstData = dst.get(); + std::fill(dstData, dstData + dstSize.x * dstSize.y, 0xFFFF00FF); + + util::bilinearScale(srcData, srcSize, { 0, 0, 24, 24 }, dstData, dstSize, { 8, 8, 24, 24 }); + util::bilinearScale(srcData, srcSize, { 26, 0, 24, 24 }, dstData, dstSize, { 0, 40, 48, 48 }); + util::bilinearScale(srcData, srcSize, { 26, 26, 24, 24 }, dstData, dstSize, { 52, 40, 36, 36 }); + util::bilinearScale(srcData, srcSize, { 26, 26, 24, 24 }, dstData, dstSize, { 52, 40, 36, 36 }); + util::bilinearScale(srcData, srcSize, { 104, 0, 24, 24 }, dstData, dstSize, { 96, 0, 48, 48 }); + util::bilinearScale(srcData, srcSize, { 52, 260, 24, 24 }, dstData, dstSize, { 108, 108, 38, 38 }); + util::bilinearScale(srcData, srcSize, { 380, 0, 24, 24 }, dstData, dstSize, { 36, 0, 24, 24 }); + util::bilinearScale(srcData, srcSize, { 396, 396, 24, 24 }, dstData, dstSize, { 0, 0, 50, 50 }); + util::bilinearScale(srcData, srcSize, { 380, 182, 12, 12 }, dstData, dstSize, { 52, 80, 24, 24 }); + + // From the bottom + util::bilinearScale(srcData, srcSize, { 252, 380, 12, 12 }, dstData, dstSize, { 0, 90, 12, 12 }); + util::bilinearScale(srcData, srcSize, { 252, 380, 12, 12 }, dstData, dstSize, { 18, 90, 24, 24 }); + + const std::string data { reinterpret_cast<char *>(dstData), dstSize.x * dstSize.y * sizeof(uint32_t) }; + util::write_file("test/fixtures/sprites/atlas_actual.png", util::compress_png(dstSize.x, dstSize.y, dstData)); + util::write_file("test/fixtures/sprites/atlas_actual.bin", util::compress(data)); + + const std::string reference = util::decompress(util::read_file("test/fixtures/sprites/atlas_reference.bin")); + + EXPECT_EQ(reference.size(), data.size()); + EXPECT_TRUE(0 == std::memcmp(data.data(), reference.data(), data.size())); +} diff --git a/test/test.gyp b/test/test.gyp index 719207a02e..c333a40064 100644 --- a/test/test.gyp +++ b/test/test.gyp @@ -38,6 +38,7 @@ 'headless/headless.cpp', 'miscellaneous/clip_ids.cpp', + 'miscellaneous/bilinear.cpp', 'miscellaneous/comparisons.cpp', 'miscellaneous/enums.cpp', 'miscellaneous/functions.cpp', |