summaryrefslogtreecommitdiff
path: root/src/mbgl/util/scaling.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/util/scaling.cpp')
-rw-r--r--src/mbgl/util/scaling.cpp111
1 files changed, 111 insertions, 0 deletions
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