summaryrefslogtreecommitdiff
path: root/src/mbgl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl')
-rw-r--r--src/mbgl/actor/mailbox.cpp6
-rw-r--r--src/mbgl/actor/mailbox.hpp2
-rw-r--r--src/mbgl/actor/thread_pool.cpp55
-rw-r--r--src/mbgl/actor/thread_pool.hpp27
-rw-r--r--src/mbgl/annotation/symbol_annotation_impl.cpp25
-rw-r--r--src/mbgl/gl/context.cpp183
-rw-r--r--src/mbgl/gl/context.hpp27
-rw-r--r--src/mbgl/gl/framebuffer.hpp17
-rw-r--r--src/mbgl/gl/gl.cpp1
-rw-r--r--src/mbgl/gl/object.cpp5
-rw-r--r--src/mbgl/gl/object.hpp6
-rw-r--r--src/mbgl/gl/renderbuffer.hpp19
-rw-r--r--src/mbgl/gl/state.hpp36
-rw-r--r--src/mbgl/gl/types.hpp5
-rw-r--r--src/mbgl/gl/value.cpp16
-rw-r--r--src/mbgl/gl/value.hpp9
-rw-r--r--src/mbgl/map/backend.cpp22
-rw-r--r--src/mbgl/map/map.cpp239
-rw-r--r--src/mbgl/map/transform.cpp22
-rw-r--r--src/mbgl/map/transform_state.cpp44
-rw-r--r--src/mbgl/map/transform_state.hpp12
-rw-r--r--src/mbgl/map/update.hpp30
-rw-r--r--src/mbgl/map/view.cpp22
-rw-r--r--src/mbgl/renderer/paint_parameters.hpp2
-rw-r--r--src/mbgl/renderer/painter.cpp50
-rw-r--r--src/mbgl/renderer/painter.hpp14
-rw-r--r--src/mbgl/renderer/painter_debug.cpp42
-rw-r--r--src/mbgl/renderer/painter_fill.cpp5
-rw-r--r--src/mbgl/style/source_impl.hpp2
-rw-r--r--src/mbgl/style/source_observer.hpp3
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.cpp22
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.hpp2
-rw-r--r--src/mbgl/style/style.cpp7
-rw-r--r--src/mbgl/style/style.hpp1
-rw-r--r--src/mbgl/text/collision_tile.cpp156
-rw-r--r--src/mbgl/text/collision_tile.hpp9
-rw-r--r--src/mbgl/util/intersection_tests.cpp32
-rw-r--r--src/mbgl/util/intersection_tests.hpp1
-rw-r--r--src/mbgl/util/offscreen_texture.cpp70
-rw-r--r--src/mbgl/util/offscreen_texture.hpp17
-rw-r--r--src/mbgl/util/tile_coordinate.hpp15
-rw-r--r--src/mbgl/util/tile_cover.cpp11
42 files changed, 733 insertions, 558 deletions
diff --git a/src/mbgl/actor/mailbox.cpp b/src/mbgl/actor/mailbox.cpp
index ae3c0967af..5f60629833 100644
--- a/src/mbgl/actor/mailbox.cpp
+++ b/src/mbgl/actor/mailbox.cpp
@@ -52,4 +52,10 @@ void Mailbox::receive() {
}
}
+void Mailbox::maybeReceive(std::weak_ptr<Mailbox> mailbox) {
+ if (auto locked = mailbox.lock()) {
+ locked->receive();
+ }
+}
+
} // namespace mbgl
diff --git a/src/mbgl/actor/mailbox.hpp b/src/mbgl/actor/mailbox.hpp
index 5d5e8cb924..cff0de243a 100644
--- a/src/mbgl/actor/mailbox.hpp
+++ b/src/mbgl/actor/mailbox.hpp
@@ -18,6 +18,8 @@ public:
void close();
void receive();
+ static void maybeReceive(std::weak_ptr<Mailbox>);
+
private:
Scheduler& scheduler;
diff --git a/src/mbgl/actor/thread_pool.cpp b/src/mbgl/actor/thread_pool.cpp
deleted file mode 100644
index 2995ed26ad..0000000000
--- a/src/mbgl/actor/thread_pool.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <mbgl/actor/thread_pool.hpp>
-#include <mbgl/actor/mailbox.hpp>
-
-namespace mbgl {
-
-ThreadPool::ThreadPool(std::size_t count) {
- threads.reserve(count);
- for (std::size_t i = 0; i < count; ++i) {
- threads.emplace_back([this] () {
- while (true) {
- std::unique_lock<std::mutex> lock(mutex);
-
- cv.wait(lock, [this] {
- return !queue.empty() || terminate;
- });
-
- if (terminate) {
- return;
- }
-
- auto mailbox = queue.front();
- queue.pop();
- lock.unlock();
-
- if (auto locked = mailbox.lock()) {
- locked->receive();
- }
- }
- });
- }
-}
-
-ThreadPool::~ThreadPool() {
- {
- std::lock_guard<std::mutex> lock(mutex);
- terminate = true;
- }
-
- cv.notify_all();
-
- for (auto& thread : threads) {
- thread.join();
- }
-}
-
-void ThreadPool::schedule(std::weak_ptr<Mailbox> mailbox) {
- {
- std::lock_guard<std::mutex> lock(mutex);
- queue.push(mailbox);
- }
-
- cv.notify_one();
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/actor/thread_pool.hpp b/src/mbgl/actor/thread_pool.hpp
deleted file mode 100644
index a14d16d771..0000000000
--- a/src/mbgl/actor/thread_pool.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-
-#include <mbgl/actor/scheduler.hpp>
-
-#include <condition_variable>
-#include <mutex>
-#include <queue>
-#include <thread>
-
-namespace mbgl {
-
-class ThreadPool : public Scheduler {
-public:
- ThreadPool(std::size_t count);
- ~ThreadPool() override;
-
- void schedule(std::weak_ptr<Mailbox>) override;
-
-private:
- std::vector<std::thread> threads;
- std::queue<std::weak_ptr<Mailbox>> queue;
- std::mutex mutex;
- std::condition_variable cv;
- bool terminate { false };
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/annotation/symbol_annotation_impl.cpp b/src/mbgl/annotation/symbol_annotation_impl.cpp
index 040de21214..e5ae5f4b91 100644
--- a/src/mbgl/annotation/symbol_annotation_impl.cpp
+++ b/src/mbgl/annotation/symbol_annotation_impl.cpp
@@ -2,6 +2,7 @@
#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/math/clamp.hpp>
+#include <mbgl/util/tile_coordinate.hpp>
namespace mbgl {
@@ -14,26 +15,10 @@ void SymbolAnnotationImpl::updateLayer(const CanonicalTileID& tileID, Annotation
std::unordered_map<std::string, std::string> featureProperties;
featureProperties.emplace("sprite", annotation.icon.empty() ? std::string("default_marker") : annotation.icon);
- const Point<double>& p = annotation.geometry;
-
- // Clamp to the latitude limits of Web Mercator.
- const double constrainedLatitude = util::clamp(p.y, -util::LATITUDE_MAX, util::LATITUDE_MAX);
-
- // Project a coordinate into unit space in a square map.
- const double sine = std::sin(constrainedLatitude * util::DEG2RAD);
- const double x = p.x / util::DEGREES_MAX + 0.5;
- const double y = 0.5 - 0.25 * std::log((1.0 + sine) / (1.0 - sine)) / M_PI;
-
- Point<double> projected(x, y);
- projected *= std::pow(2, tileID.z);
- projected.x = std::fmod(projected.x, 1);
- projected.y = std::fmod(projected.y, 1);
- projected *= double(util::EXTENT);
-
- layer.features.emplace_back(id,
- FeatureType::Point,
- GeometryCollection {{ {{ convertPoint<int16_t>(projected) }} }},
- featureProperties);
+ LatLng latLng { annotation.geometry.y, annotation.geometry.x };
+ TileCoordinate coordinate = TileCoordinate::fromLatLng(0, latLng);
+ GeometryCoordinate tilePoint = TileCoordinate::toGeometryCoordinate(UnwrappedTileID(0, tileID), coordinate.p);
+ layer.features.emplace_back(id, FeatureType::Point, GeometryCollection {{ {{ tilePoint }} }}, featureProperties);
}
} // namespace mbgl
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp
index 2a04fcc18e..23b28a15df 100644
--- a/src/mbgl/gl/context.cpp
+++ b/src/mbgl/gl/context.cpp
@@ -1,3 +1,4 @@
+#include <mbgl/map/view.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/vertex_array.hpp>
@@ -142,6 +143,113 @@ UniqueFramebuffer Context::createFramebuffer() {
return UniqueFramebuffer{ std::move(id), { this } };
}
+UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type,
+ const uint16_t width,
+ const uint16_t height) {
+ RenderbufferID id = 0;
+ MBGL_CHECK_ERROR(glGenRenderbuffers(1, &id));
+ UniqueRenderbuffer renderbuffer{ std::move(id), { this } };
+
+ bindRenderbuffer = renderbuffer;
+ MBGL_CHECK_ERROR(
+ glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), width, height));
+ return renderbuffer;
+}
+
+namespace {
+
+void checkFramebuffer() {
+ GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER));
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ switch (status) {
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+ throw std::runtime_error("Couldn't create framebuffer: incomplete attachment");
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+ throw std::runtime_error("Couldn't create framebuffer: incomplete missing attachment");
+#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
+ case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
+ throw std::runtime_error("Couldn't create framebuffer: incomplete draw buffer");
+#endif
+#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
+ case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
+ throw std::runtime_error("Couldn't create framebuffer: incomplete read buffer");
+#endif
+#ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
+ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+ throw std::runtime_error("Couldn't create framebuffer: incomplete dimensions");
+#endif
+
+ case GL_FRAMEBUFFER_UNSUPPORTED:
+ throw std::runtime_error("Couldn't create framebuffer: unsupported");
+ default:
+ throw std::runtime_error("Couldn't create framebuffer: other");
+ }
+ }
+}
+
+void bindDepthStencilRenderbuffer(
+ const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) {
+#ifdef GL_DEPTH_STENCIL_ATTACHMENT
+ MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, depthStencil.renderbuffer));
+#else
+ MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
+ depthStencil.renderbuffer));
+ MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, depthStencil.renderbuffer));
+#endif
+}
+
+} // namespace
+
+Framebuffer
+Context::createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>& color,
+ const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) {
+ if (color.size != depthStencil.size) {
+ throw new std::runtime_error("Renderbuffer size mismatch");
+ }
+ auto fbo = createFramebuffer();
+ bindFramebuffer = fbo;
+ MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_RENDERBUFFER, color.renderbuffer));
+ bindDepthStencilRenderbuffer(depthStencil);
+ checkFramebuffer();
+ return { color.size, std::move(fbo) };
+}
+
+Framebuffer Context::createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>& color) {
+ auto fbo = createFramebuffer();
+ bindFramebuffer = fbo;
+ MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_RENDERBUFFER, color.renderbuffer));
+ checkFramebuffer();
+ return { color.size, std::move(fbo) };
+}
+
+Framebuffer
+Context::createFramebuffer(const Texture& color,
+ const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) {
+ if (color.size != depthStencil.size) {
+ throw new std::runtime_error("Renderbuffer size mismatch");
+ }
+ auto fbo = createFramebuffer();
+ bindFramebuffer = fbo;
+ MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ color.texture, 0));
+ bindDepthStencilRenderbuffer(depthStencil);
+ checkFramebuffer();
+ return { color.size, std::move(fbo) };
+}
+
+Framebuffer Context::createFramebuffer(const Texture& color) {
+ auto fbo = createFramebuffer();
+ bindFramebuffer = fbo;
+ MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ color.texture, 0));
+ checkFramebuffer();
+ return { color.size, std::move(fbo) };
+}
+
UniqueTexture
Context::createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit unit) {
auto obj = createTexture();
@@ -186,50 +294,37 @@ void Context::reset() {
performCleanup();
}
-namespace {
-
-template <typename Fn>
-void applyStateFunction(Context& context, Fn&& fn) {
- fn(context.stencilFunc);
- fn(context.stencilMask);
- fn(context.stencilTest);
- fn(context.stencilOp);
- fn(context.depthRange);
- fn(context.depthMask);
- fn(context.depthTest);
- fn(context.depthFunc);
- fn(context.blend);
- fn(context.blendFunc);
- fn(context.blendColor);
- fn(context.colorMask);
- fn(context.clearDepth);
- fn(context.clearColor);
- fn(context.clearStencil);
- fn(context.program);
- fn(context.lineWidth);
- fn(context.activeTexture);
- fn(context.bindFramebuffer);
- fn(context.viewport);
+void Context::setDirtyState() {
+ // Note: does not set viewport/bindFramebuffer to dirty since they are handled separately in
+ // the view object.
+ stencilFunc.setDirty();
+ stencilMask.setDirty();
+ stencilTest.setDirty();
+ stencilOp.setDirty();
+ depthRange.setDirty();
+ depthMask.setDirty();
+ depthTest.setDirty();
+ depthFunc.setDirty();
+ blend.setDirty();
+ blendFunc.setDirty();
+ blendColor.setDirty();
+ colorMask.setDirty();
+ clearDepth.setDirty();
+ clearColor.setDirty();
+ clearStencil.setDirty();
+ program.setDirty();
+ lineWidth.setDirty();
+ activeTexture.setDirty();
#if not MBGL_USE_GLES2
- fn(context.pixelZoom);
- fn(context.rasterPos);
+ pixelZoom.setDirty();
+ rasterPos.setDirty();
#endif // MBGL_USE_GLES2
- for (auto& tex : context.texture) {
- fn(tex);
+ for (auto& tex : texture) {
+ tex.setDirty();
}
- fn(context.vertexBuffer);
- fn(context.elementBuffer);
- fn(context.vertexArrayObject);
-}
-
-} // namespace
-
-void Context::resetState() {
- applyStateFunction(*this, [](auto& state) { state.reset(); });
-}
-
-void Context::setDirtyState() {
- applyStateFunction(*this, [](auto& state) { state.setDirty(); });
+ vertexBuffer.setDirty();
+ elementBuffer.setDirty();
+ vertexArrayObject.setDirty();
}
void Context::performCleanup() {
@@ -289,6 +384,12 @@ void Context::performCleanup() {
glDeleteFramebuffers(int(abandonedFramebuffers.size()), abandonedFramebuffers.data()));
abandonedFramebuffers.clear();
}
+
+ if (!abandonedRenderbuffers.empty()) {
+ MBGL_CHECK_ERROR(glDeleteRenderbuffers(int(abandonedRenderbuffers.size()),
+ abandonedRenderbuffers.data()));
+ abandonedRenderbuffers.clear();
+ }
}
} // namespace gl
diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp
index 6a5d44793a..cf8bb2658b 100644
--- a/src/mbgl/gl/context.hpp
+++ b/src/mbgl/gl/context.hpp
@@ -4,6 +4,8 @@
#include <mbgl/gl/state.hpp>
#include <mbgl/gl/value.hpp>
#include <mbgl/gl/texture.hpp>
+#include <mbgl/gl/renderbuffer.hpp>
+#include <mbgl/gl/framebuffer.hpp>
#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/gl/index_buffer.hpp>
#include <mbgl/gl/attribute.hpp>
@@ -14,6 +16,9 @@
#include <array>
namespace mbgl {
+
+class View;
+
namespace gl {
constexpr size_t TextureMax = 64;
@@ -27,7 +32,6 @@ public:
UniqueShader createFragmentShader();
UniqueTexture createTexture();
UniqueVertexArray createVertexArray();
- UniqueFramebuffer createFramebuffer();
template <class V>
VertexBuffer<V> createVertexBuffer(std::vector<V>&& v) {
@@ -44,6 +48,20 @@ public:
};
}
+ template <RenderbufferType type>
+ Renderbuffer<type> createRenderbuffer(const std::array<uint16_t, 2>& size) {
+ static_assert(type == RenderbufferType::RGBA || type == RenderbufferType::DepthStencil,
+ "invalid renderbuffer type");
+ return { size, createRenderbuffer(type, size[0], size[1]) };
+ }
+
+ Framebuffer createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>&,
+ const Renderbuffer<RenderbufferType::DepthStencil>&);
+ Framebuffer createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>&);
+ Framebuffer createFramebuffer(const Texture&,
+ const Renderbuffer<RenderbufferType::DepthStencil>&);
+ Framebuffer createFramebuffer(const Texture&);
+
// Create a texture from an image with data.
template <typename Image>
Texture createTexture(const Image& image, TextureUnit unit = 0) {
@@ -87,8 +105,6 @@ public:
&& abandonedFramebuffers.empty();
}
- void resetState();
-
void setDirtyState();
State<value::StencilFunc> stencilFunc;
@@ -111,6 +127,7 @@ public:
State<value::ActiveTexture> activeTexture;
State<value::BindFramebuffer> bindFramebuffer;
State<value::Viewport> viewport;
+ State<value::BindRenderbuffer> bindRenderbuffer;
#if not MBGL_USE_GLES2
State<value::PixelZoom> pixelZoom;
State<value::RasterPos> rasterPos;
@@ -124,6 +141,8 @@ private:
UniqueBuffer createVertexBuffer(const void* data, std::size_t size);
UniqueBuffer createIndexBuffer(const void* data, std::size_t size);
UniqueTexture createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit);
+ UniqueFramebuffer createFramebuffer();
+ UniqueRenderbuffer createRenderbuffer(RenderbufferType, uint16_t width, uint16_t height);
void bindAttribute(const AttributeBinding&, std::size_t stride, const int8_t* offset);
friend detail::ProgramDeleter;
@@ -132,6 +151,7 @@ private:
friend detail::TextureDeleter;
friend detail::VertexArrayDeleter;
friend detail::FramebufferDeleter;
+ friend detail::RenderbufferDeleter;
std::vector<TextureID> pooledTextures;
@@ -141,6 +161,7 @@ private:
std::vector<TextureID> abandonedTextures;
std::vector<VertexArrayID> abandonedVertexArrays;
std::vector<FramebufferID> abandonedFramebuffers;
+ std::vector<RenderbufferID> abandonedRenderbuffers;
};
} // namespace gl
diff --git a/src/mbgl/gl/framebuffer.hpp b/src/mbgl/gl/framebuffer.hpp
new file mode 100644
index 0000000000..880fed159e
--- /dev/null
+++ b/src/mbgl/gl/framebuffer.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <mbgl/gl/object.hpp>
+
+#include <array>
+
+namespace mbgl {
+namespace gl {
+
+class Framebuffer {
+public:
+ std::array<uint16_t, 2> size;
+ gl::UniqueFramebuffer framebuffer;
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/gl.cpp b/src/mbgl/gl/gl.cpp
index 5cef254160..8999468dbd 100644
--- a/src/mbgl/gl/gl.cpp
+++ b/src/mbgl/gl/gl.cpp
@@ -51,6 +51,7 @@ constexpr const char* stringFromError(GLenum err) {
} // namespace
void checkError(const char* cmd, const char* file, int line) {
+// fprintf(stderr, "cmd: %s\n", cmd);
GLenum err = GL_NO_ERROR;
if ((err = glGetError()) != GL_NO_ERROR) {
std::string message = std::string(cmd) + ": Error " + stringFromError(err);
diff --git a/src/mbgl/gl/object.cpp b/src/mbgl/gl/object.cpp
index aee87f8836..e2d476e0c0 100644
--- a/src/mbgl/gl/object.cpp
+++ b/src/mbgl/gl/object.cpp
@@ -41,6 +41,11 @@ void FramebufferDeleter::operator()(FramebufferID id) const {
context->abandonedFramebuffers.push_back(id);
}
+void RenderbufferDeleter::operator()(RenderbufferID id) const {
+ assert(context);
+ context->abandonedRenderbuffers.push_back(id);
+}
+
} // namespace detail
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/object.hpp b/src/mbgl/gl/object.hpp
index 1cc1f04a97..1408add65a 100644
--- a/src/mbgl/gl/object.hpp
+++ b/src/mbgl/gl/object.hpp
@@ -41,6 +41,11 @@ struct FramebufferDeleter {
void operator()(FramebufferID) const;
};
+struct RenderbufferDeleter {
+ Context* context;
+ void operator()(RenderbufferID) const;
+};
+
} // namespace detail
using UniqueProgram = std_experimental::unique_resource<ProgramID, detail::ProgramDeleter>;
@@ -49,6 +54,7 @@ using UniqueBuffer = std_experimental::unique_resource<BufferID, detail::BufferD
using UniqueTexture = std_experimental::unique_resource<TextureID, detail::TextureDeleter>;
using UniqueVertexArray = std_experimental::unique_resource<VertexArrayID, detail::VertexArrayDeleter>;
using UniqueFramebuffer = std_experimental::unique_resource<FramebufferID, detail::FramebufferDeleter>;
+using UniqueRenderbuffer = std_experimental::unique_resource<RenderbufferID, detail::RenderbufferDeleter>;
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/renderbuffer.hpp b/src/mbgl/gl/renderbuffer.hpp
new file mode 100644
index 0000000000..9e8993bb77
--- /dev/null
+++ b/src/mbgl/gl/renderbuffer.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <mbgl/gl/object.hpp>
+
+#include <array>
+
+namespace mbgl {
+namespace gl {
+
+template <RenderbufferType renderbufferType>
+class Renderbuffer {
+public:
+ using type = std::integral_constant<RenderbufferType, renderbufferType>;
+ std::array<uint16_t, 2> size;
+ gl::UniqueRenderbuffer renderbuffer;
+};
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/state.hpp b/src/mbgl/gl/state.hpp
index dbb005e77d..efe869e5b9 100644
--- a/src/mbgl/gl/state.hpp
+++ b/src/mbgl/gl/state.hpp
@@ -3,20 +3,6 @@
namespace mbgl {
namespace gl {
-// Helper struct that allows obtaining the default value of a Value class
-template <typename T, typename = void>
-struct DefaultValue {
- static typename T::Type Get() {
- return T::Get();
- }
-};
-template <typename T>
-struct DefaultValue<T, decltype((void)T::Default, void())> {
- static typename T::Type Get() {
- return T::Default;
- }
-};
-
// Wraps a piece of OpenGL state and remember its value to avoid redundant state calls.
// Wrapped types need to implement to the Value class interface:
//
@@ -26,17 +12,12 @@ struct DefaultValue<T, decltype((void)T::Default, void())> {
// static void Set(const Type& value);
// static Type Get();
// };
-//
-// The Get() function is optional, but if it is omitted, you must provide a Default.
-// Default is also optional, but if it is omitted, you must provide a Get() function.
-// If both are present, DefaultValue<T>::Get() will use the Default member.
template <typename T>
class State {
public:
void operator=(const typename T::Type& value) {
if (*this != value) {
- dirty = false;
- currentValue = value;
+ setCurrentValue(value);
T::Set(currentValue);
}
}
@@ -49,9 +30,9 @@ public:
return dirty || currentValue != value;
}
- // Explicitly resets the piece of OpenGL state to its default value.
- void reset() {
- *this = defaultValue;
+ void setCurrentValue(const typename T::Type& value) {
+ dirty = false;
+ currentValue = value;
}
// Mark the state as dirty. This means that the next time we are assigning a value to this
@@ -68,14 +49,9 @@ public:
return dirty;
}
- void setDefaultValue(const typename T::Type& value) {
- defaultValue = value;
- }
-
private:
- typename T::Type defaultValue = DefaultValue<T>::Get();
- typename T::Type currentValue = defaultValue;
- bool dirty = false;
+ typename T::Type currentValue = T::Default;
+ bool dirty = true;
};
// Helper struct that stores the current state and restores it upon destruction. You should not use
diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp
index f24674457a..dccc61b03a 100644
--- a/src/mbgl/gl/types.hpp
+++ b/src/mbgl/gl/types.hpp
@@ -48,6 +48,11 @@ enum class BufferType : uint32_t {
Element = 0x8893
};
+enum class RenderbufferType : uint32_t {
+ RGBA = 0x8058,
+ DepthStencil = 0x88F0,
+};
+
enum class TextureMipMap : bool { No = false, Yes = true };
enum class TextureFilter : bool { Nearest = false, Linear = true };
diff --git a/src/mbgl/gl/value.cpp b/src/mbgl/gl/value.cpp
index e78b97ef2e..14cd03efc4 100644
--- a/src/mbgl/gl/value.cpp
+++ b/src/mbgl/gl/value.cpp
@@ -241,6 +241,8 @@ ActiveTexture::Type ActiveTexture::Get() {
return static_cast<Type>(activeTexture - GL_TEXTURE0);
}
+const constexpr Viewport::Type Viewport::Default;
+
void Viewport::Set(const Type& value) {
MBGL_CHECK_ERROR(glViewport(value.x, value.y, value.width, value.height));
}
@@ -252,6 +254,8 @@ Viewport::Type Viewport::Get() {
static_cast<uint16_t>(viewport[2]), static_cast<uint16_t>(viewport[3]) };
}
+const constexpr BindFramebuffer::Type BindFramebuffer::Default;
+
void BindFramebuffer::Set(const Type& value) {
MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, value));
}
@@ -262,6 +266,18 @@ BindFramebuffer::Type BindFramebuffer::Get() {
return binding;
}
+const constexpr BindRenderbuffer::Type BindRenderbuffer::Default;
+
+void BindRenderbuffer::Set(const Type& value) {
+ MBGL_CHECK_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, value));
+}
+
+BindRenderbuffer::Type BindRenderbuffer::Get() {
+ GLint binding;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_RENDERBUFFER_BINDING, &binding));
+ return binding;
+}
+
const constexpr BindTexture::Type BindTexture::Default;
void BindTexture::Set(const Type& value) {
diff --git a/src/mbgl/gl/value.hpp b/src/mbgl/gl/value.hpp
index 9110b33a16..866ce389a4 100644
--- a/src/mbgl/gl/value.hpp
+++ b/src/mbgl/gl/value.hpp
@@ -180,6 +180,7 @@ struct Viewport {
uint16_t width;
uint16_t height;
};
+ static const constexpr Type Default = { 0, 0, 0, 0 };
static void Set(const Type&);
static Type Get();
};
@@ -190,6 +191,14 @@ constexpr bool operator!=(const Viewport::Type& a, const Viewport::Type& b) {
struct BindFramebuffer {
using Type = FramebufferID;
+ static const constexpr Type Default = 0;
+ static void Set(const Type&);
+ static Type Get();
+};
+
+struct BindRenderbuffer {
+ using Type = RenderbufferID;
+ static const constexpr Type Default = 0;
static void Set(const Type&);
static Type Get();
};
diff --git a/src/mbgl/map/backend.cpp b/src/mbgl/map/backend.cpp
new file mode 100644
index 0000000000..8a06fe2d91
--- /dev/null
+++ b/src/mbgl/map/backend.cpp
@@ -0,0 +1,22 @@
+#include <mbgl/map/backend.hpp>
+#include <mbgl/gl/context.hpp>
+
+#include <cassert>
+
+namespace mbgl {
+
+Backend::Backend() : context(std::make_unique<gl::Context>()) {
+}
+
+gl::Context& Backend::getContext() {
+ return *context;
+}
+
+Backend::~Backend() = default;
+
+void Backend::notifyMapChange(MapChange) {
+ // no-op
+}
+
+
+} // namespace mbgl
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index bf2462e2ab..7b58026386 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -1,6 +1,7 @@
#include <mbgl/map/map.hpp>
#include <mbgl/map/camera.hpp>
#include <mbgl/map/view.hpp>
+#include <mbgl/map/backend.hpp>
#include <mbgl/map/transform.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
@@ -21,7 +22,7 @@
#include <mbgl/util/async_task.hpp>
#include <mbgl/util/mapbox.hpp>
#include <mbgl/util/tile_coordinate.hpp>
-#include <mbgl/actor/thread_pool.hpp>
+#include <mbgl/actor/scheduler.hpp>
#include <mbgl/platform/log.hpp>
namespace mbgl {
@@ -34,9 +35,25 @@ enum class RenderState : uint8_t {
Fully,
};
+struct StillImageRequest {
+ StillImageRequest(View& view_, Map::StillImageCallback&& callback_)
+ : view(view_), callback(std::move(callback_)) {
+ }
+
+ View& view;
+ Map::StillImageCallback callback;
+};
+
class Map::Impl : public style::Observer {
public:
- Impl(View&, FileSource&, MapMode, GLContextMode, ConstrainMode, ViewportMode);
+ Impl(Backend&,
+ float pixelRatio,
+ FileSource&,
+ Scheduler&,
+ MapMode,
+ GLContextMode,
+ ConstrainMode,
+ ViewportMode);
void onSourceAttributionChanged(style::Source&, const std::string&) override;
void onUpdate(Update) override;
@@ -45,12 +62,13 @@ public:
void onResourceError(std::exception_ptr) override;
void update();
- void render();
+ void render(View&);
void loadStyleJSON(const std::string&);
- View& view;
+ Backend& backend;
FileSource& fileSource;
+ Scheduler& scheduler;
RenderState renderState = RenderState::Never;
Transform transform;
@@ -63,7 +81,6 @@ public:
Update updateFlags = Update::Nothing;
util::AsyncTask asyncUpdate;
- ThreadPool workerThreadPool;
std::unique_ptr<AnnotationManager> annotationManager;
std::unique_ptr<Painter> painter;
@@ -75,39 +92,55 @@ public:
std::unique_ptr<AsyncRequest> styleRequest;
- Map::StillImageCallback callback;
+ std::unique_ptr<StillImageRequest> stillImageRequest;
size_t sourceCacheSize;
TimePoint timePoint;
bool loading = false;
};
-Map::Map(View& view, FileSource& fileSource, MapMode mapMode, GLContextMode contextMode, ConstrainMode constrainMode, ViewportMode viewportMode)
- : impl(std::make_unique<Impl>(view, fileSource, mapMode, contextMode, constrainMode, viewportMode)) {
- view.initialize(this);
- update(Update::Dimensions);
-}
-
-Map::Impl::Impl(View& view_,
+Map::Map(Backend& backend,
+ const std::array<uint16_t, 2> size,
+ const float pixelRatio,
+ FileSource& fileSource,
+ Scheduler& scheduler,
+ MapMode mapMode,
+ GLContextMode contextMode,
+ ConstrainMode constrainMode,
+ ViewportMode viewportMode)
+ : impl(std::make_unique<Impl>(backend,
+ pixelRatio,
+ fileSource,
+ scheduler,
+ mapMode,
+ contextMode,
+ constrainMode,
+ viewportMode)) {
+ impl->transform.resize(size);
+}
+
+Map::Impl::Impl(Backend& backend_,
+ float pixelRatio_,
FileSource& fileSource_,
+ Scheduler& scheduler_,
MapMode mode_,
GLContextMode contextMode_,
ConstrainMode constrainMode_,
ViewportMode viewportMode_)
- : view(view_),
+ : backend(backend_),
fileSource(fileSource_),
- transform([this](MapChange change) { view.notifyMapChange(change); },
+ scheduler(scheduler_),
+ transform([this](MapChange change) { backend.notifyMapChange(change); },
constrainMode_,
viewportMode_),
mode(mode_),
contextMode(contextMode_),
- pixelRatio(view.getPixelRatio()),
+ pixelRatio(pixelRatio_),
asyncUpdate([this] { update(); }),
- workerThreadPool(4),
annotationManager(std::make_unique<AnnotationManager>(pixelRatio)) {
}
Map::~Map() {
- impl->view.activate();
+ impl->backend.activate();
impl->styleRequest = nullptr;
@@ -117,60 +150,56 @@ Map::~Map() {
impl->annotationManager.reset();
impl->painter.reset();
- impl->view.deactivate();
+ impl->backend.deactivate();
}
-void Map::renderStill(StillImageCallback callback) {
+void Map::renderStill(View& view, StillImageCallback callback) {
if (!callback) {
Log::Error(Event::General, "StillImageCallback not set");
return;
}
if (impl->mode != MapMode::Still) {
- callback(std::make_exception_ptr(util::MisuseException("Map is not in still image render mode")), {});
+ callback(std::make_exception_ptr(util::MisuseException("Map is not in still image render mode")));
return;
}
- if (impl->callback) {
- callback(std::make_exception_ptr(util::MisuseException("Map is currently rendering an image")), {});
+ if (impl->stillImageRequest) {
+ callback(std::make_exception_ptr(util::MisuseException("Map is currently rendering an image")));
return;
}
if (!impl->style) {
- callback(std::make_exception_ptr(util::MisuseException("Map doesn't have a style")), {});
+ callback(std::make_exception_ptr(util::MisuseException("Map doesn't have a style")));
return;
}
if (impl->style->getLastError()) {
- callback(impl->style->getLastError(), {});
+ callback(impl->style->getLastError());
return;
}
- impl->callback = callback;
+ impl->stillImageRequest = std::make_unique<StillImageRequest>(view, std::move(callback));
impl->updateFlags |= Update::RenderStill;
impl->asyncUpdate.send();
}
-void Map::update(Update flags) {
- impl->onUpdate(flags);
-}
-
-void Map::render() {
+void Map::render(View& view) {
if (!impl->style) {
return;
}
if (impl->renderState == RenderState::Never) {
- impl->view.notifyMapChange(MapChangeWillStartRenderingMap);
+ impl->backend.notifyMapChange(MapChangeWillStartRenderingMap);
}
- impl->view.notifyMapChange(MapChangeWillStartRenderingFrame);
+ impl->backend.notifyMapChange(MapChangeWillStartRenderingFrame);
const Update flags = impl->transform.updateTransitions(Clock::now());
- impl->render();
+ impl->render(view);
- impl->view.notifyMapChange(isFullyLoaded() ?
+ impl->backend.notifyMapChange(isFullyLoaded() ?
MapChangeDidFinishRenderingFrameFullyRendered :
MapChangeDidFinishRenderingFrame);
@@ -178,26 +207,30 @@ void Map::render() {
impl->renderState = RenderState::Partial;
} else if (impl->renderState != RenderState::Fully) {
impl->renderState = RenderState::Fully;
- impl->view.notifyMapChange(MapChangeDidFinishRenderingMapFullyRendered);
+ impl->backend.notifyMapChange(MapChangeDidFinishRenderingMapFullyRendered);
if (impl->loading) {
impl->loading = false;
- impl->view.notifyMapChange(MapChangeDidFinishLoadingMap);
+ impl->backend.notifyMapChange(MapChangeDidFinishLoadingMap);
}
}
// Triggers an asynchronous update, that eventually triggers a view
// invalidation, causing renderSync to be called again if in transition.
if (flags != Update::Nothing) {
- update(flags);
+ impl->onUpdate(flags);
}
}
+void Map::triggerRepaint() {
+ impl->backend.invalidate();
+}
+
void Map::Impl::update() {
if (!style) {
updateFlags = Update::Nothing;
}
- if (updateFlags == Update::Nothing || (mode == MapMode::Still && !callback)) {
+ if (updateFlags == Update::Nothing || (mode == MapMode::Still && !stillImageRequest)) {
return;
}
@@ -230,7 +263,7 @@ void Map::Impl::update() {
style::UpdateParameters parameters(pixelRatio,
debugOptions,
transform.getState(),
- workerThreadPool,
+ scheduler,
fileSource,
mode,
*annotationManager,
@@ -239,23 +272,23 @@ void Map::Impl::update() {
style->updateTiles(parameters);
if (mode == MapMode::Continuous) {
- view.invalidate();
- } else if (callback && style->isLoaded()) {
- view.activate();
- render();
- view.deactivate();
+ backend.invalidate();
+ } else if (stillImageRequest && style->isLoaded()) {
+ // TODO: determine whether we need activate/deactivate
+ backend.activate();
+ render(stillImageRequest->view);
+ backend.deactivate();
}
updateFlags = Update::Nothing;
}
-void Map::Impl::render() {
+void Map::Impl::render(View& view) {
if (!painter) {
- painter = std::make_unique<Painter>(transform.getState());
+ painter = std::make_unique<Painter>(backend.getContext(), transform.getState());
}
- FrameData frameData { view.getFramebufferSize(),
- timePoint,
+ FrameData frameData { timePoint,
pixelRatio,
mode,
contextMode,
@@ -263,11 +296,12 @@ void Map::Impl::render() {
painter->render(*style,
frameData,
+ view,
annotationManager->getSpriteAtlas());
if (mode == MapMode::Still) {
- callback(nullptr, view.readStillImage());
- callback = nullptr;
+ auto request = std::move(stillImageRequest);
+ request->callback(nullptr);
}
painter->cleanup();
@@ -290,7 +324,7 @@ void Map::setStyleURL(const std::string& url) {
impl->loading = true;
- impl->view.notifyMapChange(MapChangeWillStartLoadingMap);
+ impl->backend.notifyMapChange(MapChangeWillStartLoadingMap);
impl->styleRequest = nullptr;
impl->styleURL = url;
@@ -334,7 +368,7 @@ void Map::setStyleJSON(const std::string& json) {
impl->loading = true;
- impl->view.notifyMapChange(MapChangeWillStartLoadingMap);
+ impl->backend.notifyMapChange(MapChangeWillStartLoadingMap);
impl->styleURL.clear();
impl->styleJSON.clear();
@@ -369,12 +403,12 @@ std::string Map::getStyleJSON() const {
void Map::cancelTransitions() {
impl->transform.cancelTransitions();
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
void Map::setGestureInProgress(bool inProgress) {
impl->transform.setGestureInProgress(inProgress);
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
bool Map::isGestureInProgress() const {
@@ -401,24 +435,24 @@ CameraOptions Map::getCameraOptions(optional<EdgeInsets> padding) const {
void Map::jumpTo(const CameraOptions& camera) {
impl->transform.jumpTo(camera);
- update(camera.zoom ? Update::RecalculateStyle : Update::Repaint);
+ impl->onUpdate(camera.zoom ? Update::RecalculateStyle : Update::Repaint);
}
void Map::easeTo(const CameraOptions& camera, const AnimationOptions& animation) {
impl->transform.easeTo(camera, animation);
- update(camera.zoom ? Update::RecalculateStyle : Update::Repaint);
+ impl->onUpdate(camera.zoom ? Update::RecalculateStyle : Update::Repaint);
}
void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation) {
impl->transform.flyTo(camera, animation);
- update(Update::RecalculateStyle);
+ impl->onUpdate(Update::RecalculateStyle);
}
#pragma mark - Position
void Map::moveBy(const ScreenCoordinate& point, const Duration& duration) {
impl->transform.moveBy(point, duration);
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
void Map::setLatLng(const LatLng& latLng, const Duration& duration) {
@@ -427,12 +461,12 @@ void Map::setLatLng(const LatLng& latLng, const Duration& duration) {
void Map::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) {
impl->transform.setLatLng(latLng, padding, duration);
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) {
impl->transform.setLatLng(latLng, anchor, duration);
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
LatLng Map::getLatLng(optional<EdgeInsets> padding) const {
@@ -447,7 +481,7 @@ void Map::resetPosition(optional<EdgeInsets> padding) {
camera.padding = padding;
camera.zoom = 0;
impl->transform.jumpTo(camera);
- update(Update::RecalculateStyle);
+ impl->onUpdate(Update::RecalculateStyle);
}
@@ -455,12 +489,12 @@ void Map::resetPosition(optional<EdgeInsets> padding) {
void Map::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) {
impl->transform.scaleBy(ds, anchor, duration);
- update(Update::RecalculateStyle);
+ impl->onUpdate(Update::RecalculateStyle);
}
void Map::setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& duration) {
impl->transform.setScale(scale, anchor, duration);
- update(Update::RecalculateStyle);
+ impl->onUpdate(Update::RecalculateStyle);
}
double Map::getScale() const {
@@ -473,7 +507,7 @@ void Map::setZoom(double zoom, const Duration& duration) {
void Map::setZoom(double zoom, optional<EdgeInsets> padding, const Duration& duration) {
impl->transform.setZoom(zoom, padding, duration);
- update(Update::RecalculateStyle);
+ impl->onUpdate(Update::RecalculateStyle);
}
double Map::getZoom() const {
@@ -486,7 +520,7 @@ void Map::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& durat
void Map::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) {
impl->transform.setLatLngZoom(latLng, zoom, padding, duration);
- update(Update::RecalculateStyle);
+ impl->onUpdate(Update::RecalculateStyle);
}
CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, optional<EdgeInsets> padding) const {
@@ -583,6 +617,11 @@ double Map::getMaxZoom() const {
#pragma mark - Size
+void Map::setSize(const std::array<uint16_t, 2>& size) {
+ impl->transform.resize(size);
+ impl->onUpdate(Update::Repaint);
+}
+
uint16_t Map::getWidth() const {
return impl->transform.getState().getWidth();
}
@@ -595,7 +634,7 @@ uint16_t Map::getHeight() const {
void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& duration) {
impl->transform.rotateBy(first, second, duration);
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
void Map::setBearing(double degrees, const Duration& duration) {
@@ -604,12 +643,12 @@ void Map::setBearing(double degrees, const Duration& duration) {
void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const Duration& duration) {
impl->transform.setAngle(-degrees * util::DEG2RAD, anchor, duration);
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
void Map::setBearing(double degrees, optional<EdgeInsets> padding, const Duration& duration) {
impl->transform.setAngle(-degrees * util::DEG2RAD, padding, duration);
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
double Map::getBearing() const {
@@ -618,7 +657,7 @@ double Map::getBearing() const {
void Map::resetNorth(const Duration& duration) {
impl->transform.setAngle(0, duration);
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
#pragma mark - Pitch
@@ -629,7 +668,7 @@ void Map::setPitch(double pitch, const Duration& duration) {
void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& duration) {
impl->transform.setPitch(pitch * util::DEG2RAD, anchor, duration);
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
double Map::getPitch() const {
@@ -640,7 +679,7 @@ double Map::getPitch() const {
void Map::setNorthOrientation(NorthOrientation orientation) {
impl->transform.setNorthOrientation(orientation);
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
NorthOrientation Map::getNorthOrientation() const {
@@ -651,7 +690,7 @@ NorthOrientation Map::getNorthOrientation() const {
void Map::setConstrainMode(mbgl::ConstrainMode mode) {
impl->transform.setConstrainMode(mode);
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
ConstrainMode Map::getConstrainMode() const {
@@ -662,7 +701,7 @@ ConstrainMode Map::getConstrainMode() const {
void Map::setViewportMode(mbgl::ViewportMode mode) {
impl->transform.setViewportMode(mode);
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
ViewportMode Map::getViewportMode() const {
@@ -707,17 +746,17 @@ double Map::getTopOffsetPixelsForAnnotationIcon(const std::string& name) {
AnnotationID Map::addAnnotation(const Annotation& annotation) {
auto result = impl->annotationManager->addAnnotation(annotation, getMaxZoom());
- update(Update::AnnotationStyle | Update::AnnotationData);
+ impl->onUpdate(Update::AnnotationStyle | Update::AnnotationData);
return result;
}
void Map::updateAnnotation(AnnotationID id, const Annotation& annotation) {
- update(impl->annotationManager->updateAnnotation(id, annotation, getMaxZoom()));
+ impl->onUpdate(impl->annotationManager->updateAnnotation(id, annotation, getMaxZoom()));
}
void Map::removeAnnotation(AnnotationID annotation) {
impl->annotationManager->removeAnnotation(annotation);
- update(Update::AnnotationStyle | Update::AnnotationData);
+ impl->onUpdate(Update::AnnotationStyle | Update::AnnotationData);
}
#pragma mark - Feature query api
@@ -800,12 +839,12 @@ void Map::addLayer(std::unique_ptr<Layer> layer, const optional<std::string>& be
}
impl->styleMutated = true;
- impl->view.activate();
+ impl->backend.activate();
impl->style->addLayer(std::move(layer), before);
- update(Update::Classes);
+ impl->onUpdate(Update::Classes);
- impl->view.deactivate();
+ impl->backend.deactivate();
}
void Map::removeLayer(const std::string& id) {
@@ -814,12 +853,12 @@ void Map::removeLayer(const std::string& id) {
}
impl->styleMutated = true;
- impl->view.activate();
+ impl->backend.activate();
impl->style->removeLayer(id);
- update(Update::Classes);
+ impl->onUpdate(Update::Classes);
- impl->view.deactivate();
+ impl->backend.deactivate();
}
void Map::addImage(const std::string& name, std::unique_ptr<const SpriteImage> image) {
@@ -831,7 +870,7 @@ void Map::addImage(const std::string& name, std::unique_ptr<const SpriteImage> i
impl->style->spriteAtlas->setSprite(name, std::move(image));
impl->style->spriteAtlas->updateDirty();
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
void Map::removeImage(const std::string& name) {
@@ -843,7 +882,7 @@ void Map::removeImage(const std::string& name) {
impl->style->spriteAtlas->removeSprite(name);
impl->style->spriteAtlas->updateDirty();
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
#pragma mark - Defaults
@@ -887,7 +926,7 @@ double Map::getDefaultPitch() const {
void Map::setDebug(MapDebugOptions debugOptions) {
impl->debugOptions = debugOptions;
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
void Map::cycleDebugOptions() {
@@ -911,7 +950,7 @@ void Map::cycleDebugOptions() {
else
impl->debugOptions = MapDebugOptions::TileBorders;
- update(Update::Repaint);
+ impl->onUpdate(Update::Repaint);
}
MapDebugOptions Map::getDebug() const {
@@ -924,20 +963,20 @@ bool Map::isFullyLoaded() const {
void Map::addClass(const std::string& className) {
if (impl->style && impl->style->addClass(className)) {
- update(Update::Classes);
+ impl->onUpdate(Update::Classes);
}
}
void Map::removeClass(const std::string& className) {
if (impl->style && impl->style->removeClass(className)) {
- update(Update::Classes);
+ impl->onUpdate(Update::Classes);
}
}
void Map::setClasses(const std::vector<std::string>& classNames) {
if (impl->style) {
impl->style->setClasses(classNames);
- update(Update::Classes);
+ impl->onUpdate(Update::Classes);
}
}
@@ -970,7 +1009,7 @@ void Map::setSourceTileCacheSize(size_t size) {
impl->sourceCacheSize = size;
if (!impl->style) return;
impl->style->setSourceTileCacheSize(size);
- impl->view.invalidate();
+ impl->backend.invalidate();
}
}
@@ -980,35 +1019,31 @@ void Map::onLowMemory() {
}
if (impl->style) {
impl->style->onLowMemory();
- impl->view.invalidate();
+ impl->backend.invalidate();
}
}
void Map::Impl::onSourceAttributionChanged(style::Source&, const std::string&) {
- view.notifyMapChange(MapChangeSourceDidChange);
+ backend.notifyMapChange(MapChangeSourceDidChange);
}
void Map::Impl::onUpdate(Update flags) {
- if (flags & Update::Dimensions) {
- transform.resize(view.getSize());
- }
-
updateFlags |= flags;
asyncUpdate.send();
}
void Map::Impl::onStyleLoaded() {
- view.notifyMapChange(MapChangeDidFinishLoadingStyle);
+ backend.notifyMapChange(MapChangeDidFinishLoadingStyle);
}
void Map::Impl::onStyleError() {
- view.notifyMapChange(MapChangeDidFailLoadingMap);
+ backend.notifyMapChange(MapChangeDidFailLoadingMap);
}
void Map::Impl::onResourceError(std::exception_ptr error) {
- if (mode == MapMode::Still && callback) {
- callback(error, {});
- callback = nullptr;
+ if (mode == MapMode::Still && stillImageRequest) {
+ auto request = std::move(stillImageRequest);
+ request->callback(error);
}
}
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index 41fc36ce27..85805a109d 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -7,6 +7,7 @@
#include <mbgl/util/unitbezier.hpp>
#include <mbgl/util/interpolate.hpp>
#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/projection.hpp>
#include <mbgl/math/clamp.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/platform/platform.hpp>
@@ -112,8 +113,8 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
// Find the shortest path otherwise.
else startLatLng.unwrapForShortestPath(latLng);
- const Point<double> startPoint = state.project(startLatLng);
- const Point<double> endPoint = state.project(latLng);
+ const Point<double> startPoint = Projection::project(startLatLng, state.scale);
+ const Point<double> endPoint = Projection::project(latLng, state.scale);
ScreenCoordinate center = getScreenCoordinate(padding);
center.y = state.height - center.y;
@@ -131,10 +132,6 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
Duration duration = animation.duration ? *animation.duration : Duration::zero();
- const double startWorldSize = state.worldSize();
- state.Bc = startWorldSize / util::DEGREES_MAX;
- state.Cc = startWorldSize / util::M2PI;
-
const double startScale = state.scale;
const double startAngle = state.angle;
const double startPitch = state.pitch;
@@ -144,7 +141,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
startTransition(camera, animation, [=](double t) {
Point<double> framePoint = util::interpolate(startPoint, endPoint, t);
- LatLng frameLatLng = state.unproject(framePoint, startWorldSize);
+ LatLng frameLatLng = Projection::unproject(framePoint, startScale);
double frameScale = util::interpolate(startScale, scale, t);
state.setLatLngZoom(frameLatLng, state.scaleZoom(frameScale));
@@ -186,8 +183,8 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
LatLng startLatLng = getLatLng(padding).wrapped();
startLatLng.unwrapForShortestPath(latLng);
- const Point<double> startPoint = state.project(startLatLng);
- const Point<double> endPoint = state.project(latLng);
+ const Point<double> startPoint = Projection::project(startLatLng, state.scale);
+ const Point<double> endPoint = Projection::project(latLng, state.scale);
ScreenCoordinate center = getScreenCoordinate(padding);
center.y = state.height - center.y;
@@ -291,10 +288,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
return;
}
- const double startWorldSize = state.worldSize();
- state.Bc = startWorldSize / util::DEGREES_MAX;
- state.Cc = startWorldSize / util::M2PI;
-
+ const double startScale = state.scale;
state.panning = true;
state.scaling = true;
state.rotating = angle != startAngle;
@@ -310,7 +304,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
double frameZoom = startZoom + state.scaleZoom(1 / w(s));
// Convert to geographic coordinates and set the new viewpoint.
- LatLng frameLatLng = state.unproject(framePoint, startWorldSize);
+ LatLng frameLatLng = Projection::unproject(framePoint, startScale);
state.setLatLngZoom(frameLatLng, frameZoom);
if (angle != startAngle) {
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index eb66513626..4f6bcecdb6 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -17,7 +17,7 @@ TransformState::TransformState(ConstrainMode constrainMode_, ViewportMode viewpo
void TransformState::matrixFor(mat4& matrix, const UnwrappedTileID& tileID) const {
const uint64_t tileScale = 1ull << tileID.canonical.z;
- const double s = worldSize() / tileScale;
+ const double s = Projection::worldSize(scale) / tileScale;
matrix::identity(matrix);
matrix::translate(matrix, matrix,
@@ -108,12 +108,12 @@ LatLng TransformState::getLatLng(LatLng::WrapMode wrapMode) const {
}
double TransformState::pixel_x() const {
- const double center = (width - worldSize()) / 2;
+ const double center = (width - Projection::worldSize(scale)) / 2;
return center + x;
}
double TransformState::pixel_y() const {
- const double center = (height - worldSize()) / 2;
+ const double center = (height - Projection::worldSize(scale)) / 2;
return center + y;
}
@@ -201,22 +201,6 @@ bool TransformState::isGestureInProgress() const {
#pragma mark - Projection
-Point<double> TransformState::project(const LatLng& ll) const {
- return Point<double>(
- (util::LONGITUDE_MAX + ll.longitude),
- (util::LONGITUDE_MAX - util::RAD2DEG * std::log(std::tan(M_PI / 4 + ll.latitude * M_PI / util::DEGREES_MAX)))
- ) * worldSize() / util::DEGREES_MAX;
-}
-
-LatLng TransformState::unproject(const Point<double>& p, double worldSize, LatLng::WrapMode wrapMode) const {
- Point<double> p2 = p * util::DEGREES_MAX / worldSize;
- return LatLng(
- util::DEGREES_MAX / M_PI * std::atan(std::exp((util::LONGITUDE_MAX - p2.y) * util::DEG2RAD)) - 90.0f,
- p2.x - util::LONGITUDE_MAX,
- wrapMode
- );
-}
-
double TransformState::zoomScale(double zoom) const {
return std::pow(2.0f, zoom);
}
@@ -225,10 +209,6 @@ double TransformState::scaleZoom(double s) const {
return util::log2(s);
}
-double TransformState::worldSize() const {
- return scale * util::tileSize;
-}
-
ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng) const {
if (width == 0 || height == 0) {
return {};
@@ -236,7 +216,7 @@ ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng)
mat4 mat = coordinatePointMatrix(getZoom());
vec4 p;
- Point<double> pt = project(latLng) / double(util::tileSize);
+ Point<double> pt = Projection::project(latLng, scale) / double(util::tileSize);
vec4 c = {{ pt.x, pt.y, 0, 1 }};
matrix::transformMat4(p, c, mat);
return { p[0] / p[3], height - p[1] / p[3] };
@@ -278,13 +258,13 @@ LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, L
double z1 = coord1[2] / w1;
double t = z0 == z1 ? 0 : (targetZ - z0) / (z1 - z0);
- return unproject(util::interpolate(p0, p1, t), scale, wrapMode);
+ return Projection::unproject(util::interpolate(p0, p1, t), scale / util::tileSize, wrapMode);
}
mat4 TransformState::coordinatePointMatrix(double z) const {
mat4 proj;
getProjMatrix(proj);
- float s = worldSize() / std::pow(2, z);
+ float s = Projection::worldSize(scale) / std::pow(2, z);
matrix::scale(proj, proj, s, s, 1);
matrix::multiply(proj, getPixelMatrix(), proj);
return proj;
@@ -325,10 +305,10 @@ void TransformState::constrain(double& scale_, double& x_, double& y_) const {
}
void TransformState::moveLatLng(const LatLng& latLng, const ScreenCoordinate& anchor) {
- auto centerCoord = project(getLatLng(LatLng::Unwrapped));
- auto latLngCoord = project(latLng);
- auto anchorCoord = project(screenCoordinateToLatLng(anchor));
- setLatLngZoom(unproject(centerCoord + latLngCoord - anchorCoord, worldSize()), getZoom());
+ auto centerCoord = Projection::project(getLatLng(LatLng::Unwrapped), scale);
+ auto latLngCoord = Projection::project(latLng, scale);
+ auto anchorCoord = Projection::project(screenCoordinateToLatLng(anchor), scale);
+ setLatLngZoom(Projection::unproject(centerCoord + latLngCoord - anchorCoord, scale), getZoom());
}
void TransformState::setLatLngZoom(const LatLng &latLng, double zoom) {
@@ -355,8 +335,8 @@ void TransformState::setScalePoint(const double newScale, const ScreenCoordinate
scale = constrainedScale;
x = constrainedPoint.x;
y = constrainedPoint.y;
- Bc = worldSize() / util::DEGREES_MAX;
- Cc = worldSize() / util::M2PI;
+ Bc = Projection::worldSize(scale) / util::DEGREES_MAX;
+ Cc = Projection::worldSize(scale) / util::M2PI;
}
} // namespace mbgl
diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp
index 1e4b2054f7..8a12b62a9e 100644
--- a/src/mbgl/map/transform_state.hpp
+++ b/src/mbgl/map/transform_state.hpp
@@ -4,6 +4,7 @@
#include <mbgl/util/geo.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/constants.hpp>
+#include <mbgl/util/projection.hpp>
#include <mbgl/util/mat4.hpp>
#include <cstdint>
@@ -65,13 +66,10 @@ public:
bool isPanning() const;
bool isGestureInProgress() const;
- // Conversion and projection
+ // Conversion
ScreenCoordinate latLngToScreenCoordinate(const LatLng&) const;
LatLng screenCoordinateToLatLng(const ScreenCoordinate&, LatLng::WrapMode = LatLng::Unwrapped) const;
- Point<double> project(const LatLng&) const;
- LatLng unproject(const Point<double>&, double worldSize, LatLng::WrapMode = LatLng::Unwrapped) const;
-
double zoomScale(double zoom) const;
double scaleZoom(double scale) const;
@@ -88,8 +86,6 @@ private:
// logical dimensions
uint16_t width = 0, height = 0;
- double worldSize() const;
-
mat4 coordinatePointMatrix(double z) const;
mat4 getPixelMatrix() const;
@@ -117,8 +113,8 @@ private:
double pitch = 0.0;
// cache values for spherical mercator math
- double Bc = worldSize() / util::DEGREES_MAX;
- double Cc = worldSize() / util::M2PI;
+ double Bc = Projection::worldSize(scale) / util::DEGREES_MAX;
+ double Cc = Projection::worldSize(scale) / util::M2PI;
};
} // namespace mbgl
diff --git a/src/mbgl/map/update.hpp b/src/mbgl/map/update.hpp
new file mode 100644
index 0000000000..dc383b819e
--- /dev/null
+++ b/src/mbgl/map/update.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <mbgl/util/traits.hpp>
+
+namespace mbgl {
+
+enum class Update {
+ Nothing = 0,
+ Classes = 1 << 2,
+ RecalculateStyle = 1 << 3,
+ RenderStill = 1 << 4,
+ Repaint = 1 << 5,
+ AnnotationStyle = 1 << 6,
+ AnnotationData = 1 << 7,
+ Layout = 1 << 8
+};
+
+constexpr Update operator|(Update lhs, Update rhs) {
+ return Update(mbgl::underlying_type(lhs) | mbgl::underlying_type(rhs));
+}
+
+constexpr Update& operator|=(Update& lhs, const Update& rhs) {
+ return (lhs = lhs | rhs);
+}
+
+constexpr bool operator& (Update lhs, Update rhs) {
+ return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs);
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/map/view.cpp b/src/mbgl/map/view.cpp
deleted file mode 100644
index 8541753c7a..0000000000
--- a/src/mbgl/map/view.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#include <mbgl/map/view.hpp>
-#include <mbgl/map/map.hpp>
-
-#include <cassert>
-
-namespace mbgl {
-
-void View::initialize(Map *map_) {
- assert(map_);
- map = map_;
-}
-
-PremultipliedImage View::readStillImage(std::array<uint16_t, 2>) {
- return {};
-}
-
-void View::notifyMapChange(MapChange) {
- // no-op
-}
-
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp
index 13bf21080d..bd67dc9cfd 100644
--- a/src/mbgl/renderer/paint_parameters.hpp
+++ b/src/mbgl/renderer/paint_parameters.hpp
@@ -3,10 +3,12 @@
namespace mbgl {
class Shaders;
+class View;
class PaintParameters {
public:
Shaders& shaders;
+ View& view;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index ad0e75cd92..fc61d6e0a0 100644
--- a/src/mbgl/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -5,6 +5,8 @@
#include <mbgl/style/source.hpp>
#include <mbgl/style/source_impl.hpp>
+#include <mbgl/map/view.hpp>
+
#include <mbgl/platform/log.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/debugging.hpp>
@@ -29,6 +31,8 @@
#include <mbgl/util/mat3.hpp>
#include <mbgl/util/string.hpp>
+#include <mbgl/util/offscreen_texture.hpp>
+
#include <cassert>
#include <algorithm>
#include <iostream>
@@ -38,8 +42,9 @@ namespace mbgl {
using namespace style;
-Painter::Painter(const TransformState& state_)
- : state(state_),
+Painter::Painter(gl::Context& context_, const TransformState& state_)
+ : context(context_),
+ state(state_),
tileTriangleVertexBuffer(context.createVertexBuffer(std::vector<FillVertex> {{
{ 0, 0 },
{ util::EXTENT, 0 },
@@ -69,9 +74,6 @@ Painter::Painter(const TransformState& state_)
#ifndef NDEBUG
overdrawShaders = std::make_unique<Shaders>(context, gl::Shader::Overdraw);
#endif
-
- // Reset GL values
- context.setDirtyState();
}
Painter::~Painter() = default;
@@ -90,19 +92,19 @@ void Painter::cleanup() {
context.performCleanup();
}
-void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& annotationSpriteAtlas) {
- if (frame.framebufferSize != frame_.framebufferSize) {
- context.viewport.setDefaultValue(
- { 0, 0, frame_.framebufferSize[0], frame_.framebufferSize[1] });
- }
+void Painter::render(const Style& style, const FrameData& frame_, View& view, SpriteAtlas& annotationSpriteAtlas) {
frame = frame_;
+ if (frame.contextMode == GLContextMode::Shared) {
+ context.setDirtyState();
+ }
PaintParameters parameters {
#ifndef NDEBUG
- paintMode() == PaintMode::Overdraw ? *overdrawShaders : *shaders
+ paintMode() == PaintMode::Overdraw ? *overdrawShaders : *shaders,
#else
- *shaders
+ *shaders,
#endif
+ view
};
glyphAtlas = style.glyphAtlas.get();
@@ -125,12 +127,14 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
frameHistory.record(frame.timePoint, state.getZoom(),
frame.mapMode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Milliseconds(0));
+
// - UPLOAD PASS -------------------------------------------------------------------------------
// Uploads all required buffers and images before we do any actual rendering.
{
MBGL_DEBUG_GROUP("upload");
spriteAtlas->upload(context, 0);
+
lineAtlas->upload(context, 0);
glyphAtlas->upload(context, 0);
frameHistory.upload(context, 0);
@@ -148,9 +152,8 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
// tiles whatsoever.
{
MBGL_DEBUG_GROUP("clear");
- context.bindFramebuffer.reset();
- context.viewport.reset();
- context.stencilFunc.reset();
+ view.bind();
+ context.stencilFunc = { gl::StencilTestFunction::Always, 0, ~0u };
context.stencilTest = true;
context.stencilMask = 0xFF;
context.depthTest = false;
@@ -188,7 +191,7 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
#if not MBGL_USE_GLES2 and not defined(NDEBUG)
if (frame.debugOptions & MapDebugOptions::StencilClip) {
- renderClipMasks();
+ renderClipMasks(parameters);
return;
}
#endif
@@ -231,7 +234,7 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
#if not MBGL_USE_GLES2 and not defined(NDEBUG)
if (frame.debugOptions & MapDebugOptions::DepthBuffer) {
- renderDepthBuffer();
+ renderDepthBuffer(parameters);
}
#endif
@@ -247,10 +250,6 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a
context.vertexArrayObject = 0;
}
-
- if (frame.contextMode == GLContextMode::Shared) {
- context.setDirtyState();
- }
}
template <class Iterator>
@@ -294,16 +293,21 @@ void Painter::renderPass(PaintParameters& parameters,
renderBackground(parameters, *layer.as<BackgroundLayer>());
} else if (layer.is<CustomLayer>()) {
MBGL_DEBUG_GROUP(layer.baseImpl->id + " - custom");
+
+ // Reset GL state to a known state so the CustomLayer always has a clean slate.
context.vertexArrayObject = 0;
context.depthFunc = gl::DepthTestFunction::LessEqual;
context.depthTest = true;
context.depthMask = false;
context.stencilTest = false;
setDepthSublayer(0);
+
layer.as<CustomLayer>()->impl->render(state);
+
+ // Reset the view back to our original one, just in case the CustomLayer changed
+ // the viewport or Framebuffer.
+ parameters.view.bind();
context.setDirtyState();
- context.bindFramebuffer.reset();
- context.viewport.reset();
} else {
MBGL_DEBUG_GROUP(layer.baseImpl->id + " - " + util::toString(item.tile->id));
if (item.bucket->needsClipping()) {
diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp
index 28aa5aab44..f339ed1aed 100644
--- a/src/mbgl/renderer/painter.hpp
+++ b/src/mbgl/renderer/painter.hpp
@@ -28,6 +28,7 @@ namespace mbgl {
class RenderTile;
class SpriteAtlas;
+class View;
class GlyphAtlas;
class LineAtlas;
struct FrameData;
@@ -58,7 +59,6 @@ class BackgroundLayer;
} // namespace style
struct FrameData {
- std::array<uint16_t, 2> framebufferSize = {{ 0, 0 }};
TimePoint timePoint;
float pixelRatio;
MapMode mapMode;
@@ -68,11 +68,12 @@ struct FrameData {
class Painter : private util::noncopyable {
public:
- Painter(const TransformState&);
+ Painter(gl::Context&, const TransformState&);
~Painter();
void render(const style::Style&,
const FrameData&,
+ View&,
SpriteAtlas& annotationSpriteAtlas);
void cleanup();
@@ -85,9 +86,9 @@ public:
#ifndef NDEBUG
// Renders tile clip boundaries, using stencil buffer to calculate fill color.
- void renderClipMasks();
+ void renderClipMasks(PaintParameters&);
// Renders the depth buffer.
- void renderDepthBuffer();
+ void renderDepthBuffer(PaintParameters&);
#endif
void renderDebugText(Tile&, const mat4&);
@@ -152,6 +153,9 @@ private:
}
#endif
+private:
+ gl::Context& context;
+
mat4 projMatrix;
std::array<float, 2> pixelsToGLUnits;
@@ -168,8 +172,6 @@ private:
int indent = 0;
- gl::Context context;
-
RenderPass pass = RenderPass::Opaque;
int numSublayers = 3;
diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp
index 23a2a8e571..e57bb2205e 100644
--- a/src/mbgl/renderer/painter_debug.cpp
+++ b/src/mbgl/renderer/painter_debug.cpp
@@ -1,6 +1,8 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/debug_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/map/view.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/shader/shaders.hpp>
#include <mbgl/util/string.hpp>
@@ -87,7 +89,7 @@ void Painter::renderDebugFrame(const mat4 &matrix) {
}
#ifndef NDEBUG
-void Painter::renderClipMasks() {
+void Painter::renderClipMasks(PaintParameters&) {
context.stencilTest = false;
context.depthTest = false;
context.program = 0;
@@ -98,13 +100,13 @@ void Painter::renderClipMasks() {
context.rasterPos = { -1, -1, 0, 0 };
// Read the stencil buffer
- const auto& fbSize = frame.framebufferSize;
- auto pixels = std::make_unique<uint8_t[]>(fbSize[0] * fbSize[1]);
+ const auto viewport = context.viewport.getCurrentValue();
+ auto pixels = std::make_unique<uint8_t[]>(viewport.width * viewport.height);
MBGL_CHECK_ERROR(glReadPixels(
- 0, // GLint x
- 0, // GLint y
- fbSize[0], // GLsizei width
- fbSize[1], // GLsizei height
+ viewport.x, // GLint x
+ viewport.y, // GLint y
+ viewport.width, // GLsizei width
+ viewport.height, // GLsizei height
GL_STENCIL_INDEX, // GLenum format
GL_UNSIGNED_BYTE, // GLenum type
pixels.get() // GLvoid * data
@@ -112,20 +114,21 @@ void Painter::renderClipMasks() {
// Scale the Stencil buffer to cover the entire color space.
auto it = pixels.get();
- auto end = it + fbSize[0] * fbSize[1];
+ auto end = it + viewport.width * viewport.height;
const auto factor = 255.0f / *std::max_element(it, end);
for (; it != end; ++it) {
*it *= factor;
}
- MBGL_CHECK_ERROR(glWindowPos2i(0, 0));
- MBGL_CHECK_ERROR(glDrawPixels(fbSize[0], fbSize[1], GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels.get()));
+ MBGL_CHECK_ERROR(glWindowPos2i(viewport.x, viewport.y));
+ MBGL_CHECK_ERROR(glDrawPixels(viewport.width, viewport.height, GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ pixels.get()));
#endif // MBGL_USE_GLES2
}
#endif // NDEBUG
#ifndef NDEBUG
-void Painter::renderDepthBuffer() {
+void Painter::renderDepthBuffer(PaintParameters&) {
context.stencilTest = false;
context.depthTest = false;
context.program = 0;
@@ -136,25 +139,26 @@ void Painter::renderDepthBuffer() {
context.rasterPos = { -1, -1, 0, 0 };
// Read the stencil buffer
- const auto& fbSize = frame.framebufferSize;
- auto pixels = std::make_unique<GLubyte[]>(fbSize[0] * fbSize[1]);
+ const auto viewport = context.viewport.getCurrentValue();
+ auto pixels = std::make_unique<uint8_t[]>(viewport.width * viewport.height);
const double base = 1.0 / (1.0 - depthRangeSize);
glPixelTransferf(GL_DEPTH_SCALE, base);
glPixelTransferf(GL_DEPTH_BIAS, 1.0 - base);
MBGL_CHECK_ERROR(glReadPixels(
- 0, // GLint x
- 0, // GLint y
- fbSize[0], // GLsizei width
- fbSize[1], // GLsizei height
+ viewport.x, // GLint x
+ viewport.y, // GLint y
+ viewport.width, // GLsizei width
+ viewport.height, // GLsizei height
GL_DEPTH_COMPONENT, // GLenum format
GL_UNSIGNED_BYTE, // GLenum type
pixels.get() // GLvoid * data
));
- MBGL_CHECK_ERROR(glWindowPos2i(0, 0));
- MBGL_CHECK_ERROR(glDrawPixels(fbSize[0], fbSize[1], GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels.get()));
+ MBGL_CHECK_ERROR(glWindowPos2i(viewport.x, viewport.y));
+ MBGL_CHECK_ERROR(glDrawPixels(viewport.width, viewport.height, GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ pixels.get()));
#endif // MBGL_USE_GLES2
}
#endif // NDEBUG
diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp
index 50ead900f6..b6606ca40b 100644
--- a/src/mbgl/renderer/painter_fill.cpp
+++ b/src/mbgl/renderer/painter_fill.cpp
@@ -1,6 +1,7 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/gl/gl.hpp>
+#include <mbgl/map/view.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
@@ -29,7 +30,9 @@ void Painter::renderFill(PaintParameters& parameters,
const bool isOutlineColorDefined = !properties.fillOutlineColor.isUndefined();
Color strokeColor = isOutlineColorDefined? properties.fillOutlineColor : fillColor;
- auto worldSize = util::convert<GLfloat>(frame.framebufferSize);
+ const auto viewport = context.viewport.getCurrentValue();
+ const std::array<GLfloat, 2> worldSize{ { static_cast<GLfloat>(viewport.width),
+ static_cast<GLfloat>(viewport.height) } };
bool pattern = !properties.fillPattern.value.from.empty();
bool outline = properties.fillAntialias && !pattern && isOutlineColorDefined;
diff --git a/src/mbgl/style/source_impl.hpp b/src/mbgl/style/source_impl.hpp
index 608a552835..14ed9cd01c 100644
--- a/src/mbgl/style/source_impl.hpp
+++ b/src/mbgl/style/source_impl.hpp
@@ -86,6 +86,7 @@ protected:
Source& base;
SourceObserver* observer = nullptr;
std::map<OverscaledTileID, std::unique_ptr<Tile>> tiles;
+ TileCache cache;
private:
// TileObserver implementation.
@@ -97,7 +98,6 @@ private:
virtual std::unique_ptr<Tile> createTile(const OverscaledTileID&, const UpdateParameters&) = 0;
std::map<UnwrappedTileID, RenderTile> renderTiles;
- TileCache cache;
};
} // namespace style
diff --git a/src/mbgl/style/source_observer.hpp b/src/mbgl/style/source_observer.hpp
index a6cdab6ba2..dcbcaeabaf 100644
--- a/src/mbgl/style/source_observer.hpp
+++ b/src/mbgl/style/source_observer.hpp
@@ -20,6 +20,9 @@ public:
virtual void onSourceAttributionChanged(Source&, const std::string&) {}
virtual void onSourceError(Source&, std::exception_ptr) {}
+ //Source description needs to be reloaded
+ virtual void onSourceDescriptionChanged(Source&) {}
+
virtual void onTileChanged(Source&, const OverscaledTileID&) {}
virtual void onTileError(Source&, const OverscaledTileID&, std::exception_ptr) {}
};
diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp
index 5b7ba4fc77..4800b9c4be 100644
--- a/src/mbgl/style/sources/geojson_source_impl.cpp
+++ b/src/mbgl/style/sources/geojson_source_impl.cpp
@@ -38,15 +38,31 @@ GeoJSONSource::Impl::~Impl() = default;
void GeoJSONSource::Impl::setURL(std::string url_) {
url = std::move(url_);
+
+ //Signal that the source description needs a reload
+ if (loaded || req) {
+ loaded = false;
+ req.reset();
+ observer->onSourceDescriptionChanged(base);
+ }
}
optional<std::string> GeoJSONSource::Impl::getURL() {
return url;
}
+
void GeoJSONSource::Impl::setGeoJSON(const GeoJSON& geoJSON) {
+ req.reset();
+ _setGeoJSON(geoJSON);
+}
+
+//Private implementation
+void GeoJSONSource::Impl::_setGeoJSON(const GeoJSON& geoJSON) {
double scale = util::EXTENT / util::tileSize;
+ cache.clear();
+
if (!options.cluster) {
mapbox::geojsonvt::Options vtOptions;
vtOptions.maxZoom = options.maxzoom;
@@ -65,7 +81,7 @@ void GeoJSONSource::Impl::setGeoJSON(const GeoJSON& geoJSON) {
geoJSONOrSupercluster =
std::make_unique<mapbox::supercluster::Supercluster>(features, clusterOptions);
}
-
+
for (auto const &item : tiles) {
GeoJSONTile* geoJSONTile = static_cast<GeoJSONTile*>(item.second.get());
setTileData(*geoJSONTile, geoJSONTile->id);
@@ -125,9 +141,9 @@ void GeoJSONSource::Impl::loadDescription(FileSource& fileSource) {
geoJSON.error().message.c_str());
// Create an empty GeoJSON VT object to make sure we're not infinitely waiting for
// tiles to load.
- setGeoJSON(GeoJSON{ FeatureCollection{} });
+ _setGeoJSON(GeoJSON{ FeatureCollection{} });
} else {
- setGeoJSON(*geoJSON);
+ _setGeoJSON(*geoJSON);
}
loaded = true;
diff --git a/src/mbgl/style/sources/geojson_source_impl.hpp b/src/mbgl/style/sources/geojson_source_impl.hpp
index 9572355f2c..13994d9078 100644
--- a/src/mbgl/style/sources/geojson_source_impl.hpp
+++ b/src/mbgl/style/sources/geojson_source_impl.hpp
@@ -29,6 +29,8 @@ public:
}
private:
+ void _setGeoJSON(const GeoJSON&);
+
Range<uint8_t> getZoomRange() final;
std::unique_ptr<Tile> createTile(const OverscaledTileID&, const UpdateParameters&) final;
diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp
index 522965b953..e1cbe56bc5 100644
--- a/src/mbgl/style/style.cpp
+++ b/src/mbgl/style/style.cpp
@@ -491,6 +491,13 @@ void Style::onSourceError(Source& source, std::exception_ptr error) {
observer->onResourceError(error);
}
+void Style::onSourceDescriptionChanged(Source& source) {
+ observer->onSourceDescriptionChanged(source);
+ if (!source.baseImpl->loaded) {
+ source.baseImpl->loadDescription(fileSource);
+ }
+}
+
void Style::onTileChanged(Source& source, const OverscaledTileID& tileID) {
observer->onTileChanged(source, tileID);
observer->onUpdate(Update::Repaint);
diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp
index 648bd48030..21b25857d6 100644
--- a/src/mbgl/style/style.hpp
+++ b/src/mbgl/style/style.hpp
@@ -134,6 +134,7 @@ private:
void onSourceLoaded(Source&) override;
void onSourceAttributionChanged(Source&, const std::string&) override;
void onSourceError(Source&, std::exception_ptr) override;
+ void onSourceDescriptionChanged(Source&) override;
void onTileChanged(Source&, const OverscaledTileID&) override;
void onTileError(Source&, const OverscaledTileID&, std::exception_ptr) override;
diff --git a/src/mbgl/text/collision_tile.cpp b/src/mbgl/text/collision_tile.cpp
index d6fc1a6ada..e485fbf36c 100644
--- a/src/mbgl/text/collision_tile.cpp
+++ b/src/mbgl/text/collision_tile.cpp
@@ -3,6 +3,7 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/math/minmax.hpp>
+#include <mbgl/util/intersection_tests.hpp>
#include <mapbox/geometry/envelope.hpp>
#include <mapbox/geometry/multi_point.hpp>
@@ -11,20 +12,7 @@
namespace mbgl {
-auto infinity = std::numeric_limits<float>::infinity();
-
-CollisionTile::CollisionTile(PlacementConfig config_) : config(std::move(config_)),
- edges({{
- // left
- CollisionBox(Point<float>(0, 0), 0, -infinity, 0, infinity, infinity),
- // right
- CollisionBox(Point<float>(util::EXTENT, 0), 0, -infinity, 0, infinity, infinity),
- // top
- CollisionBox(Point<float>(0, 0), -infinity, 0, infinity, 0, infinity),
- // bottom
- CollisionBox(Point<float>(0, util::EXTENT), -infinity, 0, infinity, 0, infinity),
- }}) {
-
+CollisionTile::CollisionTile(PlacementConfig config_) : config(std::move(config_)) {
// Compute the transformation matrix.
const float angle_sin = std::sin(config.angle);
const float angle_cos = std::cos(config.angle);
@@ -36,13 +24,12 @@ CollisionTile::CollisionTile(PlacementConfig config_) : config(std::move(config_
// The amount the map is squished depends on the y position.
// Sort of account for this by making all boxes a bit bigger.
- yStretch = std::pow(_yStretch, 1.3);
+ yStretch = std::pow(_yStretch, 1.3f);
}
-float CollisionTile::findPlacementScale(float minPlacementScale, const Point<float>& anchor,
- const CollisionBox& box, const Point<float>& blockingAnchor, const CollisionBox& blocking) {
-
+float CollisionTile::findPlacementScale(const Point<float>& anchor, const CollisionBox& box, const Point<float>& blockingAnchor, const CollisionBox& blocking) {
+ float minPlacementScale = minScale;
// Find the lowest scale at which the two boxes can fit side by side without overlapping.
// Original algorithm:
@@ -80,7 +67,18 @@ float CollisionTile::findPlacementScale(float minPlacementScale, const Point<flo
return minPlacementScale;
}
-float CollisionTile::placeFeature(const CollisionFeature& feature, const bool allowOverlap, const bool avoidEdges) {
+float CollisionTile::placeFeature(const CollisionFeature& feature, bool allowOverlap, bool avoidEdges) {
+ static const float infinity = std::numeric_limits<float>::infinity();
+ static const std::array<CollisionBox, 4> edges {{
+ // left
+ CollisionBox(Point<float>(0, 0), 0, -infinity, 0, infinity, infinity),
+ // right
+ CollisionBox(Point<float>(util::EXTENT, 0), 0, -infinity, 0, infinity, infinity),
+ // top
+ CollisionBox(Point<float>(0, 0), -infinity, 0, infinity, 0, infinity),
+ // bottom
+ CollisionBox(Point<float>(0, util::EXTENT), -infinity, 0, infinity, 0, infinity)
+ }};
float minPlacementScale = minScale;
@@ -92,20 +90,16 @@ float CollisionTile::placeFeature(const CollisionFeature& feature, const bool al
const CollisionBox& blocking = std::get<1>(*it);
Point<float> blockingAnchor = util::matrixMultiply(rotationMatrix, blocking.anchor);
- minPlacementScale = findPlacementScale(minPlacementScale, anchor, box, blockingAnchor, blocking);
+ minPlacementScale = util::max(minPlacementScale, findPlacementScale(anchor, box, blockingAnchor, blocking));
if (minPlacementScale >= maxScale) return minPlacementScale;
}
}
if (avoidEdges) {
- const Point<float> tl = { box.x1, box.y1 };
- const Point<float> tr = { box.x2, box.y1 };
- const Point<float> bl = { box.x1, box.y2 };
- const Point<float> br = { box.x2, box.y2 };
- const Point<float> rtl = util::matrixMultiply(reverseRotationMatrix, tl);
- const Point<float> rtr = util::matrixMultiply(reverseRotationMatrix, tr);
- const Point<float> rbl = util::matrixMultiply(reverseRotationMatrix, bl);
- const Point<float> rbr = util::matrixMultiply(reverseRotationMatrix, br);
+ const Point<float> rtl = util::matrixMultiply(reverseRotationMatrix, { box.x1, box.y1 });
+ const Point<float> rtr = util::matrixMultiply(reverseRotationMatrix, { box.x2, box.y1 });
+ const Point<float> rbl = util::matrixMultiply(reverseRotationMatrix, { box.x1, box.y2 });
+ const Point<float> rbr = util::matrixMultiply(reverseRotationMatrix, { box.x2, box.y2 });
CollisionBox rotatedBox(box.anchor,
util::min(rtl.x, rtr.x, rbl.x, rbr.x),
util::min(rtl.y, rtr.y, rbl.y, rbr.y),
@@ -114,8 +108,7 @@ float CollisionTile::placeFeature(const CollisionFeature& feature, const bool al
box.maxScale);
for (auto& blocking : edges) {
- minPlacementScale = findPlacementScale(minPlacementScale, box.anchor, rotatedBox, blocking.anchor, blocking);
-
+ minPlacementScale = util::max(minPlacementScale, findPlacementScale(box.anchor, rotatedBox, blocking.anchor, blocking));
if (minPlacementScale >= maxScale) return minPlacementScale;
}
}
@@ -124,7 +117,7 @@ float CollisionTile::placeFeature(const CollisionFeature& feature, const bool al
return minPlacementScale;
}
-void CollisionTile::insertFeature(CollisionFeature& feature, const float minPlacementScale, const bool ignorePlacement) {
+void CollisionTile::insertFeature(CollisionFeature& feature, float minPlacementScale, bool ignorePlacement) {
for (auto& box : feature.boxes) {
box.placementScale = minPlacementScale;
}
@@ -143,7 +136,25 @@ void CollisionTile::insertFeature(CollisionFeature& feature, const float minPlac
}
+// +---------------------------+ As you zoom, the size of the symbol changes
+// |(x1,y1) | | relative to the tile e.g. when zooming in,
+// | | | the symbol gets smaller relative to the tile.
+// | (x1',y1') v |
+// | +-------+-------+ | The boxes inserted into the tree represents
+// | | | | | the bounds at the integer zoom level (where
+// | | | | | the symbol is biggest relative to the tile).
+// | | | | |
+// |---->+-------+-------+<----| This happens because placement is updated
+// | | |(xa,ya)| | once every new integer zoom level e.g.
+// | | | | | std::floor(oldZoom) != std::floor(newZoom).
+// | | | | |
+// | +-------+-------+ | Thus, they don't represent the exact bounds
+// | ^ (x2',y2') | of the symbol at the current zoom level. For
+// | | | calculating the bounds at current zoom level
+// | | (x2,y2)| we must unscale the box using its center as
+// +---------------------------+ transform origin.
Box CollisionTile::getTreeBox(const Point<float>& anchor, const CollisionBox& box, const float scale) {
+ assert(box.x1 <= box.x2 && box.y1 <= box.y2);
return Box{
CollisionPoint{
anchor.x + box.x1 / scale,
@@ -156,49 +167,66 @@ Box CollisionTile::getTreeBox(const Point<float>& anchor, const CollisionBox& bo
};
}
-std::vector<IndexedSubfeature> CollisionTile::queryRenderedSymbols(const GeometryCoordinates& queryGeometry, const float scale) {
-
+std::vector<IndexedSubfeature> CollisionTile::queryRenderedSymbols(const GeometryCoordinates& queryGeometry, float scale) {
std::vector<IndexedSubfeature> result;
- if (queryGeometry.empty()) return result;
+ if (queryGeometry.empty() || (tree.empty() && ignoredTree.empty())) {
+ return result;
+ }
+
+ // Generate a rotated geometry out of the original query geometry.
+ // Scale has already been handled by the prior conversions.
+ GeometryCoordinates polygon;
+ for (const auto& point : queryGeometry) {
+ auto rotated = util::matrixMultiply(rotationMatrix, convertPoint<float>(point));
+ polygon.push_back(convertPoint<int16_t>(rotated));
+ }
+ // Predicate for ruling out already seen features.
std::unordered_map<std::string, std::unordered_set<std::size_t>> sourceLayerFeatures;
+ auto seenFeature = [&] (const CollisionTreeBox& treeBox) -> bool {
+ const IndexedSubfeature& feature = std::get<2>(treeBox);
+ const auto& seenFeatures = sourceLayerFeatures[feature.sourceLayerName];
+ return seenFeatures.find(feature.index) == seenFeatures.end();
+ };
- mapbox::geometry::multi_point<float> rotatedPoints {};
- rotatedPoints.reserve(queryGeometry.size());
- std::transform(queryGeometry.cbegin(), queryGeometry.cend(), std::back_inserter(rotatedPoints),
- [&](const auto& c) { return util::matrixMultiply(rotationMatrix, convertPoint<float>(c)); });
- const auto box = mapbox::geometry::envelope(rotatedPoints);
+ // Account for the rounding done when updating symbol shader variables.
+ const float roundedScale = std::pow(2.0f, std::ceil(util::log2(scale) * 10.0f) / 10.0f);
- const auto& anchor = box.min;
- CollisionBox queryBox(anchor, 0, 0, box.max.x - box.min.x, box.max.y - box.min.y, scale);
- auto predicates = bgi::intersects(getTreeBox(anchor, queryBox));
+ // Check if feature is rendered (collision free) at current scale.
+ auto visibleAtScale = [&] (const CollisionTreeBox& treeBox) -> bool {
+ const CollisionBox& box = std::get<1>(treeBox);
+ return roundedScale >= box.placementScale && roundedScale <= box.maxScale;
+ };
- auto fn = [&] (const Tree& tree_, bool ignorePlacement) {
+ // Check if query polygon intersects with the feature box at current scale.
+ auto intersectsAtScale = [&] (const CollisionTreeBox& treeBox) -> bool {
+ const CollisionBox& collisionBox = std::get<1>(treeBox);
+ const auto anchor = util::matrixMultiply(rotationMatrix, collisionBox.anchor);
+ const int16_t x1 = anchor.x + collisionBox.x1 / scale;
+ const int16_t y1 = anchor.y + collisionBox.y1 / scale * yStretch;
+ const int16_t x2 = anchor.x + collisionBox.x2 / scale;
+ const int16_t y2 = anchor.y + collisionBox.y2 / scale * yStretch;
+ auto bbox = GeometryCoordinates {
+ { x1, y1 }, { x2, y1 }, { x2, y2 }, { x1, y2 }
+ };
+ return util::polygonIntersectsPolygon(polygon, bbox);
+ };
+
+ auto predicates = bgi::satisfies(seenFeature)
+ && bgi::satisfies(visibleAtScale)
+ && bgi::satisfies(intersectsAtScale);
+
+ auto queryTree = [&](const auto& tree_) {
for (auto it = tree_.qbegin(predicates); it != tree_.qend(); ++it) {
- const CollisionBox& blocking = std::get<1>(*it);
- const IndexedSubfeature& indexedFeature = std::get<2>(*it);
-
- auto& seenFeatures = sourceLayerFeatures[indexedFeature.sourceLayerName];
- if (seenFeatures.find(indexedFeature.index) == seenFeatures.end()) {
- if (ignorePlacement) {
- seenFeatures.insert(indexedFeature.index);
- result.push_back(indexedFeature);
- } else {
- auto blockingAnchor = util::matrixMultiply(rotationMatrix, blocking.anchor);
- float minPlacementScale = findPlacementScale(minScale, anchor, queryBox, blockingAnchor, blocking);
- if (minPlacementScale >= scale) {
- seenFeatures.insert(indexedFeature.index);
- result.push_back(indexedFeature);
- }
- }
- }
+ const IndexedSubfeature& feature = std::get<2>(*it);
+ auto& seenFeatures = sourceLayerFeatures[feature.sourceLayerName];
+ seenFeatures.insert(feature.index);
+ result.push_back(feature);
}
};
- bool ignorePlacement = false;
- fn(tree, ignorePlacement);
- ignorePlacement = true;
- fn(ignoredTree, ignorePlacement);
+ queryTree(tree);
+ queryTree(ignoredTree);
return result;
}
diff --git a/src/mbgl/text/collision_tile.hpp b/src/mbgl/text/collision_tile.hpp
index dbc23b2a79..186cd19d28 100644
--- a/src/mbgl/text/collision_tile.hpp
+++ b/src/mbgl/text/collision_tile.hpp
@@ -39,10 +39,10 @@ class CollisionTile {
public:
explicit CollisionTile(PlacementConfig);
- float placeFeature(const CollisionFeature&, const bool allowOverlap, const bool avoidEdges);
- void insertFeature(CollisionFeature&, const float minPlacementScale, const bool ignorePlacement);
+ float placeFeature(const CollisionFeature&, bool allowOverlap, bool avoidEdges);
+ void insertFeature(CollisionFeature&, float minPlacementScale, bool ignorePlacement);
- std::vector<IndexedSubfeature> queryRenderedSymbols(const GeometryCoordinates&, const float scale);
+ std::vector<IndexedSubfeature> queryRenderedSymbols(const GeometryCoordinates&, float scale);
const PlacementConfig config;
@@ -52,10 +52,9 @@ public:
std::array<float, 4> rotationMatrix;
std::array<float, 4> reverseRotationMatrix;
- std::array<CollisionBox, 4> edges;
private:
- float findPlacementScale(float minPlacementScale,
+ float findPlacementScale(
const Point<float>& anchor, const CollisionBox& box,
const Point<float>& blockingAnchor, const CollisionBox& blocking);
Box getTreeBox(const Point<float>& anchor, const CollisionBox& box, const float scale = 1.0);
diff --git a/src/mbgl/util/intersection_tests.cpp b/src/mbgl/util/intersection_tests.cpp
index a0feb8ec37..c580357298 100644
--- a/src/mbgl/util/intersection_tests.cpp
+++ b/src/mbgl/util/intersection_tests.cpp
@@ -16,14 +16,6 @@ bool polygonContainsPoint(const GeometryCoordinates& ring, const GeometryCoordin
return c;
}
-bool multiPolygonContainsPoint(const GeometryCollection& rings, const GeometryCoordinate& p) {
- bool c = false;
- for (auto& ring : rings) {
- c = (c != polygonContainsPoint(ring, p));
- }
- return c;
-}
-
// Code from http://stackoverflow.com/a/1501725/331379.
float distToSegmentSquared(const GeometryCoordinate& p, const GeometryCoordinate& v, const GeometryCoordinate& w) {
if (v == w) return util::distSqr<float>(p, v);
@@ -114,23 +106,23 @@ bool polygonIntersectsBufferedMultiLine(const GeometryCoordinates& polygon, cons
return false;
}
-bool polygonIntersectsMultiPolygon(const GeometryCoordinates& polygon, const GeometryCollection& multiPolygon) {
- if (polygon.size() == 1) {
- return multiPolygonContainsPoint(multiPolygon, polygon.at(0));
+bool polygonIntersectsPolygon(const GeometryCoordinates& polygonA, const GeometryCoordinates& polygonB) {
+ for (auto& p : polygonA) {
+ if (polygonContainsPoint(polygonB, p)) return true;
}
- for (auto& ring : multiPolygon) {
- for (auto& p : ring) {
- if (polygonContainsPoint(polygon, p)) return true;
- }
+ for (auto& p : polygonB) {
+ if (polygonContainsPoint(polygonA, p)) return true;
}
- for (auto& p : polygon) {
- if (multiPolygonContainsPoint(multiPolygon, p)) return true;
- }
+ if (lineIntersectsLine(polygonA, polygonB)) return true;
- for (auto& polygonB : multiPolygon) {
- if (lineIntersectsLine(polygon, polygonB)) return true;
+ return false;
+}
+
+bool polygonIntersectsMultiPolygon(const GeometryCoordinates& polygon, const GeometryCollection& multiPolygon) {
+ for (auto& ring : multiPolygon) {
+ if (polygonIntersectsPolygon(polygon, ring)) return true;
}
return false;
diff --git a/src/mbgl/util/intersection_tests.hpp b/src/mbgl/util/intersection_tests.hpp
index 6adb3b5fdf..5bcb29c767 100644
--- a/src/mbgl/util/intersection_tests.hpp
+++ b/src/mbgl/util/intersection_tests.hpp
@@ -7,6 +7,7 @@ namespace util {
bool polygonIntersectsBufferedMultiPoint(const GeometryCoordinates&, const GeometryCollection&, float radius);
bool polygonIntersectsBufferedMultiLine(const GeometryCoordinates&, const GeometryCollection&, float radius);
+bool polygonIntersectsPolygon(const GeometryCoordinates&, const GeometryCoordinates&);
bool polygonIntersectsMultiPolygon(const GeometryCoordinates&, const GeometryCollection&);
} // namespace util
diff --git a/src/mbgl/util/offscreen_texture.cpp b/src/mbgl/util/offscreen_texture.cpp
index 51049f8282..40bb70b70e 100644
--- a/src/mbgl/util/offscreen_texture.cpp
+++ b/src/mbgl/util/offscreen_texture.cpp
@@ -1,70 +1,48 @@
+#include <mbgl/util/offscreen_texture.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/gl/gl.hpp>
-#include <mbgl/util/offscreen_texture.hpp>
+#include <cstring>
#include <cassert>
namespace mbgl {
-void OffscreenTexture::bind(gl::Context& context,
- std::array<uint16_t, 2> size) {
+OffscreenTexture::OffscreenTexture(gl::Context& context_, std::array<uint16_t, 2> size_)
+ : context(context_), size(std::move(size_)) {
assert(size[0] > 0 && size[1] > 0);
+}
- if (!texture || texture->size != size) {
- texture = context.createTexture(size);
- }
-
+void OffscreenTexture::bind() {
if (!framebuffer) {
- framebuffer = context.createFramebuffer();
- context.bindFramebuffer = *framebuffer;
- MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- texture->texture, 0));
-
- GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER));
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- switch (status) {
- case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
- throw std::runtime_error("Couldn't create framebuffer: incomplete attachment");
- case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
- throw std::runtime_error(
- "Couldn't create framebuffer: incomplete missing attachment");
-#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
- case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
- throw std::runtime_error("Couldn't create framebuffer: incomplete draw buffer");
-#endif
-#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
- case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
- throw std::runtime_error("Couldn't create framebuffer: incomplete read buffer");
-#endif
-#ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
- case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
- throw std::runtime_error("Couldn't create framebuffer: incomplete dimensions");
-#endif
-
- case GL_FRAMEBUFFER_UNSUPPORTED:
- throw std::runtime_error("Couldn't create framebuffer: unsupported");
- default:
- throw std::runtime_error("Couldn't create framebuffer: other");
- }
- }
+ texture = context.createTexture(size);
+ framebuffer = context.createFramebuffer(*texture);
} else {
- context.bindFramebuffer = *framebuffer;
+ context.bindFramebuffer = framebuffer->framebuffer;
}
context.viewport = { 0, 0, size[0], size[1] };
}
gl::Texture& OffscreenTexture::getTexture() {
+ assert(texture);
return *texture;
}
-std::array<uint16_t, 2> OffscreenTexture::getSize() const {
- if (texture) {
- // Use explicit dereference instead of -> due to clang 3.5 bug
- return (*texture).size;
- } else {
- return {{ 0, 0 }};
+PremultipliedImage OffscreenTexture::readStillImage() {
+ PremultipliedImage image { size[0], size[1] };
+ MBGL_CHECK_ERROR(glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, image.data.get()));
+
+ const auto stride = image.stride();
+ auto tmp = std::make_unique<uint8_t[]>(stride);
+ uint8_t* rgba = image.data.get();
+ for (int i = 0, j = size[1] - 1; i < j; i++, j--) {
+ std::memcpy(tmp.get(), rgba + i * stride, stride);
+ std::memcpy(rgba + i * stride, rgba + j * stride, stride);
+ std::memcpy(rgba + j * stride, tmp.get(), stride);
}
+
+ return image;
}
+
} // namespace mbgl
diff --git a/src/mbgl/util/offscreen_texture.hpp b/src/mbgl/util/offscreen_texture.hpp
index c71c0e51d9..8928bc2434 100644
--- a/src/mbgl/util/offscreen_texture.hpp
+++ b/src/mbgl/util/offscreen_texture.hpp
@@ -1,6 +1,10 @@
#pragma once
+#include <mbgl/map/view.hpp>
+#include <mbgl/gl/framebuffer.hpp>
#include <mbgl/gl/texture.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/image.hpp>
namespace mbgl {
@@ -8,15 +12,20 @@ namespace gl {
class Context;
} // namespace gl
-class OffscreenTexture {
+class OffscreenTexture : public View {
public:
- void bind(gl::Context&, std::array<uint16_t, 2> size);
+ OffscreenTexture(gl::Context&, std::array<uint16_t, 2> size = {{ 256, 256 }});
+
+ void bind() override;
+
+ PremultipliedImage readStillImage();
gl::Texture& getTexture();
- std::array<uint16_t, 2> getSize() const;
private:
- optional<gl::UniqueFramebuffer> framebuffer;
+ gl::Context& context;
+ std::array<uint16_t, 2> size;
+ optional<gl::Framebuffer> framebuffer;
optional<gl::Texture> texture;
};
diff --git a/src/mbgl/util/tile_coordinate.hpp b/src/mbgl/util/tile_coordinate.hpp
index 194a62ecef..bcd1c8444f 100644
--- a/src/mbgl/util/tile_coordinate.hpp
+++ b/src/mbgl/util/tile_coordinate.hpp
@@ -5,6 +5,7 @@
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/projection.hpp>
namespace mbgl {
@@ -17,23 +18,25 @@ public:
TileCoordinatePoint p;
double z;
- static TileCoordinate fromLatLng(const TransformState& state, double zoom, const LatLng& latLng) {
- const double scale = std::pow(2, zoom - state.getZoom());
- return { state.project(latLng) * scale / double(util::tileSize), zoom };
+ static TileCoordinate fromLatLng(double zoom, const LatLng& latLng) {
+ const double scale = std::pow(2.0, zoom);
+ return { Projection::project(latLng, scale) / double(util::tileSize), zoom };
}
static TileCoordinate fromScreenCoordinate(const TransformState& state, double zoom, const ScreenCoordinate& screenCoordinate) {
- return fromLatLng(state, zoom, state.screenCoordinateToLatLng(screenCoordinate));
+ return fromLatLng(zoom, state.screenCoordinateToLatLng(screenCoordinate));
}
TileCoordinate zoomTo(double zoom) const {
- return { p * std::pow(2, zoom - z), zoom };
+ const double scaleDiff = std::pow(2.0, zoom - z);
+ return { p * scaleDiff, zoom };
}
static GeometryCoordinate toGeometryCoordinate(const UnwrappedTileID& tileID, const TileCoordinatePoint& point) {
+ const double scale = std::pow(2.0, tileID.canonical.z);
auto zoomed = TileCoordinate { point, 0 }.zoomTo(tileID.canonical.z);
return {
- int16_t(util::clamp<int64_t>((zoomed.p.x - tileID.canonical.x - tileID.wrap * std::pow(2.0, tileID.canonical.z)) * util::EXTENT,
+ int16_t(util::clamp<int64_t>((zoomed.p.x - tileID.canonical.x - tileID.wrap * scale) * util::EXTENT,
std::numeric_limits<int16_t>::min(),
std::numeric_limits<int16_t>::max())),
int16_t(util::clamp<int64_t>((zoomed.p.y - tileID.canonical.y) * util::EXTENT,
diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp
index 5487fb269c..c6bf7d362a 100644
--- a/src/mbgl/util/tile_cover.cpp
+++ b/src/mbgl/util/tile_cover.cpp
@@ -147,13 +147,12 @@ std::vector<UnwrappedTileID> tileCover(const LatLngBounds& bounds_, int32_t z) {
{ std::max(bounds_.south(), -util::LATITUDE_MAX), bounds_.west() },
{ std::min(bounds_.north(), util::LATITUDE_MAX), bounds_.east() });
- const TransformState state;
return tileCover(
- TileCoordinate::fromLatLng(state, z, bounds.northwest()).p,
- TileCoordinate::fromLatLng(state, z, bounds.northeast()).p,
- TileCoordinate::fromLatLng(state, z, bounds.southeast()).p,
- TileCoordinate::fromLatLng(state, z, bounds.southwest()).p,
- TileCoordinate::fromLatLng(state, z, bounds.center()).p,
+ TileCoordinate::fromLatLng(z, bounds.northwest()).p,
+ TileCoordinate::fromLatLng(z, bounds.northeast()).p,
+ TileCoordinate::fromLatLng(z, bounds.southeast()).p,
+ TileCoordinate::fromLatLng(z, bounds.southwest()).p,
+ TileCoordinate::fromLatLng(z, bounds.center()).p,
z);
}