summaryrefslogtreecommitdiff
path: root/include/mbgl
diff options
context:
space:
mode:
Diffstat (limited to 'include/mbgl')
-rw-r--r--include/mbgl/geometry/anchor.hpp25
-rw-r--r--include/mbgl/geometry/binpack.hpp100
-rw-r--r--include/mbgl/geometry/buffer.hpp114
-rw-r--r--include/mbgl/geometry/debug_font_buffer.hpp17
-rw-r--r--include/mbgl/geometry/elements_buffer.hpp54
-rw-r--r--include/mbgl/geometry/fill_buffer.hpp21
-rw-r--r--include/mbgl/geometry/geometry.hpp77
-rw-r--r--include/mbgl/geometry/glyph_atlas.hpp51
-rw-r--r--include/mbgl/geometry/icon_buffer.hpp20
-rw-r--r--include/mbgl/geometry/interpolate.hpp13
-rw-r--r--include/mbgl/geometry/line_buffer.hpp39
-rw-r--r--include/mbgl/geometry/sprite_atlas.hpp74
-rw-r--r--include/mbgl/geometry/text_buffer.hpp25
-rw-r--r--include/mbgl/geometry/vao.hpp101
-rw-r--r--include/mbgl/geometry/vertex_buffer.hpp35
-rw-r--r--include/mbgl/map/map.hpp194
-rw-r--r--include/mbgl/map/raster_tile_data.hpp28
-rw-r--r--include/mbgl/map/source.hpp72
-rw-r--r--include/mbgl/map/sprite.hpp65
-rw-r--r--include/mbgl/map/tile.hpp73
-rw-r--r--include/mbgl/map/tile_data.hpp77
-rw-r--r--include/mbgl/map/tile_parser.hpp68
-rw-r--r--include/mbgl/map/transform.hpp106
-rw-r--r--include/mbgl/map/transform_state.hpp69
-rw-r--r--include/mbgl/map/vector_tile.hpp119
-rw-r--r--include/mbgl/map/vector_tile_data.hpp55
-rw-r--r--include/mbgl/map/view.hpp54
-rw-r--r--include/mbgl/mbgl.hpp7
-rw-r--r--include/mbgl/platform/event.hpp79
-rw-r--r--include/mbgl/platform/gl.hpp83
-rw-r--r--include/mbgl/platform/log.hpp71
-rw-r--r--include/mbgl/platform/platform.hpp46
-rw-r--r--include/mbgl/platform/request.hpp48
-rw-r--r--include/mbgl/renderer/bucket.hpp26
-rw-r--r--include/mbgl/renderer/debug_bucket.hpp36
-rw-r--r--include/mbgl/renderer/fill_bucket.hpp88
-rw-r--r--include/mbgl/renderer/frame_history.hpp32
-rw-r--r--include/mbgl/renderer/icon_bucket.hpp53
-rw-r--r--include/mbgl/renderer/line_bucket.hpp61
-rw-r--r--include/mbgl/renderer/painter.hpp219
-rw-r--r--include/mbgl/renderer/prerendered_texture.hpp36
-rw-r--r--include/mbgl/renderer/raster_bucket.hpp30
-rw-r--r--include/mbgl/renderer/text_bucket.hpp61
-rw-r--r--include/mbgl/shader/composite_shader.hpp29
-rw-r--r--include/mbgl/shader/dot_shader.hpp33
-rw-r--r--include/mbgl/shader/gaussian_shader.hpp29
-rw-r--r--include/mbgl/shader/icon_shader.hpp42
-rw-r--r--include/mbgl/shader/line_shader.hpp45
-rw-r--r--include/mbgl/shader/linejoin_shader.hpp37
-rw-r--r--include/mbgl/shader/outline_shader.hpp29
-rw-r--r--include/mbgl/shader/pattern_shader.hpp45
-rw-r--r--include/mbgl/shader/plain_shader.hpp26
-rw-r--r--include/mbgl/shader/raster_shader.hpp33
-rw-r--r--include/mbgl/shader/shader.hpp29
-rw-r--r--include/mbgl/shader/text_shader.hpp72
-rw-r--r--include/mbgl/style/applied_class_properties.hpp39
-rw-r--r--include/mbgl/style/class_dictionary.hpp32
-rw-r--r--include/mbgl/style/class_properties.hpp43
-rw-r--r--include/mbgl/style/filter_comparison.hpp65
-rw-r--r--include/mbgl/style/filter_comparison_private.hpp23
-rw-r--r--include/mbgl/style/filter_expression.hpp54
-rw-r--r--include/mbgl/style/filter_expression_private.hpp75
-rw-r--r--include/mbgl/style/function_properties.hpp79
-rw-r--r--include/mbgl/style/property_fallback.hpp29
-rw-r--r--include/mbgl/style/property_key.hpp57
-rw-r--r--include/mbgl/style/property_transition.hpp15
-rw-r--r--include/mbgl/style/property_value.hpp21
-rw-r--r--include/mbgl/style/rasterize_properties.hpp38
-rw-r--r--include/mbgl/style/style.hpp68
-rw-r--r--include/mbgl/style/style_bucket.hpp88
-rw-r--r--include/mbgl/style/style_layer.hpp94
-rw-r--r--include/mbgl/style/style_layer_group.hpp23
-rw-r--r--include/mbgl/style/style_parser.hpp119
-rw-r--r--include/mbgl/style/style_properties.hpp116
-rw-r--r--include/mbgl/style/style_source.hpp29
-rw-r--r--include/mbgl/style/types.hpp160
-rw-r--r--include/mbgl/style/value.hpp43
-rw-r--r--include/mbgl/style/value_comparison.hpp109
-rw-r--r--include/mbgl/text/collision.hpp32
-rw-r--r--include/mbgl/text/glyph.hpp61
-rw-r--r--include/mbgl/text/glyph_store.hpp95
-rw-r--r--include/mbgl/text/placement.hpp37
-rw-r--r--include/mbgl/text/rotation_range.hpp54
-rw-r--r--include/mbgl/text/types.hpp109
-rw-r--r--include/mbgl/util/clip_ids.hpp19
-rw-r--r--include/mbgl/util/constants.hpp33
-rw-r--r--include/mbgl/util/enum.hpp55
-rw-r--r--include/mbgl/util/error.hpp20
-rw-r--r--include/mbgl/util/image.hpp36
-rw-r--r--include/mbgl/util/io.hpp15
-rw-r--r--include/mbgl/util/mat4.hpp45
-rw-r--r--include/mbgl/util/math.hpp115
-rw-r--r--include/mbgl/util/noncopyable.hpp23
-rw-r--r--include/mbgl/util/pbf.hpp184
-rw-r--r--include/mbgl/util/raster.hpp70
-rw-r--r--include/mbgl/util/rect.hpp21
-rw-r--r--include/mbgl/util/recursive_wrapper.hpp127
-rw-r--r--include/mbgl/util/std.hpp38
-rw-r--r--include/mbgl/util/string.hpp24
-rw-r--r--include/mbgl/util/texturepool.hpp25
-rw-r--r--include/mbgl/util/threadpool.hpp45
-rw-r--r--include/mbgl/util/time.hpp42
-rw-r--r--include/mbgl/util/timer.hpp40
-rw-r--r--include/mbgl/util/token.hpp52
-rw-r--r--include/mbgl/util/transition.hpp84
-rw-r--r--include/mbgl/util/unitbezier.hpp121
-rw-r--r--include/mbgl/util/utf.hpp50
-rw-r--r--include/mbgl/util/uv.hpp141
-rw-r--r--include/mbgl/util/variant.hpp731
-rw-r--r--include/mbgl/util/vec.hpp117
110 files changed, 7251 insertions, 0 deletions
diff --git a/include/mbgl/geometry/anchor.hpp b/include/mbgl/geometry/anchor.hpp
new file mode 100644
index 0000000000..ab006530ff
--- /dev/null
+++ b/include/mbgl/geometry/anchor.hpp
@@ -0,0 +1,25 @@
+#ifndef MBGL_GEOMETRY_ANCHOR
+#define MBGL_GEOMETRY_ANCHOR
+
+#include <vector>
+
+namespace mbgl {
+
+struct Anchor {
+ float x = 0.0f;
+ float y = 0.0f;
+ float angle = 0.0f;
+ float scale = 0.0f;
+ int segment = -1;
+
+ explicit Anchor(float x, float y, float angle, float scale)
+ : x(x), y(y), angle(angle), scale(scale) {}
+ explicit Anchor(float x, float y, float angle, float scale, int segment)
+ : x(x), y(y), angle(angle), scale(scale), segment(segment) {}
+};
+
+typedef std::vector<Anchor> Anchors;
+
+}
+
+#endif \ No newline at end of file
diff --git a/include/mbgl/geometry/binpack.hpp b/include/mbgl/geometry/binpack.hpp
new file mode 100644
index 0000000000..9aadaa202c
--- /dev/null
+++ b/include/mbgl/geometry/binpack.hpp
@@ -0,0 +1,100 @@
+#ifndef MBGL_GEOMETRY_BINPACK
+#define MBGL_GEOMETRY_BINPACK
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/rect.hpp>
+#include <cstdint>
+#include <list>
+
+namespace mbgl {
+
+template <typename T>
+class BinPack : private util::noncopyable {
+public:
+ BinPack(T width, T height)
+ : free(1, Rect<uint16_t>{ 0, 0, width, height }) {}
+public:
+ Rect<T> allocate(T width, T height) {
+ // Find the smallest free rect angle
+ auto smallest = free.end();
+ for (auto it = free.begin(); it != free.end(); ++it) {
+ const Rect<T>& ref = *it;
+ const Rect<T>& rect = *smallest;
+ if (width <= ref.w && height <= ref.h) {
+ if (smallest == free.end() || (ref.y <= rect.y && ref.x <= rect.x)) {
+ smallest = it;
+ }
+ }
+ }
+
+ if (smallest == free.end()) {
+ // There's no space left for this char.
+ return Rect<uint16_t>{ 0, 0, 0, 0 };
+ } else {
+ Rect<T> rect = *smallest;
+ free.erase(smallest);
+
+ // Shorter/Longer Axis Split Rule (SAS)
+ // http://clb.demon.fi/files/RectangleBinPack.pdf p. 15
+ // Ignore the dimension of R and just split long the shorter dimension
+ // See Also: http://www.cs.princeton.edu/~chazelle/pubs/blbinpacking.pdf
+ if (rect.w < rect.h) {
+ // split horizontally
+ // +--+---+
+ // |__|___| <-- b1
+ // +------+ <-- b2
+ if (rect.w > width) free.emplace_back(rect.x + width, rect.y, rect.w - width, height);
+ if (rect.h > height) free.emplace_back(rect.x, rect.y + height, rect.w, rect.h - height);
+ } else {
+ // split vertically
+ // +--+---+
+ // |__| | <-- b1
+ // +--|---+ <-- b2
+ if (rect.w > width) free.emplace_back(rect.x + width, rect.y, rect.w - width, rect.h);
+ if (rect.h > height) free.emplace_back(rect.x, rect.y + height, width, rect.h - height);
+ }
+
+ return Rect<uint16_t>{ rect.x, rect.y, width, height };
+ }
+ }
+
+
+ void release(Rect<T> rect) {
+ // Simple algorithm to recursively merge the newly released cell with its
+ // neighbor. This doesn't merge more than two cells at a time, and fails
+ // for complicated merges.
+ for (auto it = free.begin(); it != free.end(); ++it) {
+ Rect<T> ref = *it;
+ if (ref.y == rect.y && ref.h == rect.h && ref.x + ref.w == rect.x) {
+ ref.w += rect.w;
+ }
+ else if (ref.x == rect.x && ref.w == rect.w && ref.y + ref.h == rect.y) {
+ ref.h += rect.h;
+ }
+ else if (rect.y == ref.y && rect.h == ref.h && rect.x + rect.w == ref.x) {
+ ref.x = rect.x;
+ ref.w += rect.w;
+ }
+ else if (rect.x == ref.x && rect.w == ref.w && rect.y + rect.h == ref.y) {
+ ref.y = rect.y;
+ ref.h += rect.h;
+ } else {
+ continue;
+ }
+
+ free.erase(it);
+ release(ref);
+ return;
+
+ }
+
+ free.emplace_back(rect);
+ };
+
+private:
+ std::list<Rect<T>> free;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/geometry/buffer.hpp b/include/mbgl/geometry/buffer.hpp
new file mode 100644
index 0000000000..20489cb33c
--- /dev/null
+++ b/include/mbgl/geometry/buffer.hpp
@@ -0,0 +1,114 @@
+#ifndef MBGL_GEOMETRY_BUFFER
+#define MBGL_GEOMETRY_BUFFER
+
+#include <mbgl/platform/gl.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <cstdlib>
+#include <cassert>
+#include <stdexcept>
+
+namespace mbgl {
+
+template <
+ size_t item_size,
+ int bufferType = GL_ARRAY_BUFFER,
+ size_t defaultLength = 8192,
+ bool retainAfterUpload = false
+>
+class Buffer : private util::noncopyable {
+public:
+ ~Buffer() {
+ cleanup();
+ if (buffer != 0) {
+ glDeleteBuffers(1, &buffer);
+ buffer = 0;
+ }
+ }
+
+ // Returns the number of elements in this buffer. This is not the number of
+ // bytes, but rather the number of coordinates with associated information.
+ inline size_t index() const {
+ return pos / itemSize;
+ }
+
+ inline bool empty() const {
+ return pos == 0;
+ }
+
+ // Transfers this buffer to the GPU and binds the buffer to the GL context.
+ void bind(bool force = false) {
+ if (buffer == 0) {
+ glGenBuffers(1, &buffer);
+ force = true;
+ }
+ glBindBuffer(bufferType, buffer);
+ if (force) {
+ if (array == nullptr) {
+ throw std::runtime_error("Buffer was already deleted or doesn't contain elements");
+ }
+
+ glBufferData(bufferType, pos, array, GL_STATIC_DRAW);
+ if (!retainAfterUpload) {
+ cleanup();
+ }
+ }
+ }
+
+ void cleanup() {
+ if (array) {
+ free(array);
+ array = nullptr;
+ }
+ }
+
+protected:
+ // increase the buffer size by at least /required/ bytes.
+ inline void *addElement() {
+ if (buffer != 0) {
+ throw std::runtime_error("Can't add elements after buffer was bound to GPU");
+ }
+ if (length < pos + itemSize) {
+ while (length < pos + itemSize) length += defaultLength;
+ array = realloc(array, length);
+ if (array == nullptr) {
+ throw std::runtime_error("Buffer reallocation failed¯");
+ }
+ }
+ pos += itemSize;
+ return static_cast<char *>(array) + (pos - itemSize);
+ }
+
+ // Get a pointer to the item at a given index.
+ inline void *getElement(size_t index) {
+ if (array == nullptr) {
+ throw std::runtime_error("Buffer was already deleted or doesn't contain elements");
+ }
+
+ if (index * itemSize >= pos) {
+ throw new std::runtime_error("Can't get element after array bounds");
+ } else {
+ return static_cast<char *>(array) + (index * itemSize);
+ }
+ }
+
+public:
+ static const size_t itemSize = item_size;
+
+private:
+ // CPU buffer
+ void *array = nullptr;
+
+ // Byte position where we are writing.
+ size_t pos = 0;
+
+ // Number of bytes that are valid in this buffer.
+ size_t length = 0;
+
+ // GL buffer ID
+ uint32_t buffer = 0;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/geometry/debug_font_buffer.hpp b/include/mbgl/geometry/debug_font_buffer.hpp
new file mode 100644
index 0000000000..7cceb0f576
--- /dev/null
+++ b/include/mbgl/geometry/debug_font_buffer.hpp
@@ -0,0 +1,17 @@
+#ifndef MBGL_GEOMETRY_DEBUG_FONT_BUFFER
+#define MBGL_GEOMETRY_DEBUG_FONT_BUFFER
+
+#include "buffer.hpp"
+
+namespace mbgl {
+
+class DebugFontBuffer : public Buffer<
+ 4 // 2 bytes per coordinate, 2 coordinates
+> {
+public:
+ void addText(const char *text, double left, double baseline, double scale = 1);
+};
+
+}
+
+#endif
diff --git a/include/mbgl/geometry/elements_buffer.hpp b/include/mbgl/geometry/elements_buffer.hpp
new file mode 100644
index 0000000000..ed60338e08
--- /dev/null
+++ b/include/mbgl/geometry/elements_buffer.hpp
@@ -0,0 +1,54 @@
+#ifndef MBGL_GEOMETRY_TRIANGLE_ELEMENTS_BUFFER
+#define MBGL_GEOMETRY_TRIANGLE_ELEMENTS_BUFFER
+
+#include <mbgl/geometry/buffer.hpp>
+#include <mbgl/geometry/vao.hpp>
+
+namespace mbgl {
+
+struct ElementGroup {
+ VertexArrayObject array;
+ uint32_t vertex_length;
+ uint32_t elements_length;
+
+ ElementGroup() : vertex_length(0), elements_length(0) {}
+ ElementGroup(uint32_t vertex_length, uint32_t elements_length)
+ : vertex_length(vertex_length),
+ elements_length(elements_length) {
+ }
+};
+
+class TriangleElementsBuffer : public Buffer<
+ 6, // bytes per triangle (3 * unsigned short == 6 bytes)
+ GL_ELEMENT_ARRAY_BUFFER
+> {
+public:
+ typedef uint16_t element_type;
+
+ void add(element_type a, element_type b, element_type c);
+};
+
+
+class LineElementsBuffer : public Buffer<
+ 4, // bytes per triangle (2 * unsigned short == 6 bytes)
+ GL_ELEMENT_ARRAY_BUFFER
+> {
+public:
+ typedef uint16_t element_type;
+
+ void add(element_type a, element_type b);
+};
+
+class PointElementsBuffer : public Buffer<
+ 2, // bytes per point (1 unsigned short)
+ GL_ELEMENT_ARRAY_BUFFER
+> {
+public:
+ typedef uint16_t element_type;
+
+ void add(element_type a);
+};
+
+}
+
+#endif
diff --git a/include/mbgl/geometry/fill_buffer.hpp b/include/mbgl/geometry/fill_buffer.hpp
new file mode 100644
index 0000000000..4a3d5a5b38
--- /dev/null
+++ b/include/mbgl/geometry/fill_buffer.hpp
@@ -0,0 +1,21 @@
+#ifndef MBGL_GEOMETRY_FILL_BUFFER
+#define MBGL_GEOMETRY_FILL_BUFFER
+
+#include "buffer.hpp"
+#include <vector>
+#include <cstdint>
+
+namespace mbgl {
+
+class FillVertexBuffer : public Buffer<
+ 4 // bytes per coordinates (2 * unsigned short == 4 bytes)
+> {
+public:
+ typedef int16_t vertex_type;
+
+ void add(vertex_type x, vertex_type y);
+};
+
+}
+
+#endif
diff --git a/include/mbgl/geometry/geometry.hpp b/include/mbgl/geometry/geometry.hpp
new file mode 100644
index 0000000000..47981ce83b
--- /dev/null
+++ b/include/mbgl/geometry/geometry.hpp
@@ -0,0 +1,77 @@
+#ifndef MBGL_GEOMETRY_GEOMETRY
+#define MBGL_GEOMETRY_GEOMETRY
+
+#include <mbgl/util/pbf.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <cstdlib>
+
+namespace mbgl {
+
+class Geometry : private util::noncopyable {
+
+public:
+ inline explicit Geometry(pbf& data);
+
+ enum command : uint8_t {
+ end = 0,
+ move_to = 1,
+ line_to = 2,
+ close = 7
+ };
+
+ inline command next(int32_t &rx, int32_t &ry);
+
+private:
+ pbf& data;
+ uint8_t cmd;
+ uint32_t length;
+ int32_t x, y;
+ int32_t ox, oy;
+};
+
+Geometry::Geometry(pbf& data)
+ : data(data),
+ cmd(1),
+ length(0),
+ x(0), y(0),
+ ox(0), oy(0) {}
+
+Geometry::command Geometry::next(int32_t &rx, int32_t &ry) {
+ if (data.data < data.end) {
+ if (length == 0) {
+ uint32_t cmd_length = static_cast<uint32_t>(data.varint());
+ cmd = cmd_length & 0x7;
+ length = cmd_length >> 3;
+ }
+
+ --length;
+
+ if (cmd == move_to || cmd == line_to) {
+ rx = (x += data.svarint());
+ ry = (y += data.svarint());
+
+ if (cmd == move_to) {
+ ox = x;
+ oy = y;
+ return move_to;
+ } else {
+ return line_to;
+ }
+ } else if (cmd == close) {
+ rx = ox;
+ ry = oy;
+ return close;
+ } else {
+ fprintf(stderr, "unknown command: %d\n", cmd);
+ // TODO: gracefully handle geometry parse failures
+ return end;
+ }
+ } else {
+ return end;
+ }
+}
+
+}
+
+#endif
diff --git a/include/mbgl/geometry/glyph_atlas.hpp b/include/mbgl/geometry/glyph_atlas.hpp
new file mode 100644
index 0000000000..e05cbe3b90
--- /dev/null
+++ b/include/mbgl/geometry/glyph_atlas.hpp
@@ -0,0 +1,51 @@
+#ifndef MBGL_GEOMETRY_GLYPH_ATLAS
+#define MBGL_GEOMETRY_GLYPH_ATLAS
+
+#include <mbgl/geometry/binpack.hpp>
+#include <mbgl/text/glyph_store.hpp>
+
+#include <string>
+#include <set>
+#include <map>
+#include <mutex>
+#include <atomic>
+
+namespace mbgl {
+
+class GlyphAtlas {
+public:
+
+private:
+ struct GlyphValue {
+ GlyphValue(const Rect<uint16_t>& rect, uint64_t id)
+ : rect(rect), ids({ id }) {}
+ Rect<uint16_t> rect;
+ std::set<uint64_t> ids;
+ };
+
+public:
+ GlyphAtlas(uint16_t width, uint16_t height);
+ ~GlyphAtlas();
+
+
+ Rect<uint16_t> addGlyph(uint64_t tile_id, const std::string& face_name,
+ const SDFGlyph& glyph);
+ void removeGlyphs(uint64_t tile_id);
+ void bind();
+
+public:
+ const uint16_t width = 0;
+ const uint16_t height = 0;
+
+private:
+ std::mutex mtx;
+ BinPack<uint16_t> bin;
+ std::map<std::string, std::map<uint32_t, GlyphValue>> index;
+ char *const data = nullptr;
+ std::atomic<bool> dirty;
+ uint32_t texture = 0;
+};
+
+};
+
+#endif
diff --git a/include/mbgl/geometry/icon_buffer.hpp b/include/mbgl/geometry/icon_buffer.hpp
new file mode 100644
index 0000000000..346b3b5f06
--- /dev/null
+++ b/include/mbgl/geometry/icon_buffer.hpp
@@ -0,0 +1,20 @@
+#ifndef MBGL_GEOMETRY_ICON_BUFFER
+#define MBGL_GEOMETRY_ICON_BUFFER
+
+#include "buffer.hpp"
+
+namespace mbgl {
+
+ class IconVertexBuffer : public Buffer<
+ 4 + // int16 x/y coordinates per vertex (== 4 bytes)
+ 4 // uint16 x/y coordinates of icon in sprite (== 4 bytes)
+ > {
+ public:
+ typedef int16_t vertex_type;
+
+ void add(vertex_type x, vertex_type y, uint16_t tx, uint16_t ty);
+ };
+
+}
+
+#endif
diff --git a/include/mbgl/geometry/interpolate.hpp b/include/mbgl/geometry/interpolate.hpp
new file mode 100644
index 0000000000..cebbcc7028
--- /dev/null
+++ b/include/mbgl/geometry/interpolate.hpp
@@ -0,0 +1,13 @@
+#ifndef MBGL_GEOMETRY_INTERPOLATE
+#define MBGL_GEOMETRY_INTERPOLATE
+
+#include <mbgl/geometry/anchor.hpp>
+#include <mbgl/util/math.hpp>
+
+namespace mbgl {
+
+Anchors interpolate(const std::vector<Coordinate> &vertices, float spacing,
+ float minScale = 0.0f, int start = 0);
+}
+
+#endif
diff --git a/include/mbgl/geometry/line_buffer.hpp b/include/mbgl/geometry/line_buffer.hpp
new file mode 100644
index 0000000000..5012bb12ac
--- /dev/null
+++ b/include/mbgl/geometry/line_buffer.hpp
@@ -0,0 +1,39 @@
+#ifndef MBGL_GEOMETRY_LINE_BUFFER
+#define MBGL_GEOMETRY_LINE_BUFFER
+
+#include "buffer.hpp"
+
+namespace mbgl {
+
+class LineVertexBuffer : public Buffer<
+ 8 // 2 coordinates per vertex + 1 linesofar + 1 extrude coord pair == 4 (== 8 bytes)
+> {
+public:
+ typedef int16_t vertex_type;
+
+ /*
+ * Scale the extrusion vector so that the normal length is this value.
+ * Contains the "texture" normals (-1..1). This is distinct from the extrude
+ * normals for line joins, because the x-value remains 0 for the texture
+ * normal array, while the extrude normal actually moves the vertex to create
+ * the acute/bevelled line join.
+ */
+ static const int8_t extrudeScale = 63;
+
+ /*
+ * Add a vertex to this buffer
+ *
+ * @param {number} x vertex position
+ * @param {number} y vertex position
+ * @param {number} ex extrude normal
+ * @param {number} ey extrude normal
+ * @param {number} tx texture normal
+ * @param {number} ty texture normal
+ */
+ size_t add(vertex_type x, vertex_type y, float ex, float ey, int8_t tx, int8_t ty, int32_t linesofar = 0);
+};
+
+
+}
+
+#endif
diff --git a/include/mbgl/geometry/sprite_atlas.hpp b/include/mbgl/geometry/sprite_atlas.hpp
new file mode 100644
index 0000000000..4b55540cc8
--- /dev/null
+++ b/include/mbgl/geometry/sprite_atlas.hpp
@@ -0,0 +1,74 @@
+#ifndef MBGL_GEOMETRY_SPRITE_ATLAS
+#define MBGL_GEOMETRY_SPRITE_ATLAS
+
+#include <mbgl/geometry/binpack.hpp>
+
+#include <string>
+#include <map>
+#include <mutex>
+#include <atomic>
+#include <set>
+
+namespace mbgl {
+
+class Sprite;
+class SpritePosition;
+
+class SpriteAtlas {
+public:
+ typedef uint16_t dimension;
+
+public:
+ // Add way to construct this from another SpriteAtlas (e.g. with another pixelRatio)
+ SpriteAtlas(dimension width, dimension height);
+ ~SpriteAtlas();
+
+ // Changes the pixel ratio.
+ bool resize(float newRatio);
+
+ // Update uninitialized sprites in this atlas from the given sprite.
+ void update(const Sprite &sprite);
+
+ // Returns the coordinates of a square icon. The getter also *creates* new square icons in the
+ // atlas if they don't exist, but they'll be default-initialized with a a black circle.
+ Rect<dimension> getIcon(int size, const std::string &name);
+
+ // Returns the coordinates of an image that is sourced from the sprite image.
+ // This getter does not create images, as the dimension of the texture us unknown if the
+ // sprite is not yet loaded. Instead, it returns a 0/0/0/0 rect.
+ Rect<dimension> getImage(const std::string &name, const Sprite &sprite);
+
+ // Binds the image buffer of this sprite atlas to the GPU, and uploads data if it is out
+ // of date.
+ void bind(bool linear = false);
+
+ inline float getWidth() const { return width; }
+ inline float getHeight() const { return height; }
+ inline float getTextureWidth() const { return width * pixelRatio; }
+ inline float getTextureHeight() const { return height * pixelRatio; }
+
+private:
+ void allocate();
+ Rect<SpriteAtlas::dimension> allocateImage(size_t width, size_t height);
+ void copy(const Rect<dimension> &dst, const SpritePosition &src, const Sprite &sprite);
+
+public:
+ const dimension width = 0;
+ const dimension height = 0;
+
+private:
+ std::mutex mtx;
+ float pixelRatio = 1.0f;
+ BinPack<dimension> bin;
+ std::map<std::string, Rect<dimension>> images;
+ std::set<std::string> uninitialized;
+ uint32_t *data = nullptr;
+ std::atomic<bool> dirty;
+ uint32_t texture = 0;
+ uint32_t filter = 0;
+ static const int buffer = 1;
+};
+
+};
+
+#endif
diff --git a/include/mbgl/geometry/text_buffer.hpp b/include/mbgl/geometry/text_buffer.hpp
new file mode 100644
index 0000000000..159f3207a8
--- /dev/null
+++ b/include/mbgl/geometry/text_buffer.hpp
@@ -0,0 +1,25 @@
+#ifndef MBGL_GEOMETRY_TEXT_BUFFER
+#define MBGL_GEOMETRY_TEXT_BUFFER
+
+#include "buffer.hpp"
+#include <array>
+
+namespace mbgl {
+
+class TextVertexBuffer : public Buffer <
+ 16,
+ GL_ARRAY_BUFFER,
+ 32768
+> {
+public:
+ typedef int16_t vertex_type;
+
+ static const double angleFactor;
+
+ size_t add(int16_t x, int16_t y, float ox, float oy, uint16_t tx, uint16_t ty, float angle, float minzoom, std::array<float, 2> range, float maxzoom, float labelminzoom);
+};
+
+
+}
+
+#endif
diff --git a/include/mbgl/geometry/vao.hpp b/include/mbgl/geometry/vao.hpp
new file mode 100644
index 0000000000..71d7ff89fe
--- /dev/null
+++ b/include/mbgl/geometry/vao.hpp
@@ -0,0 +1,101 @@
+#ifndef MBGL_GEOMETRY_VAO
+#define MBGL_GEOMETRY_VAO
+
+#include <mbgl/platform/gl.hpp>
+
+#include <stdexcept>
+
+namespace mbgl {
+
+class VertexArrayObject {
+public:
+ template <typename Shader, typename VertexBuffer>
+ void bind(Shader& shader, VertexBuffer& vertex_buffer, char *offset) {
+#ifdef GL_ARB_vertex_array_object
+ if (!vao) {
+ glGenVertexArrays(1, &vao);
+ glBindVertexArray(vao);
+ } else {
+ // We have been given the correct information.
+ glBindVertexArray(vao);
+ }
+
+ if (shader_ptr != &shader) {
+ if (shader_ptr != nullptr) {
+ fprintf(stderr, "shader rebind!");
+ }
+#endif
+ vertex_buffer.bind();
+ shader.bind(offset);
+
+#ifdef GL_ARB_vertex_array_object
+ shader_ptr = &shader;
+ vertex_buffer_ptr = &vertex_buffer;
+ elements_buffer_ptr = nullptr;
+ offset_ptr = offset;
+ } else if (vertex_buffer_ptr != &vertex_buffer) {
+ throw std::runtime_error("trying to bind VAO to another vertex buffer");
+ } else if (elements_buffer_ptr != nullptr) {
+ throw std::runtime_error("trying to bind VAO to another elements buffer");
+ } else if (offset_ptr != offset) {
+ throw std::runtime_error("trying to bind VAO to another offset");
+ }
+#endif
+ }
+
+ template <typename Shader, typename VertexBuffer, typename ElementsBuffer>
+ void bind(Shader& shader, VertexBuffer& vertex_buffer, ElementsBuffer& elements_buffer, char *offset) {
+#ifdef GL_ARB_vertex_array_object
+ if (!vao) {
+ glGenVertexArrays(1, &vao);
+ glBindVertexArray(vao);
+ } else {
+ // We have been given the correct information.
+ glBindVertexArray(vao);
+ }
+
+ if (shader_ptr != &shader) {
+#endif
+ vertex_buffer.bind();
+ elements_buffer.bind();
+ shader.bind(offset);
+
+#ifdef GL_ARB_vertex_array_object
+ shader_ptr = &shader;
+ vertex_buffer_ptr = &vertex_buffer;
+ elements_buffer_ptr = &elements_buffer;
+ offset_ptr = offset;
+ } else if (vertex_buffer_ptr != &vertex_buffer) {
+ throw std::runtime_error("trying to bind VAO to another vertex buffer");
+ } else if (elements_buffer_ptr != &elements_buffer) {
+ throw std::runtime_error("trying to bind VAO to another elements buffer");
+ } else if (offset_ptr != offset) {
+ throw std::runtime_error("trying to bind VAO to another offset");
+ }
+#endif
+ }
+
+ ~VertexArrayObject() {
+#ifdef GL_ARB_vertex_array_object
+ if (vao) {
+ glDeleteVertexArrays(1, &vao);
+ }
+#endif
+ }
+
+private:
+#ifdef GL_ARB_vertex_array_object
+ GLuint vao = 0;
+
+ // For debug reasons, we're storing the bind information so that we can
+ // detect errors and report
+ void *shader_ptr = nullptr;
+ void *vertex_buffer_ptr = nullptr;
+ void *elements_buffer_ptr = nullptr;
+ char *offset_ptr = 0;
+#endif
+};
+
+}
+
+#endif
diff --git a/include/mbgl/geometry/vertex_buffer.hpp b/include/mbgl/geometry/vertex_buffer.hpp
new file mode 100644
index 0000000000..58fd4a9d03
--- /dev/null
+++ b/include/mbgl/geometry/vertex_buffer.hpp
@@ -0,0 +1,35 @@
+#ifndef MBGL_GEOMETRY_VERTEX_BUFFER
+#define MBGL_GEOMETRY_VERTEX_BUFFER
+
+#include <vector>
+#include <cstddef>
+#include <cstdint>
+#include <cmath>
+
+namespace mbgl {
+
+class VertexBuffer {
+public:
+ typedef int16_t vertex_type;
+ VertexBuffer(std::initializer_list<vertex_type> init);
+ ~VertexBuffer();
+
+ /*
+ * Returns the number of elements in this buffer. This is not the number of
+ * bytes, but rather the number of coordinates with associated information.
+ */
+ size_t index() const;
+
+ /*
+ * Transfers this buffer to the GPU and binds the buffer to the GL context.
+ */
+ void bind();
+
+private:
+ const std::vector<vertex_type> array;
+ uint32_t buffer = 0;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
new file mode 100644
index 0000000000..774e5e1292
--- /dev/null
+++ b/include/mbgl/map/map.hpp
@@ -0,0 +1,194 @@
+
+#ifndef MBGL_MAP_MAP
+#define MBGL_MAP_MAP
+
+#include <uv.h>
+
+#include <mbgl/map/view.hpp>
+#include <mbgl/map/transform.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/geometry/glyph_atlas.hpp>
+#include <mbgl/text/glyph_store.hpp>
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/texturepool.hpp>
+
+#include <cstdint>
+#include <string>
+#include <map>
+
+namespace mbgl {
+
+class Source;
+class SpriteAtlas;
+
+class Map : private util::noncopyable {
+public:
+ explicit Map(View &view);
+ ~Map();
+
+ // Start/stop the map render thread
+ void start();
+ void stop();
+
+ // Runs the map event loop.
+ void run();
+
+ // Triggers a lazy rerender: only performs a render when the map is not clean.
+ void rerender();
+
+ // Forces a map update: always triggers a rerender.
+ void update();
+
+ // Triggers a cleanup that releases resources.
+ void cleanup();
+
+ // Controls buffer swapping.
+ bool needsSwap();
+ void swapped();
+
+ // Size
+ void resize(uint16_t width, uint16_t height, float ratio = 1);
+ void resize(uint16_t width, uint16_t height, float ratio, uint16_t fb_width, uint16_t fb_height);
+
+ // Styling
+ const std::set<std::shared_ptr<StyleSource>> getActiveSources() const;
+ void setAppliedClasses(const std::vector<std::string> &classes);
+ void toggleClass(const std::string &name);
+ const std::vector<std::string> &getAppliedClasses() const;
+ void setDefaultTransitionDuration(uint64_t duration_milliseconds = 0);
+ void setStyleJSON(std::string newStyleJSON);
+ std::string getStyleJSON() const;
+ void setAccessToken(std::string access_token);
+ std::string getAccessToken() const;
+
+ // Transition
+ void cancelTransitions();
+
+ // Position
+ void moveBy(double dx, double dy, double duration = 0);
+ void setLonLat(double lon, double lat, double duration = 0);
+ void getLonLat(double &lon, double &lat) const;
+ void startPanning();
+ void stopPanning();
+ void resetPosition();
+
+ // Scale
+ void scaleBy(double ds, double cx = -1, double cy = -1, double duration = 0);
+ void setScale(double scale, double cx = -1, double cy = -1, double duration = 0);
+ double getScale() const;
+ void setZoom(double zoom, double duration = 0);
+ double getZoom() const;
+ void setLonLatZoom(double lon, double lat, double zoom, double duration = 0);
+ void getLonLatZoom(double &lon, double &lat, double &zoom) const;
+ void resetZoom();
+ void startScaling();
+ void stopScaling();
+ double getMinZoom() const;
+ double getMaxZoom() const;
+
+ // Rotation
+ void rotateBy(double sx, double sy, double ex, double ey, double duration = 0);
+ void setAngle(double angle, double duration = 0);
+ void setAngle(double angle, double cx, double cy);
+ double getAngle() const;
+ void resetNorth();
+ void startRotating();
+ void stopRotating();
+ bool canRotate();
+
+ // Debug
+ void setDebug(bool value);
+ void toggleDebug();
+ bool getDebug() const;
+
+public:
+ inline const TransformState &getState() const { return state; }
+ inline std::shared_ptr<const Style> getStyle() const { return style; }
+ inline std::shared_ptr<GlyphAtlas> getGlyphAtlas() { return glyphAtlas; }
+ inline std::shared_ptr<GlyphStore> getGlyphStore() { return glyphStore; }
+ inline std::shared_ptr<SpriteAtlas> getSpriteAtlas() { return spriteAtlas; }
+ inline std::shared_ptr<Texturepool> getTexturepool() { return texturepool; }
+ inline std::shared_ptr<uv::loop> getLoop() { return loop; }
+ inline timestamp getAnimationTime() const { return animationTime; }
+ inline timestamp getTime() const { return animationTime; }
+
+private:
+ // uv async callbacks
+ static void render(uv_async_t *async);
+ static void terminate(uv_async_t *async);
+ static void cleanup(uv_async_t *async);
+ static void delete_async(uv_handle_t *handle);
+
+ // Setup
+ void setup();
+
+ void updateSources();
+ void updateSources(const std::shared_ptr<StyleLayerGroup> &group);
+
+ void updateTiles();
+ void updateRenderState();
+
+ size_t countLayers(const std::vector<LayerDescription>& layers);
+
+ // Prepares a map render by updating the tiles we need for the current view, as well as updating
+ // the stylesheet.
+ void prepare();
+
+ enum RenderPass { Opaque, Translucent };
+
+ // Unconditionally performs a render with the current map state.
+ void render();
+ void renderLayers(std::shared_ptr<StyleLayerGroup> group);
+ void renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass);
+
+private:
+ // If cleared, the next time the render thread attempts to render the map, it will *actually*
+ // render the map.
+ std::atomic_flag is_clean = ATOMIC_FLAG_INIT;
+
+ // If this flag is cleared, the current back buffer is ready for being swapped with the front
+ // buffer (i.e. it has rendered data).
+ std::atomic_flag is_swapped = ATOMIC_FLAG_INIT;
+
+ // This is cleared once the current front buffer has been presented and the back buffer is
+ // ready for rendering.
+ std::atomic_flag is_rendered = ATOMIC_FLAG_INIT;
+
+public:
+ View &view;
+
+private:
+ Transform transform;
+ TransformState state;
+
+ std::shared_ptr<Style> style;
+ std::shared_ptr<GlyphAtlas> glyphAtlas;
+ std::shared_ptr<GlyphStore> glyphStore;
+ std::shared_ptr<SpriteAtlas> spriteAtlas;
+ std::shared_ptr<Texturepool> texturepool;
+
+ Painter painter;
+
+ std::string styleJSON = "";
+ std::string accessToken = "";
+
+ bool debug = false;
+ timestamp animationTime = 0;
+
+ int indent = 0;
+
+ std::set<std::shared_ptr<StyleSource>> activeSources;
+
+private:
+ bool async = false;
+ std::shared_ptr<uv::loop> loop;
+ uv_thread_t thread;
+ uv_async_t *async_terminate = nullptr;
+ uv_async_t *async_render = nullptr;
+ uv_async_t *async_cleanup = nullptr;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/map/raster_tile_data.hpp b/include/mbgl/map/raster_tile_data.hpp
new file mode 100644
index 0000000000..976faa91bc
--- /dev/null
+++ b/include/mbgl/map/raster_tile_data.hpp
@@ -0,0 +1,28 @@
+#ifndef MBGL_MAP_RASTER_TILE_DATA
+#define MBGL_MAP_RASTER_TILE_DATA
+
+#include <mbgl/map/tile_data.hpp>
+
+#include <mbgl/renderer/raster_bucket.hpp>
+
+
+namespace mbgl {
+
+class RasterTileData : public TileData {
+ friend class TileParser;
+
+public:
+ RasterTileData(Tile::ID id, Map &map, const std::string url);
+ ~RasterTileData();
+
+ virtual void parse();
+ virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc);
+ virtual bool hasData(std::shared_ptr<StyleLayer> layer_desc) const;
+
+protected:
+ RasterBucket bucket;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/map/source.hpp b/include/mbgl/map/source.hpp
new file mode 100644
index 0000000000..be5fad3af8
--- /dev/null
+++ b/include/mbgl/map/source.hpp
@@ -0,0 +1,72 @@
+#ifndef MBGL_MAP_SOURCE
+#define MBGL_MAP_SOURCE
+
+#include <mbgl/map/tile.hpp>
+#include <mbgl/map/tile_data.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/time.hpp>
+#include <mbgl/style/style_source.hpp>
+#include <mbgl/style/types.hpp>
+
+#include <list>
+#include <forward_list>
+#include <memory>
+#include <vector>
+#include <string>
+#include <map>
+#include <set>
+
+namespace mbgl {
+
+class TransformState;
+class Texturepool;
+
+class Source : public std::enable_shared_from_this<Source>, private util::noncopyable {
+public:
+ Source(StyleSource style_source, const std::string &access_token = "");
+ Source(SourceType type = SourceType::Vector, const std::string &url = "",
+ uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 22,
+ const std::string &access_token = "");
+
+ bool update(Map &map);
+ void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
+ void drawClippingMasks(Painter &painter);
+ size_t getTileCount() const;
+ void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc);
+ void finishRender(Painter &painter);
+
+ std::forward_list<Tile::ID> getIDs() const;
+ void updateClipIDs(const std::map<Tile::ID, ClipID> &mapping);
+
+ static std::string normalizeSourceURL(const std::string &url, const std::string &access_token);
+
+public:
+ const SourceType type;
+ const std::string url;
+ const uint32_t tile_size;
+ const int32_t min_zoom;
+ const int32_t max_zoom;
+
+private:
+ bool findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std::forward_list<Tile::ID>& retain);
+ bool findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std::forward_list<Tile::ID>& retain);
+ std::forward_list<Tile::ID> covering_tiles(const TransformState &state, int32_t clamped_zoom, const box& points);
+
+ bool updateTiles(Map &map);
+
+ TileData::State addTile(Map &map, const Tile::ID& id);
+ TileData::State hasTile(const Tile::ID& id);
+
+ double getZoom(const TransformState &state) const;
+
+private:
+ // Stores the time when this source was most recently updated.
+ timestamp updated = 0;
+
+ std::map<Tile::ID, std::unique_ptr<Tile>> tiles;
+ std::map<Tile::ID, std::weak_ptr<TileData>> tile_data;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/map/sprite.hpp b/include/mbgl/map/sprite.hpp
new file mode 100644
index 0000000000..22126eb6a1
--- /dev/null
+++ b/include/mbgl/map/sprite.hpp
@@ -0,0 +1,65 @@
+#ifndef MBGL_STYLE_SPRITE
+#define MBGL_STYLE_SPRITE
+
+#include <mbgl/util/raster.hpp>
+#include <mbgl/util/vec.hpp>
+
+#include <string>
+#include <mutex>
+#include <memory>
+#include <atomic>
+#include <unordered_map>
+
+namespace mbgl {
+
+class Map;
+
+class SpritePosition {
+public:
+ explicit SpritePosition() {}
+ explicit SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t pixelRatio = 1);
+
+ operator bool() const {
+ return !(width == 0 && height == 0 && x == 0 && y == 0);
+ }
+
+ uint16_t x = 0, y = 0;
+ uint16_t width = 0, height = 0;
+ uint8_t pixelRatio = 1;
+};
+
+class Sprite : public std::enable_shared_from_this<Sprite> {
+public:
+ Sprite(Map &map, float pixelRatio = 1);
+
+ void load(const std::string& base_url);
+
+ const SpritePosition &getSpritePosition(const std::string& name) const;
+
+ bool isLoaded() const;
+
+public:
+ const float pixelRatio;
+ std::unique_ptr<util::Image> raster;
+
+private:
+ void asyncParseJSON();
+ void asyncParseImage();
+
+ static void parseJSON(std::shared_ptr<Sprite> &sprite);
+ static void parseImage(std::shared_ptr<Sprite> &sprite);
+ static void complete(std::shared_ptr<Sprite> &sprite);
+
+private:
+ Map &map;
+ std::string url;
+ std::string body;
+ std::string image;
+ std::atomic<bool> loaded;
+ std::unordered_map<std::string, SpritePosition> pos;
+ const SpritePosition empty;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/map/tile.hpp b/include/mbgl/map/tile.hpp
new file mode 100644
index 0000000000..7e868afad9
--- /dev/null
+++ b/include/mbgl/map/tile.hpp
@@ -0,0 +1,73 @@
+#ifndef MBGL_MAP_TILE
+#define MBGL_MAP_TILE
+
+#include <mbgl/util/vec.hpp>
+#include <mbgl/util/mat4.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <cstdint>
+#include <forward_list>
+#include <string>
+#include <bitset>
+#include <memory>
+
+namespace mbgl {
+
+class TileData;
+
+struct ClipID {
+ explicit ClipID() {}
+ explicit ClipID(const std::bitset<8> &mask, uint8_t length) : mask(mask), length(length) {}
+ explicit ClipID(const std::string &mask, uint8_t length) : mask(mask), length(length) {}
+ std::bitset<8> mask;
+ uint8_t length = 0;
+};
+
+class Tile : private util::noncopyable {
+public:
+ struct ID {
+ const int16_t w = 0;
+ const int8_t z = 0;
+ const int32_t x = 0, y = 0;
+
+ inline explicit ID(int8_t z, int32_t x, int32_t y)
+ : w((x < 0 ? x - (1 << z) + 1 : x) / (1 << z)), z(z), x(x), y(y) {}
+
+ inline uint64_t to_uint64() const {
+ return ((std::pow(2, z) * y + x) * 32) + z;
+ }
+
+ inline operator std::string() const {
+ return std::to_string(z) + "/" + std::to_string(x) + "/" + std::to_string(y);
+ }
+
+ inline bool operator==(const ID& rhs) const {
+ return w == rhs.w && z == rhs.z && x == rhs.x && y == rhs.y;
+ }
+
+ inline bool operator<(const ID &rhs) const {
+ if (w != rhs.w) return w < rhs.w;
+ if (z != rhs.z) return z < rhs.z;
+ if (x != rhs.x) return x < rhs.x;
+ return y < rhs.y;
+ }
+
+ ID parent(int8_t z) const;
+ ID normalized() const;
+ std::forward_list<ID> children(int32_t z) const;
+ bool isChildOf(const Tile::ID &id) const;
+ };
+
+public:
+ explicit Tile(const ID& id);
+
+public:
+ const Tile::ID id;
+ ClipID clip;
+ mat4 matrix;
+ std::shared_ptr<TileData> data;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/map/tile_data.hpp b/include/mbgl/map/tile_data.hpp
new file mode 100644
index 0000000000..a4b73c339f
--- /dev/null
+++ b/include/mbgl/map/tile_data.hpp
@@ -0,0 +1,77 @@
+#ifndef MBGL_MAP_TILE_DATA
+#define MBGL_MAP_TILE_DATA
+
+#include <mbgl/map/tile.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/platform/platform.hpp>
+#include <mbgl/geometry/vao.hpp>
+#include <mbgl/renderer/debug_bucket.hpp>
+
+#include <cstdint>
+#include <string>
+#include <memory>
+#include <atomic>
+
+namespace mbgl {
+
+class Map;
+class Painter;
+class StyleLayer;
+
+class TileData : public std::enable_shared_from_this<TileData>,
+ private util::noncopyable {
+public:
+ struct exception : std::exception {};
+ struct geometry_too_long_exception : exception {};
+
+public:
+ typedef std::shared_ptr<TileData> Ptr;
+
+ enum class State {
+ invalid,
+ initial,
+ loading,
+ loaded,
+ parsed,
+ obsolete
+ };
+
+public:
+ TileData(Tile::ID id, Map &map, const std::string url);
+ ~TileData();
+
+ void request();
+ void cancel();
+ void reparse();
+ const std::string toString() const;
+
+ // Override this in the child class.
+ virtual void beforeParse();
+ virtual void parse() = 0;
+ virtual void afterParse();
+ virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc) = 0;
+ virtual bool hasData(std::shared_ptr<StyleLayer> layer_desc) const = 0;
+
+
+public:
+ const Tile::ID id;
+ std::atomic<State> state;
+
+protected:
+ Map &map;
+
+ // Request-related information.
+ const std::string url;
+ std::weak_ptr<platform::Request> req;
+ std::string data;
+
+ // Contains the tile ID string for painting debug information.
+ DebugFontBuffer debugFontBuffer;
+
+public:
+ DebugBucket debugBucket;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/map/tile_parser.hpp b/include/mbgl/map/tile_parser.hpp
new file mode 100644
index 0000000000..14e00946b8
--- /dev/null
+++ b/include/mbgl/map/tile_parser.hpp
@@ -0,0 +1,68 @@
+#ifndef MBGL_MAP_TILE_PARSER
+#define MBGL_MAP_TILE_PARSER
+
+#include <mbgl/map/vector_tile.hpp>
+#include <mbgl/text/placement.hpp>
+#include <mbgl/text/glyph_store.hpp>
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/util/utf.hpp>
+#include <mbgl/style/filter_expression.hpp>
+
+namespace mbgl {
+
+class Style;
+class GlyphAtlas;
+class GlyphStore;
+class SpriteAtlas;
+class VectorTileData;
+class StyleLayer;
+class StyleLayerGroup;
+class StyleBucket;
+class StyleBucketFill;
+class StyleBucketLine;
+class StyleBucketIcon;
+
+class Bucket;
+
+class TileParser {
+public:
+ TileParser(const std::string &data, VectorTileData &tile,
+ const std::shared_ptr<const Style> &style,
+ const std::shared_ptr<GlyphAtlas> &glyphAtlas,
+ const std::shared_ptr<GlyphStore> &glyphStore,
+ const std::shared_ptr<SpriteAtlas> &spriteAtlas);
+
+public:
+ void parse();
+
+private:
+ bool obsolete() const;
+ void parseGlyphs();
+ void parseStyleLayers(std::shared_ptr<StyleLayerGroup> group);
+ void addGlyph(uint64_t tileid, const std::string stackname, const std::u32string &string, const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face);
+ std::unique_ptr<Bucket> createBucket(std::shared_ptr<StyleBucket> bucket_desc);
+
+ std::unique_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill);
+ std::unique_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line);
+ std::unique_ptr<Bucket> createIconBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketIcon &icon);
+ std::unique_ptr<Bucket> createTextBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketText &text);
+
+ template <class Bucket> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter);
+ template <class Bucket, typename ...Args> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter, Args&& ...args);
+
+private:
+ const VectorTile vector_data;
+ VectorTileData& tile;
+
+ // Cross-thread shared data.
+ std::shared_ptr<const Style> style;
+ std::shared_ptr<GlyphAtlas> glyphAtlas;
+ std::shared_ptr<GlyphStore> glyphStore;
+ std::shared_ptr<SpriteAtlas> spriteAtlas;
+
+ Placement placement;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/map/transform.hpp b/include/mbgl/map/transform.hpp
new file mode 100644
index 0000000000..61bef76563
--- /dev/null
+++ b/include/mbgl/map/transform.hpp
@@ -0,0 +1,106 @@
+#ifndef MBGL_MAP_TRANSFORM
+#define MBGL_MAP_TRANSFORM
+
+#include <mbgl/util/transition.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/uv.hpp>
+
+#include "view.hpp"
+#include "transform_state.hpp"
+
+#include <forward_list>
+
+namespace mbgl {
+
+struct box;
+
+ class Transform : private util::noncopyable {
+public:
+ Transform(View &view);
+
+ // Map view
+ // Note: width * ratio does not necessarily equal fb_width
+ bool resize(uint16_t width, uint16_t height, float ratio,
+ uint16_t fb_width, uint16_t fb_height);
+
+ // Position
+ void moveBy(double dx, double dy, timestamp duration = 0);
+ void setLonLat(double lon, double lat, timestamp duration = 0);
+ void setLonLatZoom(double lon, double lat, double zoom, timestamp duration = 0);
+ void getLonLat(double& lon, double& lat) const;
+ void getLonLatZoom(double& lon, double& lat, double& zoom) const;
+ void startPanning();
+ void stopPanning();
+
+ // Zoom
+ void scaleBy(double ds, double cx = -1, double cy = -1, timestamp duration = 0);
+ void setScale(double scale, double cx = -1, double cy = -1, timestamp duration = 0);
+ void setZoom(double zoom, timestamp duration = 0);
+ double getZoom() const;
+ double getScale() const;
+ void startScaling();
+ void stopScaling();
+ double getMinZoom() const;
+ double getMaxZoom() const;
+
+ // Angle
+ void rotateBy(double sx, double sy, double ex, double ey, timestamp duration = 0);
+ void setAngle(double angle, timestamp duration = 0);
+ void setAngle(double angle, double cx, double cy);
+ double getAngle() const;
+ void startRotating();
+ void stopRotating();
+ bool canRotate();
+
+ // Transitions
+ bool needsTransition() const;
+ void updateTransitions(timestamp now);
+ void cancelTransitions();
+
+ // Transform state
+ const TransformState currentState() const;
+ const TransformState finalState() const;
+
+private:
+ // Functions prefixed with underscores will *not* perform any locks. It is the caller's
+ // responsibility to lock this object.
+ void _moveBy(double dx, double dy, timestamp duration = 0);
+ void _setScale(double scale, double cx, double cy, timestamp duration = 0);
+ void _setScaleXY(double new_scale, double xn, double yn, timestamp duration = 0);
+ void _setAngle(double angle, timestamp duration = 0);
+ void _clearPanning();
+ void _clearRotating();
+ void _clearScaling();
+
+ void constrain(double& scale, double& y) const;
+
+private:
+ View &view;
+
+ mutable uv::rwlock mtx;
+
+ // This reflects the current state of the transform, representing the actual position of the
+ // map. After calling a transform function with a timer, this will likely remain the same until
+ // you render a new frame.
+ TransformState current;
+
+ // This reflects the final position of the transform, after all possible transition took place.
+ TransformState final;
+
+ // Limit the amount of zooming possible on the map.
+ // TODO: make these modifiable from outside.
+ const double min_scale = std::pow(2, 0);
+ const double max_scale = std::pow(2, 18);
+
+ // cache values for spherical mercator math
+ double zc, Bc, Cc;
+
+ std::forward_list<std::shared_ptr<util::transition>> transitions;
+ std::shared_ptr<util::transition> scale_timeout;
+ std::shared_ptr<util::transition> rotate_timeout;
+ std::shared_ptr<util::transition> pan_timeout;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/map/transform_state.hpp b/include/mbgl/map/transform_state.hpp
new file mode 100644
index 0000000000..85dd2eb87d
--- /dev/null
+++ b/include/mbgl/map/transform_state.hpp
@@ -0,0 +1,69 @@
+#ifndef MBGL_MAP_TRANSFORM_STATE
+#define MBGL_MAP_TRANSFORM_STATE
+
+#include <mbgl/util/mat4.hpp>
+#include <mbgl/map/tile.hpp>
+
+#include <cstdint>
+
+namespace mbgl {
+
+class Transform;
+
+class TransformState {
+ friend class Transform;
+
+public:
+ // Matrix
+ void matrixFor(mat4& matrix, const Tile::ID& id) const;
+ box cornersToBox(uint32_t z) const;
+
+ // Dimensions
+ bool hasSize() const;
+ uint16_t getWidth() const;
+ uint16_t getHeight() const;
+ uint16_t getFramebufferWidth() const;
+ uint16_t getFramebufferHeight() const;
+ const std::array<uint16_t, 2> getFramebufferDimensions() const;
+ float getPixelRatio() const;
+
+ // Zoom
+ float getNormalizedZoom() const;
+ int32_t getIntegerZoom() const;
+ double getZoom() const;
+ double getScale() const;
+
+ // Rotation
+ float getAngle() const;
+
+ // Changing
+ bool isChanging() const;
+
+private:
+ double pixel_x() const;
+ double pixel_y() const;
+
+private:
+ // logical dimensions
+ uint16_t width = 0, height = 0;
+
+ // physical (framebuffer) dimensions
+ std::array<uint16_t, 2> framebuffer = {{ 0, 0 }};
+
+ // map scale factor
+ float pixelRatio = 0;
+
+ // animation state
+ bool rotating = false;
+ bool scaling = false;
+ bool panning = false;
+
+ // map position
+ double x = 0, y = 0;
+ double angle = 0;
+ double scale = std::numeric_limits<double>::infinity();
+};
+
+}
+
+#endif
diff --git a/include/mbgl/map/vector_tile.hpp b/include/mbgl/map/vector_tile.hpp
new file mode 100644
index 0000000000..77e379865f
--- /dev/null
+++ b/include/mbgl/map/vector_tile.hpp
@@ -0,0 +1,119 @@
+#ifndef MBGL_MAP_VECTOR_TILE
+#define MBGL_MAP_VECTOR_TILE
+
+#include <mbgl/util/pbf.hpp>
+#include <mbgl/util/vec.hpp>
+#include <mbgl/style/value.hpp>
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/style/filter_expression.hpp>
+#include <vector>
+#include <map>
+#include <unordered_map>
+#include <set>
+#include <limits>
+
+namespace mbgl {
+
+class BucketDescription;
+class VectorTileLayer;
+
+struct pbf;
+
+enum class FeatureType {
+ Unknown = 0,
+ Point = 1,
+ LineString = 2,
+ Polygon = 3
+};
+
+std::ostream& operator<<(std::ostream&, const FeatureType& type);
+
+class VectorTileFeature {
+public:
+ VectorTileFeature(pbf feature, const VectorTileLayer& layer);
+
+ uint64_t id = 0;
+ FeatureType type = FeatureType::Unknown;
+ std::map<std::string, Value> properties;
+ pbf geometry;
+};
+
+std::ostream& operator<<(std::ostream&, const VectorTileFeature& feature);
+
+
+class VectorTileTagExtractor {
+public:
+ VectorTileTagExtractor(const VectorTileLayer &layer);
+
+ void setTags(const pbf &pbf);
+ std::vector<Value> getValues(const std::string &key) const;
+ void setType(FilterExpression::GeometryType type);
+ FilterExpression::GeometryType getType() const;
+
+private:
+ const VectorTileLayer &layer_;
+ pbf tags_;
+ FilterExpression::GeometryType type_ = FilterExpression::GeometryType::Any;
+};
+
+/*
+ * Allows iterating over the features of a VectorTileLayer using a
+ * BucketDescription as filter. Only features matching the descriptions will
+ * be returned (as pbf).
+ */
+class FilteredVectorTileLayer {
+public:
+ class iterator {
+ public:
+ iterator(const FilteredVectorTileLayer& filter, const pbf& data);
+ void operator++();
+ bool operator!=(const iterator& other) const;
+ const pbf& operator*() const;
+
+ private:
+ const FilteredVectorTileLayer& parent;
+ bool valid = false;
+ pbf feature;
+ pbf data;
+ };
+
+public:
+ FilteredVectorTileLayer(const VectorTileLayer& layer, const FilterExpression &filterExpression);
+
+ iterator begin() const;
+ iterator end() const;
+
+private:
+ const VectorTileLayer& layer;
+ const FilterExpression& filterExpression;
+};
+
+std::ostream& operator<<(std::ostream&, const GlyphPlacement& placement);
+
+class VectorTileLayer {
+public:
+ VectorTileLayer(pbf data);
+
+ const pbf data;
+ std::string name;
+ uint32_t extent = 4096;
+ std::vector<std::string> keys;
+ std::unordered_map<std::string, uint32_t> key_index;
+ std::vector<Value> values;
+ std::map<std::string, std::map<Value, Shaping>> shaping;
+};
+
+class VectorTile {
+public:
+ VectorTile();
+ VectorTile(pbf data);
+ VectorTile& operator=(VectorTile&& other);
+
+ std::map<std::string, const VectorTileLayer> layers;
+};
+
+
+
+}
+
+#endif
diff --git a/include/mbgl/map/vector_tile_data.hpp b/include/mbgl/map/vector_tile_data.hpp
new file mode 100644
index 0000000000..dd55e8dae1
--- /dev/null
+++ b/include/mbgl/map/vector_tile_data.hpp
@@ -0,0 +1,55 @@
+#ifndef MBGL_MAP_VECTOR_TILE_DATA
+#define MBGL_MAP_VECTOR_TILE_DATA
+
+#include <mbgl/map/tile_data.hpp>
+
+
+#include <mbgl/renderer/bucket.hpp>
+
+#include <mbgl/geometry/vertex_buffer.hpp>
+#include <mbgl/geometry/elements_buffer.hpp>
+#include <mbgl/geometry/fill_buffer.hpp>
+#include <mbgl/geometry/line_buffer.hpp>
+#include <mbgl/geometry/icon_buffer.hpp>
+#include <mbgl/geometry/text_buffer.hpp>
+#include <mbgl/map/tile_parser.hpp>
+
+#include <unordered_map>
+
+namespace mbgl {
+
+
+class VectorTileData : public TileData {
+ friend class TileParser;
+
+public:
+ VectorTileData(Tile::ID id, Map &map, const std::string url);
+ ~VectorTileData();
+
+ virtual void beforeParse();
+ virtual void parse();
+ virtual void afterParse();
+ virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc);
+ virtual bool hasData(std::shared_ptr<StyleLayer> layer_desc) const;
+
+protected:
+ // Holds the actual geometries in this tile.
+ FillVertexBuffer fillVertexBuffer;
+ LineVertexBuffer lineVertexBuffer;
+ IconVertexBuffer iconVertexBuffer;
+ TextVertexBuffer textVertexBuffer;
+
+ TriangleElementsBuffer triangleElementsBuffer;
+ LineElementsBuffer lineElementsBuffer;
+ PointElementsBuffer pointElementsBuffer;
+
+ // Holds the buckets of this tile.
+ // They contain the location offsets in the buffers stored above
+ std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets;
+
+ std::unique_ptr<TileParser> parser;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/map/view.hpp b/include/mbgl/map/view.hpp
new file mode 100644
index 0000000000..92d60d4d02
--- /dev/null
+++ b/include/mbgl/map/view.hpp
@@ -0,0 +1,54 @@
+#ifndef MBGL_MAP_VIEW
+#define MBGL_MAP_VIEW
+
+#include <mbgl/util/time.hpp>
+
+namespace mbgl {
+
+class Map;
+
+enum MapChange : uint8_t {
+ MapChangeRegionWillChange = 0,
+ MapChangeRegionWillChangeAnimated = 1,
+ MapChangeRegionDidChange = 2,
+ MapChangeRegionDidChangeAnimated = 3,
+ MapChangeWillStartLoadingMap = 4,
+ MapChangeDidFinishLoadingMap = 5,
+ MapChangeDidFailLoadingMap = 6,
+ MapChangeWillStartRenderingMap = 7,
+ MapChangeDidFinishRenderingMap = 8,
+ MapChangeDidFinishRenderingMapFullyRendered = 9
+};
+
+class View {
+public:
+ virtual void initialize(Map *map) {
+ this->map = map;
+ }
+
+ // Called from the render (=GL) thread. Signals that the context should
+ // swap the front and the back buffer.
+ virtual void swap() = 0;
+
+ // Called from the render thread. Makes the GL context active in the current
+ // thread. This is typically just called once at the beginning of the
+ // renderer setup since the render thread doesn't switch the contexts.
+ virtual void make_active() = 0;
+
+ // Returns the base framebuffer object, if any, and 0 if using the system
+ // provided framebuffer.
+ virtual unsigned int root_fbo() {
+ return 0;
+ }
+
+ // Notifies a watcher of map x/y/scale/rotation changes.
+ // Must only be called from the same thread that caused the change.
+ // Must not be called from the render thread.
+ virtual void notify_map_change(MapChange change, timestamp delay = 0) = 0;
+
+protected:
+ mbgl::Map *map = nullptr;
+};
+}
+
+#endif
diff --git a/include/mbgl/mbgl.hpp b/include/mbgl/mbgl.hpp
new file mode 100644
index 0000000000..90abd4e11e
--- /dev/null
+++ b/include/mbgl/mbgl.hpp
@@ -0,0 +1,7 @@
+#ifndef MBGL_MAIN
+#define MBGL_MAIN
+
+#include "map/map.hpp"
+#include "map/view.hpp"
+
+#endif
diff --git a/include/mbgl/platform/event.hpp b/include/mbgl/platform/event.hpp
new file mode 100644
index 0000000000..b55c721c99
--- /dev/null
+++ b/include/mbgl/platform/event.hpp
@@ -0,0 +1,79 @@
+#ifndef MBGL_PLATFORM_EVENT
+#define MBGL_PLATFORM_EVENT
+
+#include <mbgl/util/enum.hpp>
+
+#include <cstdint>
+
+namespace mbgl {
+
+enum class EventSeverity : uint8_t {
+ Debug,
+ Info,
+ Test,
+ Warning,
+ Error,
+};
+
+MBGL_DEFINE_ENUM_CLASS(EventSeverityClass, EventSeverity, {
+ { EventSeverity::Debug, "DEBUG" },
+ { EventSeverity::Info, "INFO" },
+ { EventSeverity::Test, "TEST" },
+ { EventSeverity::Warning, "WARNING" },
+ { EventSeverity::Error, "ERROR" },
+ { EventSeverity(-1), "UNKNOWN" },
+});
+
+enum class Event : uint8_t {
+ General,
+ Setup,
+ Shader,
+ ParseStyle,
+ ParseTile,
+ Render,
+ HttpRequest,
+ Sprite,
+};
+
+MBGL_DEFINE_ENUM_CLASS(EventClass, Event, {
+ { Event::General, "General" },
+ { Event::Setup, "Setup" },
+ { Event::Shader, "Shader" },
+ { Event::ParseStyle, "ParseStyle" },
+ { Event::ParseTile, "ParseTile" },
+ { Event::Render, "Render" },
+ { Event::HttpRequest, "HttpRequest" },
+ { Event::Sprite, "Sprite" },
+ { Event(-1), "Unknown" },
+});
+
+
+struct EventPermutation {
+ const EventSeverity severity;
+ const Event event;
+
+ constexpr bool operator==(const EventPermutation &rhs) const {
+ return severity == rhs.severity && event == rhs.event;
+ }
+};
+
+constexpr EventSeverity disabledEventSeverities[] = {
+#if !DEBUG
+ EventSeverity::Debug,
+#endif
+#if !TESTING
+ EventSeverity::Test,
+#endif
+};
+
+
+constexpr Event disabledEvents[] = {
+};
+
+constexpr EventPermutation disabledEventPermutations[] = {
+ { EventSeverity::Debug, Event::Shader }
+};
+
+}
+
+#endif
diff --git a/include/mbgl/platform/gl.hpp b/include/mbgl/platform/gl.hpp
new file mode 100644
index 0000000000..a29b230dbf
--- /dev/null
+++ b/include/mbgl/platform/gl.hpp
@@ -0,0 +1,83 @@
+#ifndef MBGL_RENDERER_GL
+#define MBGL_RENDERER_GL
+
+#include <string>
+
+#ifdef NVIDIA
+ #include <GLES2/gl2.h>
+ #include <GLES2/gl2ext.h>
+
+ extern PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;
+
+ #define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
+#elif __APPLE__
+ #include "TargetConditionals.h"
+ #if TARGET_OS_IPHONE
+ #include <OpenGLES/ES2/gl.h>
+ #include <OpenGLES/ES2/glext.h>
+ #define glGenVertexArrays glGenVertexArraysOES
+ #define glBindVertexArray glBindVertexArrayOES
+ #define glDeleteVertexArrays glDeleteVertexArraysOES
+ #define GL_ARB_vertex_array_object 1
+ #define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
+ #elif TARGET_IPHONE_SIMULATOR
+ #include <OpenGLES/ES2/gl.h>
+ #include <OpenGLES/ES2/glext.h>
+ #elif TARGET_OS_MAC
+ #include <OpenGL/OpenGL.h>
+ #include <OpenGL/gl.h>
+ #define glGenVertexArrays glGenVertexArraysAPPLE
+ #define glBindVertexArray glBindVertexArrayAPPLE
+ #define glDeleteVertexArrays glDeleteVertexArraysAPPLE
+ #else
+ #error Unsupported Apple platform
+ #endif
+#else
+ #define GL_GLEXT_PROTOTYPES
+ #include <GL/gl.h>
+ #include <GL/glu.h>
+ #include <GL/glext.h>
+#endif
+
+namespace mbgl {
+namespace gl {
+// Debug group markers, useful for debuggin on iOS
+#if defined(__APPLE__) && defined(DEBUG) && defined(GL_EXT_debug_marker)
+// static int indent = 0;
+inline void start_group(const std::string &str) {
+ glPushGroupMarkerEXT(0, str.c_str());
+ // fprintf(stderr, "%s%s\n", std::string(indent * 4, ' ').c_str(), str.c_str());
+ // indent++;
+}
+
+inline void end_group() {
+ glPopGroupMarkerEXT();
+ // indent--;
+}
+#else
+inline void start_group(const std::string &) {}
+inline void end_group() {}
+#endif
+
+
+struct group {
+ inline group(const std::string &str) { start_group(str); }
+ ~group() { end_group(); };
+};
+}
+}
+
+#ifdef GL_ES_VERSION_2_0
+ #define glClearDepth glClearDepthf
+ #define glDepthRange glDepthRangef
+#endif
+
+void _CHECK_GL_ERROR(const char *cmd, const char *file, int line);
+
+#define _CHECK_ERROR(cmd, file, line) \
+ cmd; \
+ do { _CHECK_GL_ERROR(#cmd, file, line); } while (false);
+
+#define CHECK_ERROR(cmd) _CHECK_ERROR(cmd, __FILE__, __LINE__)
+
+#endif
diff --git a/include/mbgl/platform/log.hpp b/include/mbgl/platform/log.hpp
new file mode 100644
index 0000000000..dc000b4d52
--- /dev/null
+++ b/include/mbgl/platform/log.hpp
@@ -0,0 +1,71 @@
+#ifndef MBGL_PLATFORM_LOG
+#define MBGL_PLATFORM_LOG
+
+#include "event.hpp"
+
+#include <memory>
+#include <string>
+
+namespace mbgl {
+
+class LogBackend {
+public:
+ virtual inline ~LogBackend() = default;
+ virtual void record(EventSeverity severity, Event event, const std::string &msg) = 0;
+ virtual void record(EventSeverity severity, Event event, const char* format, ...) = 0;
+ virtual void record(EventSeverity severity, Event event, int64_t code) = 0;
+ virtual void record(EventSeverity severity, Event event, int64_t code, const std::string &msg) = 0;
+};
+
+class Log {
+private:
+ template <typename T>
+ constexpr static bool includes(const T e, T const *l, const size_t i = 0) {
+ return i >= sizeof l ? false : *(l + i) == e ? true : includes(e, l, i + 1);
+ }
+
+public:
+ template <typename ...Args>
+ static inline void Debug(Event event, Args&& ...args) {
+ Record(EventSeverity::Debug, event, ::std::forward<Args>(args)...);
+ }
+
+ template <typename ...Args>
+ static inline void Info(Event event, Args&& ...args) {
+ Record(EventSeverity::Info, event, ::std::forward<Args>(args)...);
+ }
+
+ template <typename ...Args>
+ static inline void Warning(Event event, Args&& ...args) {
+ Record(EventSeverity::Warning, event, ::std::forward<Args>(args)...);
+ }
+
+ template <typename ...Args>
+ static inline void Error(Event event, Args&& ...args) {
+ Record(EventSeverity::Error, event, ::std::forward<Args>(args)...);
+ }
+
+ template <typename ...Args>
+ static inline void Record(EventSeverity severity, Event event, Args&& ...args) {
+ if (!includes(severity, disabledEventSeverities) &&
+ !includes(event, disabledEvents) &&
+ !includes({ severity, event }, disabledEventPermutations)) {
+ if (Backend) {
+ Backend->record(severity, event, ::std::forward<Args>(args)...);
+ }
+ }
+ }
+
+ template<typename T, typename ...Args>
+ static inline const T &Set(Args&& ...args) {
+ Backend = ::std::unique_ptr<T>(new T(::std::forward<Args>(args)...));
+ return *dynamic_cast<T *>(Backend.get());
+ }
+
+private:
+ static std::unique_ptr<LogBackend> Backend;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/platform/platform.hpp b/include/mbgl/platform/platform.hpp
new file mode 100644
index 0000000000..02aeb594b6
--- /dev/null
+++ b/include/mbgl/platform/platform.hpp
@@ -0,0 +1,46 @@
+#ifndef MBGL_PLATFORM_PLATFORM
+#define MBGL_PLATFORM_PLATFORM
+
+#include <memory>
+#include <functional>
+#include <string>
+
+typedef struct uv_loop_s uv_loop_t;
+
+namespace uv {
+class loop;
+}
+
+namespace mbgl {
+namespace platform {
+
+class Request;
+
+struct Response {
+ Response(std::function<void(Response *)> callback) : callback(callback) {}
+ int16_t code = -1;
+ std::string body;
+ std::string error_message;
+ std::function<void(Response *)> callback;
+};
+
+// Makes an HTTP request of a URL, preferrably on a background thread, and calls a function with the
+// results in the original thread (which runs the libuv loop).
+// If the loop pointer is NULL, the callback function will be called on an arbitrary thread.
+// Returns a cancellable request.
+std::shared_ptr<Request> request_http(const std::string &url,
+ std::function<void(Response *)> callback,
+ std::shared_ptr<uv::loop> loop = nullptr);
+
+// Cancels an HTTP request.
+void cancel_request_http(const std::shared_ptr<Request> &req);
+
+// Shows an alpha image with the specified dimensions in a named window.
+void show_debug_image(std::string name, const char *data, size_t width, size_t height);
+
+// Shows an alpha image with the specified dimensions in a named window.
+void show_color_debug_image(std::string name, const char *data, size_t logical_width, size_t logical_height, size_t width, size_t height);
+}
+}
+
+#endif
diff --git a/include/mbgl/platform/request.hpp b/include/mbgl/platform/request.hpp
new file mode 100644
index 0000000000..7d2da8888c
--- /dev/null
+++ b/include/mbgl/platform/request.hpp
@@ -0,0 +1,48 @@
+#ifndef MBGL_PLATFORM_REQUEST
+#define MBGL_PLATFORM_REQUEST
+
+#include <string>
+#include <functional>
+#include <memory>
+#include <atomic>
+
+#include <mbgl/util/noncopyable.hpp>
+
+// Forward definition.
+typedef struct uv_loop_s uv_loop_t;
+typedef struct uv_async_s uv_async_t;
+
+namespace uv {
+class loop;
+}
+
+namespace mbgl {
+namespace platform {
+
+struct Response;
+
+class Request : public std::enable_shared_from_this<Request>, private util::noncopyable {
+public:
+ Request(const std::string &url,
+ std::function<void(Response *)> callback,
+ std::shared_ptr<uv::loop> loop);
+ ~Request();
+
+ void complete();
+
+private:
+ static void complete(uv_async_t *async);
+
+public:
+ const std::string url;
+ std::unique_ptr<Response> res;
+ std::atomic<bool> cancelled;
+
+public:
+ uv_async_t *async = nullptr;
+ std::shared_ptr<uv::loop> loop;
+};
+}
+}
+
+#endif
diff --git a/include/mbgl/renderer/bucket.hpp b/include/mbgl/renderer/bucket.hpp
new file mode 100644
index 0000000000..18f58ee464
--- /dev/null
+++ b/include/mbgl/renderer/bucket.hpp
@@ -0,0 +1,26 @@
+#ifndef MBGL_RENDERER_BUCKET
+#define MBGL_RENDERER_BUCKET
+
+#include <string>
+#include <memory>
+#include <mbgl/map/tile.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/renderer/prerendered_texture.hpp>
+
+namespace mbgl {
+
+class Painter;
+class StyleLayer;
+
+class Bucket : private util::noncopyable {
+public:
+ virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) = 0;
+ virtual bool hasData() const = 0;
+ virtual ~Bucket() {}
+
+ std::unique_ptr<PrerenderedTexture> prerendered;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/renderer/debug_bucket.hpp b/include/mbgl/renderer/debug_bucket.hpp
new file mode 100644
index 0000000000..ac4f18cc2c
--- /dev/null
+++ b/include/mbgl/renderer/debug_bucket.hpp
@@ -0,0 +1,36 @@
+#ifndef MBGL_RENDERER_DEBUGBUCKET
+#define MBGL_RENDERER_DEBUGBUCKET
+
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/geometry/debug_font_buffer.hpp>
+#include <mbgl/geometry/vao.hpp>
+
+#include <vector>
+#include <memory>
+
+#ifndef BUFFER_OFFSET
+#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
+#endif
+
+namespace mbgl {
+
+class PlainShader;
+
+class DebugBucket : public Bucket {
+public:
+ DebugBucket(DebugFontBuffer& fontBuffer);
+
+ virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
+ virtual bool hasData() const;
+
+ void drawLines(PlainShader& shader);
+ void drawPoints(PlainShader& shader);
+
+private:
+ DebugFontBuffer& fontBuffer;
+ VertexArrayObject array;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/renderer/fill_bucket.hpp b/include/mbgl/renderer/fill_bucket.hpp
new file mode 100644
index 0000000000..9193b09149
--- /dev/null
+++ b/include/mbgl/renderer/fill_bucket.hpp
@@ -0,0 +1,88 @@
+#ifndef MBGL_RENDERER_FILLBUCKET
+#define MBGL_RENDERER_FILLBUCKET
+
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/geometry/elements_buffer.hpp>
+#include <mbgl/geometry/fill_buffer.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+#include <clipper/clipper.hpp>
+#include <libtess2/tesselator.h>
+
+#include <vector>
+#include <memory>
+
+#ifndef BUFFER_OFFSET
+#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
+#endif
+
+namespace mbgl {
+
+class Style;
+class FillVertexBuffer;
+class TriangleElementsBuffer;
+class LineElementsBuffer;
+class BucketDescription;
+class OutlineShader;
+class PlainShader;
+class PatternShader;
+struct pbf;
+
+class FillBucket : public Bucket {
+
+ static void *alloc(void *data, unsigned int size);
+ static void *realloc(void *data, void *ptr, unsigned int size);
+ static void free(void *userData, void *ptr);
+
+
+ typedef ElementGroup triangle_group_type;
+ typedef ElementGroup line_group_type;
+public:
+ FillBucket(FillVertexBuffer& vertexBuffer,
+ TriangleElementsBuffer& triangleElementsBuffer,
+ LineElementsBuffer& lineElementsBuffer,
+ const StyleBucketFill& properties);
+ ~FillBucket();
+
+ virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
+ virtual bool hasData() const;
+
+ void addGeometry(pbf& data);
+ void tessellate();
+
+ void drawElements(PlainShader& shader);
+ void drawElements(PatternShader& shader);
+ void drawVertices(OutlineShader& shader);
+
+public:
+ const StyleBucketFill &properties;
+
+private:
+ TESSalloc *allocator;
+ TESStesselator *tesselator;
+ ClipperLib::Clipper clipper;
+
+ FillVertexBuffer& vertexBuffer;
+ TriangleElementsBuffer& triangleElementsBuffer;
+ LineElementsBuffer& lineElementsBuffer;
+
+ // hold information on where the vertices are located in the FillBuffer
+ const size_t vertex_start;
+ const size_t triangle_elements_start;
+ const size_t line_elements_start;
+ VertexArrayObject array;
+
+ std::vector<triangle_group_type> triangleGroups;
+ std::vector<line_group_type> lineGroups;
+
+ std::vector<ClipperLib::IntPoint> line;
+ bool hasVertices = false;
+
+ static const int vertexSize = 2;
+ static const int stride = sizeof(TESSreal) * vertexSize;
+ static const int vertices_per_group = 3;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/renderer/frame_history.hpp b/include/mbgl/renderer/frame_history.hpp
new file mode 100644
index 0000000000..a5dbe21bca
--- /dev/null
+++ b/include/mbgl/renderer/frame_history.hpp
@@ -0,0 +1,32 @@
+#ifndef MBGL_RENDERER_FRAME_HISTORY
+#define MBGL_RENDERER_FRAME_HISTORY
+
+#include <deque>
+#include <cassert>
+#include <cmath>
+
+#include <mbgl/platform/platform.hpp>
+#include <mbgl/util/time.hpp>
+
+namespace mbgl {
+
+struct FrameSnapshot {
+ explicit inline FrameSnapshot(timestamp t, float z) : t(t), z(z) {}
+ float t;
+ float z;
+};
+
+class FrameHistory {
+public:
+ // Record frame history that will be used to calculate fading params
+ void record(timestamp now, float zoom);
+
+ bool needsAnimation(timestamp duration) const;
+
+public:
+ std::deque<FrameSnapshot> history;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/renderer/icon_bucket.hpp b/include/mbgl/renderer/icon_bucket.hpp
new file mode 100644
index 0000000000..e3b311332d
--- /dev/null
+++ b/include/mbgl/renderer/icon_bucket.hpp
@@ -0,0 +1,53 @@
+#ifndef MBGL_RENDERER_ICONBUCKET
+#define MBGL_RENDERER_ICONBUCKET
+
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/geometry/elements_buffer.hpp>
+#include <mbgl/geometry/icon_buffer.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+#include <vector>
+#include <memory>
+
+#ifndef BUFFER_OFFSET
+#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
+#endif
+
+namespace mbgl {
+
+class Style;
+class IconVertexBuffer;
+class BucketDescription;
+class IconShader;
+class DotShader;
+class SpriteAtlas;
+class VectorTileFeature;
+
+class IconBucket : public Bucket {
+public:
+ IconBucket(IconVertexBuffer& vertexBuffer,
+ const StyleBucketIcon& properties);
+
+ virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
+ virtual bool hasData() const;
+
+ void addFeature(const VectorTileFeature &feature, SpriteAtlas &sprite_atlas);
+
+ void drawIcons(IconShader& shader);
+ void drawIcons(DotShader& shader);
+
+public:
+ const StyleBucketIcon &properties;
+
+private:
+
+ IconVertexBuffer& vertexBuffer;
+ VertexArrayObject array;
+
+ const size_t vertex_start;
+ size_t vertex_end = 0;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/renderer/line_bucket.hpp b/include/mbgl/renderer/line_bucket.hpp
new file mode 100644
index 0000000000..d42b10bfb7
--- /dev/null
+++ b/include/mbgl/renderer/line_bucket.hpp
@@ -0,0 +1,61 @@
+#ifndef MBGL_RENDERER_LINEBUCKET
+#define MBGL_RENDERER_LINEBUCKET
+
+#include "bucket.hpp"
+#include <mbgl/geometry/vao.hpp>
+#include <mbgl/geometry/elements_buffer.hpp>
+#include <mbgl/geometry/line_buffer.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+#include <memory>
+#include <vector>
+
+namespace mbgl {
+
+class Style;
+class LineVertexBuffer;
+class TriangleElementsBuffer;
+class LineShader;
+class LinejoinShader;
+struct pbf;
+
+class LineBucket : public Bucket {
+ typedef ElementGroup triangle_group_type;
+ typedef ElementGroup point_group_type;
+public:
+ LineBucket(LineVertexBuffer& vertexBuffer,
+ TriangleElementsBuffer& triangleElementsBuffer,
+ PointElementsBuffer& pointElementsBuffer,
+ const StyleBucketLine& properties);
+
+ virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
+ virtual bool hasData() const;
+
+ void addGeometry(pbf& data);
+ void addGeometry(const std::vector<Coordinate>& line);
+
+ bool hasPoints() const;
+
+ void drawLines(LineShader& shader);
+ void drawPoints(LinejoinShader& shader);
+
+public:
+ const StyleBucketLine &properties;
+
+private:
+
+ LineVertexBuffer& vertexBuffer;
+ TriangleElementsBuffer& triangleElementsBuffer;
+ PointElementsBuffer& pointElementsBuffer;
+
+ const size_t vertex_start;
+ const size_t triangle_elements_start;
+ const size_t point_elements_start;
+
+ std::vector<triangle_group_type> triangleGroups;
+ std::vector<point_group_type> pointGroups;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/renderer/painter.hpp b/include/mbgl/renderer/painter.hpp
new file mode 100644
index 0000000000..9868b5d9da
--- /dev/null
+++ b/include/mbgl/renderer/painter.hpp
@@ -0,0 +1,219 @@
+#ifndef MBGL_RENDERER_PAINTER
+#define MBGL_RENDERER_PAINTER
+
+#include <mbgl/map/tile_data.hpp>
+#include <mbgl/geometry/vao.hpp>
+#include <mbgl/geometry/vertex_buffer.hpp>
+#include <mbgl/util/mat4.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/renderer/frame_history.hpp>
+#include <mbgl/style/types.hpp>
+
+#include <mbgl/shader/plain_shader.hpp>
+#include <mbgl/shader/outline_shader.hpp>
+#include <mbgl/shader/pattern_shader.hpp>
+#include <mbgl/shader/line_shader.hpp>
+#include <mbgl/shader/linejoin_shader.hpp>
+#include <mbgl/shader/icon_shader.hpp>
+#include <mbgl/shader/raster_shader.hpp>
+#include <mbgl/shader/text_shader.hpp>
+#include <mbgl/shader/dot_shader.hpp>
+#include <mbgl/shader/composite_shader.hpp>
+#include <mbgl/shader/gaussian_shader.hpp>
+
+#include <mbgl/map/transform_state.hpp>
+
+#include <map>
+#include <unordered_map>
+#include <set>
+
+namespace mbgl {
+
+class Transform;
+class Style;
+class Tile;
+class GlyphAtlas;
+class Source;
+class StyleSource;
+
+class FillBucket;
+class LineBucket;
+class IconBucket;
+class TextBucket;
+class RasterBucket;
+
+struct FillProperties;
+struct CompositeProperties;
+
+class LayerDescription;
+class RasterTileData;
+
+class Painter : private util::noncopyable {
+public:
+ Painter(Map &map);
+ ~Painter();
+
+
+ void setup();
+
+ // Perform cleanup tasks that prepare shutting down the app. This doesn't mean that the
+ // app will be shut down. That means all operations must be automatically be reversed (e.g. through
+ // lazy initialization) in case rendering continues.
+ void cleanup();
+
+
+ void clear();
+
+ // Updates the default matrices to the current viewport dimensions.
+ void changeMatrix();
+
+ // Renders a particular layer from a tile.
+ void renderTileLayer(const Tile& tile, std::shared_ptr<StyleLayer> layer_desc);
+
+ // Renders debug information for a tile.
+ void renderTileDebug(const Tile& tile);
+
+ // Renders the backdrop of the OpenGL view. This also paints in areas where we don't have any
+ // tiles whatsoever.
+ void renderMatte();
+
+ // Renders the red debug frame around a tile, visualizing its perimeter.
+ void renderDebugFrame();
+
+ void renderDebugText(DebugBucket& bucket);
+ void renderDebugText(const std::vector<std::string> &strings);
+ void renderFill(FillBucket& bucket, const FillProperties& properties, const Tile::ID& id, const mat4 &mat);
+ void renderFill(FillBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
+ void renderLine(LineBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
+ void renderIcon(IconBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
+ void renderText(TextBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
+ void renderRaster(RasterBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
+
+ void preparePrerender(PrerenderedTexture &texture);
+ void finishPrerender(PrerenderedTexture &texture);
+
+ template <typename Properties>
+ void renderPrerenderedTexture(PrerenderedTexture &texture, const Properties &properties);
+
+ void resize();
+
+ // Changes whether debug information is drawn onto the map
+ void setDebug(bool enabled);
+
+ // Opaque/Translucent pass setting
+ void setOpaque();
+ void setTranslucent();
+
+ // Configures the painter strata that is used for early z-culling of fragments.
+ void setStrata(float strata);
+
+ void drawClippingMasks(const std::set<std::shared_ptr<StyleSource>> &sources);
+ void drawClippingMask(const mat4& matrix, const ClipID& clip);
+
+ void clearFramebuffers();
+ void resetFramebuffer();
+ void bindFramebuffer();
+ void pushFramebuffer();
+ GLuint popFramebuffer();
+ void discardFramebuffers();
+ void drawComposite(GLuint texture, const CompositeProperties &properties);
+
+ bool needsAnimation() const;
+private:
+ void setupShaders();
+ const mat4 &translatedMatrix(const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchorType anchor = TranslateAnchorType::Default);
+
+ void prepareTile(const Tile& tile);
+
+public:
+ void useProgram(uint32_t program);
+ void lineWidth(float lineWidth);
+ void depthMask(bool value);
+
+public:
+ mat4 matrix;
+ mat4 vtxMatrix;
+ mat4 projMatrix;
+ mat4 nativeMatrix;
+ mat4 extrudeMatrix;
+
+ // used to composite images and flips the geometry upside down
+ const mat4 flipMatrix = []{
+ mat4 flipMatrix;
+ matrix::ortho(flipMatrix, 0, 4096, -4096, 0, 0, 1);
+ matrix::translate(flipMatrix, flipMatrix, 0, -4096, 0);
+ return flipMatrix;
+ }();
+
+private:
+ Map& map;
+
+ FrameHistory frameHistory;
+
+ bool debug = false;
+
+ uint32_t gl_program = 0;
+ float gl_lineWidth = 0;
+ bool gl_depthMask = true;
+ std::array<uint16_t, 2> gl_viewport = {{ 0, 0 }};
+ float strata = 0;
+ enum { Opaque, Translucent } pass = Opaque;
+ const float strata_epsilon = 1.0f / (1 << 16);
+
+public:
+ std::unique_ptr<PlainShader> plainShader;
+ std::unique_ptr<OutlineShader> outlineShader;
+ std::unique_ptr<LineShader> lineShader;
+ std::unique_ptr<LinejoinShader> linejoinShader;
+ std::unique_ptr<PatternShader> patternShader;
+ std::unique_ptr<IconShader> iconShader;
+ std::unique_ptr<RasterShader> rasterShader;
+ std::unique_ptr<TextShader> textShader;
+ std::unique_ptr<DotShader> dotShader;
+ std::unique_ptr<CompositeShader> compositeShader;
+ std::unique_ptr<GaussianShader> gaussianShader;
+
+ // Set up the stencil quad we're using to generate the stencil mask.
+ VertexBuffer tileStencilBuffer = {
+ // top left triangle
+ 0, 0,
+ 4096, 0,
+ 0, 4096,
+
+ // bottom right triangle
+ 4096, 0,
+ 0, 4096,
+ 4096, 4096
+ };
+
+ VertexArrayObject coveringPlainArray;
+ VertexArrayObject coveringPatternArray;
+ VertexArrayObject coveringRasterArray;
+ VertexArrayObject coveringGaussianArray;
+
+ VertexArrayObject compositeArray;
+ VertexArrayObject matteArray;
+
+ // Set up the tile boundary lines we're using to draw the tile outlines.
+ VertexBuffer tileBorderBuffer = {
+ 0, 0,
+ 4096, 0,
+ 4096, 4096,
+ 0, 4096,
+ 0, 0
+ };
+
+ VertexArrayObject tileBorderArray;
+
+ // Framebuffer management
+ std::vector<GLuint> fbos;
+ std::vector<GLuint> fbos_color;
+ GLuint fbo_depth_stencil;
+ int fbo_level = -1;
+ bool fbo_depth_stencil_valid = false;
+
+};
+
+}
+
+#endif
diff --git a/include/mbgl/renderer/prerendered_texture.hpp b/include/mbgl/renderer/prerendered_texture.hpp
new file mode 100644
index 0000000000..9c72e14b88
--- /dev/null
+++ b/include/mbgl/renderer/prerendered_texture.hpp
@@ -0,0 +1,36 @@
+#ifndef MBGL_RENDERER_PRERENDERED_TEXTURE
+#define MBGL_RENDERER_PRERENDERED_TEXTURE
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/platform/gl.hpp>
+#include <mbgl/style/rasterize_properties.hpp>
+
+namespace mbgl {
+
+class Painter;
+
+class PrerenderedTexture : private util::noncopyable {
+public:
+ PrerenderedTexture(const RasterizedProperties &properties);
+ ~PrerenderedTexture();
+
+ void bindTexture();
+ void bindFramebuffer();
+ void unbindFramebuffer();
+
+ inline GLuint getTexture() const { return texture; }
+
+ void blur(Painter& painter, uint16_t passes);
+
+public:
+ const RasterizedProperties properties;
+
+private:
+ GLint previous_fbo = 0;
+ GLuint fbo = 0;
+ GLuint texture = 0;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/renderer/raster_bucket.hpp b/include/mbgl/renderer/raster_bucket.hpp
new file mode 100644
index 0000000000..c111193126
--- /dev/null
+++ b/include/mbgl/renderer/raster_bucket.hpp
@@ -0,0 +1,30 @@
+#ifndef MBGL_RENDERER_RASTERBUCKET
+#define MBGL_RENDERER_RASTERBUCKET
+
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/util/raster.hpp>
+
+namespace mbgl {
+
+class RasterShader;
+class VertexBuffer;
+class VertexArrayObject;
+
+class RasterBucket : public Bucket {
+public:
+ RasterBucket(const std::shared_ptr<Texturepool> &texturepool);
+
+ virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
+ virtual bool hasData() const;
+
+ bool setImage(const std::string &data);
+
+ void drawRaster(RasterShader& shader, VertexBuffer &vertices, VertexArrayObject &array);
+
+private:
+ Raster raster;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/renderer/text_bucket.hpp b/include/mbgl/renderer/text_bucket.hpp
new file mode 100644
index 0000000000..cb4b8f2cda
--- /dev/null
+++ b/include/mbgl/renderer/text_bucket.hpp
@@ -0,0 +1,61 @@
+#ifndef MBGL_RENDERER_TEXTBUCKET
+#define MBGL_RENDERER_TEXTBUCKET
+
+#include "bucket.hpp"
+#include <mbgl/geometry/vao.hpp>
+#include <mbgl/geometry/elements_buffer.hpp>
+#include <mbgl/map/vector_tile.hpp>
+#include <mbgl/text/types.hpp>
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+#include <memory>
+#include <map>
+#include <vector>
+
+namespace mbgl {
+
+class Style;
+class TextVertexBuffer;
+class TriangleElementsBuffer;
+class TextShader;
+class Placement;
+struct pbf;
+
+class TextBucket : public Bucket {
+ typedef ElementGroup triangle_group_type;
+
+public:
+ TextBucket(
+ TextVertexBuffer &vertexBuffer,
+ TriangleElementsBuffer &triangleElementsBuffer,
+ const StyleBucketText &properties, Placement &placement);
+
+ virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID &id);
+ virtual bool hasData() const;
+
+ void addGlyphs(const PlacedGlyphs &glyphs, float placementZoom,
+ PlacementRange placementRange, float zoom);
+
+ void addFeature(const pbf &geometry,
+ const GlyphPositions &face,
+ const Shaping &shaping);
+
+ void drawGlyphs(TextShader &shader);
+
+public:
+ const StyleBucketText &properties;
+
+private:
+ TextVertexBuffer& vertexBuffer;
+ TriangleElementsBuffer& triangleElementsBuffer;
+ Placement &placement;
+
+ const size_t vertex_start;
+ const size_t triangle_elements_start;
+
+ std::vector<triangle_group_type> triangleGroups;
+};
+}
+
+#endif
diff --git a/include/mbgl/shader/composite_shader.hpp b/include/mbgl/shader/composite_shader.hpp
new file mode 100644
index 0000000000..c0c1704f3d
--- /dev/null
+++ b/include/mbgl/shader/composite_shader.hpp
@@ -0,0 +1,29 @@
+#ifndef MBGL_SHADER_COMPOSITE_SHADER
+#define MBGL_SHADER_COMPOSITE_SHADER
+
+#include <mbgl/shader/shader.hpp>
+
+namespace mbgl {
+
+class CompositeShader : public Shader {
+public:
+ CompositeShader();
+
+ void bind(char *offset);
+
+ void setImage(int32_t image);
+ void setOpacity(float opacity);
+
+private:
+ int32_t a_pos = -1;
+
+ int32_t image = 0;
+ int32_t u_image = -1;
+
+ float opacity = 0;
+ int32_t u_opacity = -1;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/shader/dot_shader.hpp b/include/mbgl/shader/dot_shader.hpp
new file mode 100644
index 0000000000..d8d649db9c
--- /dev/null
+++ b/include/mbgl/shader/dot_shader.hpp
@@ -0,0 +1,33 @@
+#ifndef MBGL_SHADER_SHADER_DOT
+#define MBGL_SHADER_SHADER_DOT
+
+#include <mbgl/shader/shader.hpp>
+
+namespace mbgl {
+
+ class DotShader : public Shader {
+ public:
+ DotShader();
+
+ void bind(char *offset);
+
+ void setColor(const std::array<float, 4>& color);
+ void setSize(float size);
+ void setBlur(float blur);
+
+ private:
+ int32_t a_pos = -1;
+
+ std::array<float, 4> color = {{}};
+ int32_t u_color = -1;
+
+ float size = 0;
+ int32_t u_size = -1;
+
+ float blur = 0;
+ int32_t u_blur = -1;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/shader/gaussian_shader.hpp b/include/mbgl/shader/gaussian_shader.hpp
new file mode 100644
index 0000000000..a4b9d09f3a
--- /dev/null
+++ b/include/mbgl/shader/gaussian_shader.hpp
@@ -0,0 +1,29 @@
+#ifndef MBGL_RENDERER_SHADER_GAUSSIAN
+#define MBGL_RENDERER_SHADER_GAUSSIAN
+
+#include <mbgl/shader/shader.hpp>
+
+namespace mbgl {
+
+class GaussianShader : public Shader {
+public:
+ GaussianShader();
+
+ void bind(char *offset);
+
+ void setImage(int32_t image);
+ void setOffset(const std::array<float, 2>& offset);
+
+private:
+ int32_t a_pos = -1;
+
+ int32_t image = 0;
+ int32_t u_image = -1;
+
+ std::array<float, 2> offset = {{}};
+ int32_t u_offset = -1;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/shader/icon_shader.hpp b/include/mbgl/shader/icon_shader.hpp
new file mode 100644
index 0000000000..b97b3c2be3
--- /dev/null
+++ b/include/mbgl/shader/icon_shader.hpp
@@ -0,0 +1,42 @@
+#ifndef MBGL_SHADER_SHADER_ICON
+#define MBGL_SHADER_SHADER_ICON
+
+#include <mbgl/shader/shader.hpp>
+
+namespace mbgl {
+
+class IconShader : public Shader {
+public:
+ IconShader();
+
+ void bind(char *offset);
+
+ void setImage(int32_t image);
+ void setColor(const std::array<float, 4>& color);
+ void setDimension(const std::array<float, 2>& dimension);
+ void setSize(float size);
+ void setRatio(float ratio);
+
+private:
+ int32_t a_pos = -1;
+ int32_t a_tex = -1;
+
+ int32_t image = -1;
+ int32_t u_image = -1;
+
+ std::array<float, 4> color = {{}};
+ int32_t u_color = -1;
+
+ std::array<float, 2> dimension = {{}};
+ int32_t u_dimension = -1;
+
+ float size = 0;
+ int32_t u_size = -1;
+
+ float ratio = 0;
+ int32_t u_ratio = -1;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/shader/line_shader.hpp b/include/mbgl/shader/line_shader.hpp
new file mode 100644
index 0000000000..38efe0b71f
--- /dev/null
+++ b/include/mbgl/shader/line_shader.hpp
@@ -0,0 +1,45 @@
+#ifndef MBGL_SHADER_SHADER_LINE
+#define MBGL_SHADER_SHADER_LINE
+
+#include <mbgl/shader/shader.hpp>
+
+namespace mbgl {
+
+class LineShader : public Shader {
+public:
+ LineShader();
+
+ void bind(char *offset);
+
+ void setExtrudeMatrix(const std::array<float, 16>& exmatrix);
+ void setColor(const std::array<float, 4>& color);
+ void setLineWidth(const std::array<float, 2>& linewidth);
+ void setRatio(float ratio);
+ void setDashArray(const std::array<float, 2>& dasharray);
+ void setDebug(float debug);
+
+private:
+ int32_t a_pos = -1;
+ int32_t a_extrude = -1;
+ int32_t a_linesofar = -1;
+
+ std::array<float, 16> exmatrix = {{}};
+ int32_t u_exmatrix = -1;
+
+ std::array<float, 4> color = {{}};
+ int32_t u_color = -1;
+
+ std::array<float, 2> linewidth = {{}};
+ int32_t u_linewidth = -1;
+
+ float ratio = 0;
+ int32_t u_ratio = -1;
+
+ std::array<float, 2> dasharray = {{}};
+ int32_t u_dasharray = -1;
+};
+
+
+}
+
+#endif
diff --git a/include/mbgl/shader/linejoin_shader.hpp b/include/mbgl/shader/linejoin_shader.hpp
new file mode 100644
index 0000000000..5a5c97e921
--- /dev/null
+++ b/include/mbgl/shader/linejoin_shader.hpp
@@ -0,0 +1,37 @@
+#ifndef MBGL_SHADER_SHADER_LINEJOIN
+#define MBGL_SHADER_SHADER_LINEJOIN
+
+#include <mbgl/shader/shader.hpp>
+
+namespace mbgl {
+
+class LinejoinShader : public Shader {
+public:
+ LinejoinShader();
+
+ void bind(char *offset);
+
+ void setColor(const std::array<float, 4>& color);
+ void setWorld(const std::array<float, 2>& world);
+ void setLineWidth(const std::array<float, 2>& linewidth);
+ void setSize(float size);
+
+private:
+ int32_t a_pos = -1;
+
+ std::array<float, 4> color = {{}};
+ int32_t u_color = -1;
+
+ std::array<float, 2> world = {{}};
+ int32_t u_world = -1;
+
+ std::array<float, 2> linewidth = {{}};
+ int32_t u_linewidth = -1;
+
+ float size = 0;
+ int32_t u_size = -1;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/shader/outline_shader.hpp b/include/mbgl/shader/outline_shader.hpp
new file mode 100644
index 0000000000..551e31ca57
--- /dev/null
+++ b/include/mbgl/shader/outline_shader.hpp
@@ -0,0 +1,29 @@
+#ifndef MBGL_SHADER_SHADER_OUTLINE
+#define MBGL_SHADER_SHADER_OUTLINE
+
+#include <mbgl/shader/shader.hpp>
+
+namespace mbgl {
+
+class OutlineShader : public Shader {
+public:
+ OutlineShader();
+
+ void bind(char *offset);
+
+ void setColor(const std::array<float, 4>& color);
+ void setWorld(const std::array<float, 2>& world);
+
+private:
+ int32_t a_pos = -1;
+
+ std::array<float, 4> color = {{}};
+ int32_t u_color = -1;
+
+ std::array<float, 2> world = {{}};
+ int32_t u_world = -1;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/shader/pattern_shader.hpp b/include/mbgl/shader/pattern_shader.hpp
new file mode 100644
index 0000000000..b1b49b54df
--- /dev/null
+++ b/include/mbgl/shader/pattern_shader.hpp
@@ -0,0 +1,45 @@
+#ifndef MBGL_SHADER_SHADER_PATTERN
+#define MBGL_SHADER_SHADER_PATTERN
+
+#include <mbgl/shader/shader.hpp>
+
+namespace mbgl {
+
+class PatternShader : public Shader {
+public:
+ PatternShader();
+
+ void bind(char *offset);
+
+ void setColor(const std::array<float, 4>& color);
+ void setOffset(const std::array<float, 2>& offset);
+ void setPatternSize(const std::array<float, 2>& pattern_size);
+ void setPatternTopLeft(const std::array<float, 2>& pattern_tl);
+ void setPatternBottomRight(const std::array<float, 2>& pattern_br);
+ void setMix(float mix);
+
+private:
+ int32_t a_pos = -1;
+
+ std::array<float, 4> color = {{}};
+ int32_t u_color = -1;
+
+ std::array<float, 2> offset = {{}};
+ int32_t u_offset = -1;
+
+ std::array<float, 2> pattern_size = {{}};
+ int32_t u_pattern_size = -1;
+
+ std::array<float, 2> pattern_tl = {{}};
+ int32_t u_pattern_tl = -1;
+
+ std::array<float, 2> pattern_br = {{}};
+ int32_t u_pattern_br = -1;
+
+ float mix = 0;
+ int32_t u_mix = -1;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/shader/plain_shader.hpp b/include/mbgl/shader/plain_shader.hpp
new file mode 100644
index 0000000000..277788431f
--- /dev/null
+++ b/include/mbgl/shader/plain_shader.hpp
@@ -0,0 +1,26 @@
+#ifndef MBGL_SHADER_SHADER_PLAIN
+#define MBGL_SHADER_SHADER_PLAIN
+
+#include <mbgl/shader/shader.hpp>
+
+namespace mbgl {
+
+class PlainShader : public Shader {
+public:
+ PlainShader();
+
+ void bind(char *offset);
+
+ void setColor(float r, float g, float b, float a);
+ void setColor(const std::array<float, 4>& color);
+
+private:
+ int32_t a_pos = -1;
+
+ std::array<float, 4> color = {{}};
+ int32_t u_color = -1;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/shader/raster_shader.hpp b/include/mbgl/shader/raster_shader.hpp
new file mode 100644
index 0000000000..ec69fa7238
--- /dev/null
+++ b/include/mbgl/shader/raster_shader.hpp
@@ -0,0 +1,33 @@
+#ifndef MBGL_RENDERER_SHADER_RASTER
+#define MBGL_RENDERER_SHADER_RASTER
+
+#include <mbgl/shader/shader.hpp>
+
+namespace mbgl {
+
+class RasterShader : public Shader {
+public:
+ RasterShader();
+
+ void bind(char *offset);
+
+ void setImage(int32_t image);
+ void setOpacity(float opacity);
+ void setBuffer(float buffer);
+
+private:
+ int32_t a_pos = -1;
+
+ int32_t image = 0;
+ int32_t u_image = -1;
+
+ float opacity = 0;
+ int32_t u_opacity = -1;
+
+ float buffer = 0;
+ int32_t u_buffer = -1;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/shader/shader.hpp b/include/mbgl/shader/shader.hpp
new file mode 100644
index 0000000000..2398cb12e3
--- /dev/null
+++ b/include/mbgl/shader/shader.hpp
@@ -0,0 +1,29 @@
+#ifndef MBGL_RENDERER_SHADER
+#define MBGL_RENDERER_SHADER
+
+#include <cstdint>
+#include <array>
+#include <mbgl/util/noncopyable.hpp>
+
+namespace mbgl {
+
+class Shader : private util::noncopyable {
+public:
+ Shader(const char *vertex, const char *fragment);
+ ~Shader();
+ bool valid;
+ uint32_t program;
+
+ void setMatrix(const std::array<float, 16>& matrix);
+
+private:
+ bool compileShader(uint32_t *shader, uint32_t type, const char *source);
+
+protected:
+ std::array<float, 16> matrix = {{}};
+ int32_t u_matrix = -1;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/shader/text_shader.hpp b/include/mbgl/shader/text_shader.hpp
new file mode 100644
index 0000000000..554b890fb0
--- /dev/null
+++ b/include/mbgl/shader/text_shader.hpp
@@ -0,0 +1,72 @@
+#ifndef MBGL_SHADER_TEXT_SHADER
+#define MBGL_SHADER_TEXT_SHADER
+
+#include "shader.hpp"
+
+namespace mbgl {
+
+class TextShader : public Shader {
+public:
+ TextShader();
+
+ void bind(char *offset);
+
+ void setColor(float r, float g, float b, float a);
+ void setColor(const std::array<float, 4> &color);
+ void setBuffer(float buffer);
+ void setGamma(float gamma);
+ void setExtrudeMatrix(const std::array<float, 16> &exmatrix);
+ void setAngle(float angle);
+ void setZoom(float zoom);
+ void setFlip(float flip);
+ void setFadeDist(float fadedist);
+ void setMinFadeZoom(float minfadezoom);
+ void setMaxFadeZoom(float maxfadezoom);
+ void setFadeZoom(float fadezoom);
+ void setTextureSize(const std::array<float, 2> &texsize);
+
+private:
+ int32_t a_pos = -1;
+ int32_t a_offset = -1;
+ int32_t a_data1 = -1;
+ int32_t a_data2 = -1;
+
+ std::array<float, 4> color = {{}};
+ int32_t u_color = -1;
+
+ float buffer = 0.0f;
+ int32_t u_buffer = -1;
+
+ float gamma = 0.0f;
+ int32_t u_gamma = -1;
+
+ std::array<float, 16> exmatrix = {{}};
+ int32_t u_exmatrix = -1;
+
+ float angle = 0.0f;
+ int32_t u_angle = -1;
+
+ float zoom = 0.0f;
+ int32_t u_zoom = -1;
+
+ float flip = 0.0f;
+ int32_t u_flip = -1;
+
+ float fadedist = 0.0f;
+ int32_t u_fadedist = -1;
+
+ float minfadezoom = 0.0f;
+ int32_t u_minfadezoom = -1;
+
+ float maxfadezoom = 0.0f;
+ int32_t u_maxfadezoom = -1;
+
+ float fadezoom = 0.0f;
+ int32_t u_fadezoom = -1;
+
+ std::array<float, 2> texsize = {{}};
+ int32_t u_texsize = -1;
+};
+}
+
+#endif
diff --git a/include/mbgl/style/applied_class_properties.hpp b/include/mbgl/style/applied_class_properties.hpp
new file mode 100644
index 0000000000..827f15a2a1
--- /dev/null
+++ b/include/mbgl/style/applied_class_properties.hpp
@@ -0,0 +1,39 @@
+#ifndef MBGL_STYLE_APPLIED_CLASS_PROPERTIES
+#define MBGL_STYLE_APPLIED_CLASS_PROPERTIES
+
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/class_dictionary.hpp>
+#include <mbgl/util/time.hpp>
+
+#include <list>
+
+namespace mbgl {
+
+class AppliedClassProperty {
+public:
+ AppliedClassProperty(ClassID class_id, timestamp begin, timestamp end, const PropertyValue &value);
+
+public:
+ const ClassID name;
+ const timestamp begin;
+ const timestamp end;
+ const PropertyValue value;
+};
+
+
+class AppliedClassProperties {
+public:
+ std::list<AppliedClassProperty> properties;
+
+public:
+ // Returns thie ID of the most recent
+ ClassID mostRecent() const;
+ void add(ClassID class_id, timestamp begin, timestamp end, const PropertyValue &value);
+ bool hasTransitions() const;
+ void cleanup(timestamp now);
+ bool empty() const;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/class_dictionary.hpp b/include/mbgl/style/class_dictionary.hpp
new file mode 100644
index 0000000000..c7f9c6a284
--- /dev/null
+++ b/include/mbgl/style/class_dictionary.hpp
@@ -0,0 +1,32 @@
+#ifndef MBGL_STYLE_CLASS_DICTIONARY
+#define MBGL_STYLE_CLASS_DICTIONARY
+
+#include <cstdint>
+#include <string>
+#include <unordered_map>
+
+namespace mbgl {
+
+enum class ClassID : uint32_t {
+ Fallback = 0, // These values are from the fallback properties
+ Default = 1, // These values are from the default style for a layer
+ Named = 2 // These values (and all subsequent IDs) are from a named style from the layer
+};
+
+class ClassDictionary {
+public:
+ // Returns an ID for a class name. If the class name does not yet have an ID, one is
+ // auto-generated and stored for future reference.
+ static ClassID Lookup(const std::string &class_name);
+
+ // Returns either Fallback, Default or Named, depending on the type of the class id.
+ static ClassID Normalize(ClassID id);
+
+private:
+ static std::unordered_map<std::string, ClassID> store;
+ static uint32_t offset;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/class_properties.hpp b/include/mbgl/style/class_properties.hpp
new file mode 100644
index 0000000000..84b6f483bd
--- /dev/null
+++ b/include/mbgl/style/class_properties.hpp
@@ -0,0 +1,43 @@
+#ifndef MBGL_STYLE_CLASS_PROPERTIES
+#define MBGL_STYLE_CLASS_PROPERTIES
+
+#include <mbgl/style/property_key.hpp>
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/property_transition.hpp>
+
+#include <map>
+
+namespace mbgl {
+
+class ClassProperties {
+public:
+ inline ClassProperties() {}
+ inline ClassProperties(ClassProperties &&properties)
+ : properties(std::move(properties.properties)) {}
+
+ inline void set(PropertyKey key, const PropertyValue &value) {
+ properties.emplace(key, value);
+ }
+
+ inline void set(PropertyKey key, const PropertyTransition &transition) {
+ transitions.emplace(key, transition);
+ }
+
+ const PropertyTransition &getTransition(PropertyKey key, const PropertyTransition &defaultTransition) const;
+
+ // Route-through iterable interface so that you can iterate on the object as is.
+ inline std::map<PropertyKey, PropertyValue>::const_iterator begin() const {
+ return properties.begin();
+ }
+ inline std::map<PropertyKey, PropertyValue>::const_iterator end() const {
+ return properties.end();
+ }
+
+public:
+ std::map<PropertyKey, PropertyValue> properties;
+ std::map<PropertyKey, PropertyTransition> transitions;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/filter_comparison.hpp b/include/mbgl/style/filter_comparison.hpp
new file mode 100644
index 0000000000..bf48744f1e
--- /dev/null
+++ b/include/mbgl/style/filter_comparison.hpp
@@ -0,0 +1,65 @@
+#ifndef MBGL_STYLE_FILTER_COMPARISON
+#define MBGL_STYLE_FILTER_COMPARISON
+
+#include <mbgl/style/value.hpp>
+
+#include <vector>
+#include <string>
+#include <iosfwd>
+
+namespace mbgl {
+
+class FilterComparison {
+public:
+ enum class Operator : uint8_t {
+ Equal,
+ NotEqual,
+ Greater,
+ GreaterEqual,
+ Less,
+ LessEqual,
+ In,
+ NotIn
+ };
+
+ class Instance {
+ public:
+ Instance(Operator op, std::vector<Value> &&values)
+ : op(op), values(values) {}
+
+ bool compare(const std::vector<Value> &property_values) const;
+
+ private:
+ Operator op = Operator::Equal;
+ std::vector<Value> values;
+
+ friend std::ostream& operator <<(std::ostream &, const Instance &);
+ };
+
+public:
+ FilterComparison(const std::string &field) : field(field) {};
+
+ const std::string &getField() const;
+ template <typename Extractor> inline bool compare(const Extractor &extractor) const;
+
+ template <typename ...Args>
+ inline void add(Args&& ...args) {
+ instances.emplace_back(::std::forward<Args>(args)...);
+ }
+
+private:
+ std::string field;
+ std::vector<Instance> instances;
+
+ friend std::ostream& operator <<(std::ostream &, const FilterComparison &);
+};
+
+std::ostream& operator <<(std::ostream &s, const FilterComparison &comparison);
+std::ostream& operator <<(std::ostream &s, const FilterComparison::Instance &instance);
+
+
+FilterComparison::Operator parseFilterComparisonOperator(const std::string &op);
+
+}
+
+#endif
diff --git a/include/mbgl/style/filter_comparison_private.hpp b/include/mbgl/style/filter_comparison_private.hpp
new file mode 100644
index 0000000000..6486832424
--- /dev/null
+++ b/include/mbgl/style/filter_comparison_private.hpp
@@ -0,0 +1,23 @@
+#ifndef MBGL_STYLE_FILTER_COMPARISON_PRIVATE
+#define MBGL_STYLE_FILTER_COMPARISON_PRIVATE
+
+#include "filter_comparison.hpp"
+
+namespace mbgl {
+
+template <typename Extractor>
+inline bool FilterComparison::compare(const Extractor &extractor) const {
+ const std::vector<Value> values = extractor.getValues(field);
+
+ // All instances are ANDed together.
+ for (const Instance &instance : instances) {
+ if (!instance.compare(values)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+}
+
+#endif
diff --git a/include/mbgl/style/filter_expression.hpp b/include/mbgl/style/filter_expression.hpp
new file mode 100644
index 0000000000..2a6a2927e7
--- /dev/null
+++ b/include/mbgl/style/filter_expression.hpp
@@ -0,0 +1,54 @@
+#ifndef MBGL_STYLE_FILTER_EXPRESSION
+#define MBGL_STYLE_FILTER_EXPRESSION
+
+#include <mbgl/style/filter_comparison.hpp>
+#include <mbgl/util/recursive_wrapper.hpp>
+
+#include <iosfwd>
+
+namespace mbgl {
+
+class FilterExpression {
+public:
+ typedef util::recursive_wrapper<FilterExpression> Wrapper;
+
+ enum class Operator : uint8_t {
+ And,
+ Or,
+ Xor,
+ Nor
+ };
+
+ enum class GeometryType : uint8_t {
+ Any,
+ Point,
+ LineString,
+ Polygon
+ };
+
+public:
+ FilterExpression() = default;
+ FilterExpression(Operator op) : op(op) {};
+
+ bool empty() const;
+
+ template <typename Extractor> bool compare(const Extractor &extractor) const;
+ void add(const FilterComparison &comparison);
+ void add(const FilterExpression &expression);
+ void setGeometryType(GeometryType g);
+
+private:
+ Operator op = Operator::And;
+ GeometryType type = GeometryType::Any;
+ std::vector<FilterComparison> comparisons;
+ std::vector<FilterExpression::Wrapper> expressions;
+
+ friend std::ostream& operator <<(std::ostream &, const FilterExpression &);
+};
+
+std::ostream& operator <<(std::ostream &s, const FilterExpression &expression);
+
+FilterExpression::GeometryType parseGeometryType(const std::string &geometry);
+}
+
+#endif
diff --git a/include/mbgl/style/filter_expression_private.hpp b/include/mbgl/style/filter_expression_private.hpp
new file mode 100644
index 0000000000..9379d250ba
--- /dev/null
+++ b/include/mbgl/style/filter_expression_private.hpp
@@ -0,0 +1,75 @@
+#ifndef MBGL_STYLE_FILTER_EXPRESSION_PRIVATE
+#define MBGL_STYLE_FILTER_EXPRESSION_PRIVATE
+
+#include "filter_expression.hpp"
+#include "filter_comparison_private.hpp"
+
+namespace mbgl {
+
+template <typename Extractor>
+bool FilterExpression::compare(const Extractor &extractor) const {
+ if (type != GeometryType::Any && extractor.getType() != type && extractor.getType() != GeometryType::Any) {
+ return false;
+ }
+
+ switch (op) {
+ case Operator::And:
+ for (const FilterComparison &comparison : comparisons) {
+ if (!comparison.compare(extractor)) {
+ return false;
+ }
+ }
+ for (const FilterExpression &expression: expressions) {
+ if (!expression.compare(extractor)) {
+ return false;
+ }
+ }
+ return true;
+ case Operator::Or:
+ for (const FilterComparison &comparison : comparisons) {
+ if (comparison.compare(extractor)) {
+ return true;
+ }
+ }
+ for (const FilterExpression &expression: expressions) {
+ if (expression.compare(extractor)) {
+ return true;
+ }
+ }
+ return false;
+ case Operator::Xor: {
+ int count = 0;
+ for (const FilterComparison &comparison : comparisons) {
+ count += comparison.compare(extractor);
+ if (count > 1) {
+ return false;
+ }
+ }
+ for (const FilterExpression &expression: expressions) {
+ count += expression.compare(extractor);
+ if (count > 1) {
+ return false;
+ }
+ }
+ return count == 1;
+ }
+ case Operator::Nor:
+ for (const FilterComparison &comparison : comparisons) {
+ if (comparison.compare(extractor)) {
+ return false;
+ }
+ }
+ for (const FilterExpression &expression: expressions) {
+ if (expression.compare(extractor)) {
+ return false;
+ }
+ }
+ return true;
+ default:
+ return true;
+ }
+}
+
+}
+
+#endif
diff --git a/include/mbgl/style/function_properties.hpp b/include/mbgl/style/function_properties.hpp
new file mode 100644
index 0000000000..74ac80f83c
--- /dev/null
+++ b/include/mbgl/style/function_properties.hpp
@@ -0,0 +1,79 @@
+#ifndef MBGL_STYLE_FUNCTION_PROPERTIES
+#define MBGL_STYLE_FUNCTION_PROPERTIES
+
+#include <mbgl/util/variant.hpp>
+
+#include <vector>
+
+namespace mbgl {
+
+template <typename T>
+struct ConstantFunction {
+ inline ConstantFunction(const T &value) : value(value) {}
+ inline T evaluate(float) const { return value; }
+
+private:
+ const T value;
+};
+
+template <typename T>
+struct LinearFunction {
+ inline LinearFunction(const T &value, float z_base, float slope, const T &min, const T &max)
+ : value(value), min(min), max(max), z_base(z_base), slope(slope) {}
+ T evaluate(float z) const;
+
+private:
+ const T value, min, max;
+ const float z_base, slope;
+};
+
+template <typename T>
+struct ExponentialFunction {
+ inline ExponentialFunction(const T &value, float z_base, float exp_base, float slope, const T &min,
+ const T &max)
+ : value(value), min(min), max(max), z_base(z_base), exp_base(exp_base), slope(slope) {}
+ T evaluate(float z) const;
+
+private:
+ const T value, min, max;
+ const float z_base, exp_base, slope;
+};
+
+template <typename T>
+struct StopsFunction {
+ inline StopsFunction(const std::vector<std::pair<float, T>> &values) : values(values) {}
+ T evaluate(float z) const;
+
+private:
+ const std::vector<std::pair<float, T>> values;
+};
+
+template <typename T>
+using Function = util::variant<
+ std::false_type,
+ ConstantFunction<T>,
+ LinearFunction<T>,
+ ExponentialFunction<T>,
+ StopsFunction<T>
+>;
+
+template <typename T>
+struct FunctionEvaluator {
+ typedef T result_type;
+ inline FunctionEvaluator(float z) : z(z) {}
+
+ inline result_type operator()(const std::false_type &) {
+ return result_type();
+ }
+
+ template <template <typename> class Fn>
+ inline result_type operator()(const Fn<T>& fn) {
+ return fn.evaluate(z);
+ }
+private:
+ float z;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/property_fallback.hpp b/include/mbgl/style/property_fallback.hpp
new file mode 100644
index 0000000000..5c5eae0cd6
--- /dev/null
+++ b/include/mbgl/style/property_fallback.hpp
@@ -0,0 +1,29 @@
+#ifndef MBGL_STYLE_PROPERTY_FALLBACK
+#define MBGL_STYLE_PROPERTY_FALLBACK
+
+#include <mbgl/style/property_key.hpp>
+#include <mbgl/style/property_value.hpp>
+
+#include <map>
+
+namespace mbgl {
+
+class PropertyFallbackValue {
+public:
+ static const PropertyValue &Get(PropertyKey key) {
+ auto it = properties.find(key);
+ if (it != properties.end()) {
+ return it->second;
+ } else {
+ return defaultProperty;
+ }
+ }
+
+private:
+ static const std::map<PropertyKey, PropertyValue> properties;
+ static const PropertyValue defaultProperty;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/property_key.hpp b/include/mbgl/style/property_key.hpp
new file mode 100644
index 0000000000..d9005f2f4a
--- /dev/null
+++ b/include/mbgl/style/property_key.hpp
@@ -0,0 +1,57 @@
+#ifndef MBGL_STYLE_PROPERTY_KEY
+#define MBGL_STYLE_PROPERTY_KEY
+
+namespace mbgl {
+
+enum class PropertyKey {
+ FillAntialias,
+ FillOpacity,
+ FillColor,
+ FillOutlineColor,
+ FillTranslate, // for transitions only
+ FillTranslateX,
+ FillTranslateY,
+ FillTranslateAnchor,
+ FillImage,
+
+ LineOpacity,
+ LineColor,
+ LineTranslate, // for transitions only
+ LineTranslateX,
+ LineTranslateY,
+ LineTranslateAnchor,
+ LineWidth,
+ LineOffset,
+ LineBlur,
+ LineDashArray, // for transitions only
+ LineDashLand,
+ LineDashGap,
+ LineImage,
+
+ IconOpacity,
+ IconRotate,
+ IconRotateAnchor,
+
+ TextOpacity,
+ TextSize,
+ TextColor,
+ TextHaloColor,
+ TextHaloWidth,
+ TextHaloBlur,
+
+ CompositeOpacity,
+
+ RasterOpacity,
+ RasterSpin,
+ RasterBrightnessLow,
+ RasterBrightnessHigh,
+ RasterSaturation,
+ RasterContrast,
+ RasterFade,
+
+ BackgroundColor
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/property_transition.hpp b/include/mbgl/style/property_transition.hpp
new file mode 100644
index 0000000000..07b7cfe288
--- /dev/null
+++ b/include/mbgl/style/property_transition.hpp
@@ -0,0 +1,15 @@
+#ifndef MBGL_STYLE_PROPERTY_TRANSITION
+#define MBGL_STYLE_PROPERTY_TRANSITION
+
+#include <cstdint>
+
+namespace mbgl {
+
+struct PropertyTransition {
+ uint16_t duration = 0;
+ uint16_t delay = 0;
+};
+
+}
+
+#endif \ No newline at end of file
diff --git a/include/mbgl/style/property_value.hpp b/include/mbgl/style/property_value.hpp
new file mode 100644
index 0000000000..4d148dc029
--- /dev/null
+++ b/include/mbgl/style/property_value.hpp
@@ -0,0 +1,21 @@
+#ifndef MBGL_STYLE_PROPERTY_VALUE
+#define MBGL_STYLE_PROPERTY_VALUE
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/style/function_properties.hpp>
+#include <mbgl/style/types.hpp>
+
+namespace mbgl {
+
+typedef util::variant<
+ std::string,
+ TranslateAnchorType,
+ RotateAnchorType,
+ Function<bool>,
+ Function<float>,
+ Function<Color>
+> PropertyValue;
+
+}
+
+#endif
diff --git a/include/mbgl/style/rasterize_properties.hpp b/include/mbgl/style/rasterize_properties.hpp
new file mode 100644
index 0000000000..aea90dfbdd
--- /dev/null
+++ b/include/mbgl/style/rasterize_properties.hpp
@@ -0,0 +1,38 @@
+#ifndef MBGL_STYLE_RASTERIZE_PROPERTIES
+#define MBGL_STYLE_RASTERIZE_PROPERTIES
+
+#include <mbgl/style/function_properties.hpp>
+
+namespace mbgl {
+
+// The calculated properties for a layer in a tile.
+class RasterizedProperties {
+public:
+ float buffer = 1.0f / 32.0f;
+ uint16_t size = 256;
+ uint8_t blur = 0;
+};
+
+class RasterizeProperties {
+public:
+ Function<bool> enabled = ConstantFunction<bool>(false);
+ Function<float> buffer = ConstantFunction<float>(1.0f / 32.0f);
+ Function<float> size = ConstantFunction<float>(256);
+ Function<float> blur = ConstantFunction<float>(0);
+
+ inline bool isEnabled(const int8_t z) const {
+ return util::apply_visitor(FunctionEvaluator<bool>(z), enabled);
+ }
+
+ inline RasterizedProperties get(const int8_t z) const {
+ RasterizedProperties properties;
+ properties.buffer = util::apply_visitor(FunctionEvaluator<float>(z), buffer);
+ properties.size = util::apply_visitor(FunctionEvaluator<float>(z), size);
+ properties.blur = util::apply_visitor(FunctionEvaluator<float>(z), blur);
+ return properties;
+ }
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/style.hpp b/include/mbgl/style/style.hpp
new file mode 100644
index 0000000000..6aab71a4c6
--- /dev/null
+++ b/include/mbgl/style/style.hpp
@@ -0,0 +1,68 @@
+#ifndef MBGL_STYLE_STYLE
+#define MBGL_STYLE_STYLE
+
+#include <mbgl/style/property_transition.hpp>
+#include <mbgl/style/style_source.hpp>
+
+#include <mbgl/util/time.hpp>
+#include <mbgl/util/uv.hpp>
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include <unordered_map>
+#include <vector>
+#include <set>
+#include <memory>
+
+namespace mbgl {
+
+class Sprite;
+class StyleLayer;
+class StyleLayerGroup;
+struct BackgroundProperties;
+
+class Style {
+public:
+ struct exception : std::runtime_error { exception(const char *msg) : std::runtime_error(msg) {} };
+
+public:
+ Style();
+
+ void loadJSON(const uint8_t *const data);
+
+ size_t layerCount() const;
+ void updateProperties(float z, timestamp t);
+
+ void setDefaultTransitionDuration(uint16_t duration_milliseconds = 0);
+
+ void setAppliedClasses(const std::vector<std::string> &classes);
+ const std::vector<std::string> &getAppliedClasses() const;
+ void toggleClass(const std::string &name);
+
+ // Updates the styling information to reflect the current array
+ // of applied classes.
+ void updateClasses();
+
+ bool hasTransitions() const;
+
+ const BackgroundProperties &getBackgroundProperties() const;
+
+public:
+ std::shared_ptr<Sprite> sprite;
+ std::shared_ptr<StyleLayerGroup> layers;
+ std::vector<std::string> appliedClasses;
+ std::string sprite_url;
+ std::string glyph_url;
+
+
+private:
+ PropertyTransition defaultTransition;
+ bool initial_render_complete = false;
+
+ mutable uv::rwlock mtx;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/style_bucket.hpp b/include/mbgl/style/style_bucket.hpp
new file mode 100644
index 0000000000..62f072d9cd
--- /dev/null
+++ b/include/mbgl/style/style_bucket.hpp
@@ -0,0 +1,88 @@
+#ifndef MBGL_STYLE_STYLE_BUCKET
+#define MBGL_STYLE_STYLE_BUCKET
+
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/filter_expression.hpp>
+#include <mbgl/style/style_source.hpp>
+#include <mbgl/util/vec.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <memory>
+#include <forward_list>
+
+namespace mbgl {
+
+class Source;
+
+class StyleBucketFill {
+public:
+ WindingType winding = WindingType::Default;
+};
+
+class StyleBucketLine {
+public:
+ CapType cap = CapType::Default;
+ JoinType join = JoinType::Default;
+ float miter_limit = 2.0f;
+ float round_limit = 1.0f;
+};
+
+class StyleBucketIcon {
+public:
+ uint16_t size = 16;
+ vec2<float> translate {0, 0};
+ TranslateAnchorType translate_anchor = TranslateAnchorType::Default;
+ std::string icon;
+ float spacing = 0.0f;
+ float padding = 2.0f;
+};
+
+class StyleBucketText {
+public:
+ std::string field;
+ TextPathType path = TextPathType::Default;
+ TextTransformType transform = TextTransformType::Default;
+ std::string font;
+ float max_size = 16.0f;
+ float max_width = 15.0f * 24;
+ float line_height = 1.2f * 24;
+ float letter_spacing = 0.0f;
+ float alignment = 0.5f;
+ float vertical_alignment = 0.5;
+ vec2<float> translate {0, 0};
+ TranslateAnchorType translate_anchor = TranslateAnchorType::Default;
+ float max_angle_delta = M_PI;
+ float min_distance = 250.0f;
+ float rotate = 0.0f; // what is this?
+ float padding = 2.0f;
+ float slant = 0.0f;
+ bool always_visible = false;
+};
+
+class StyleBucketRaster {
+public:
+};
+
+typedef util::variant<StyleBucketFill, StyleBucketLine, StyleBucketIcon,
+ StyleBucketText, StyleBucketRaster,
+ std::false_type> StyleBucketRender;
+
+
+class StyleBucket {
+public:
+ typedef std::shared_ptr<StyleBucket> Ptr;
+
+ StyleBucket(StyleLayerType type);
+
+ std::string name;
+ std::shared_ptr<StyleSource> style_source;
+ std::string source_layer;
+ FilterExpression filter;
+ StyleBucketRender render = std::false_type();
+};
+
+
+
+};
+
+#endif
diff --git a/include/mbgl/style/style_layer.hpp b/include/mbgl/style/style_layer.hpp
new file mode 100644
index 0000000000..14d60ed9b6
--- /dev/null
+++ b/include/mbgl/style/style_layer.hpp
@@ -0,0 +1,94 @@
+#ifndef MBGL_STYLE_STYLE_LAYER
+#define MBGL_STYLE_STYLE_LAYER
+
+#include <mbgl/style/class_dictionary.hpp>
+#include <mbgl/style/class_properties.hpp>
+#include <mbgl/style/style_properties.hpp>
+#include <mbgl/style/rasterize_properties.hpp>
+#include <mbgl/style/applied_class_properties.hpp>
+
+#include <vector>
+#include <memory>
+#include <string>
+#include <map>
+#include <set>
+
+namespace mbgl {
+
+class StyleBucket;
+class StyleLayerGroup;
+
+class StyleLayer {
+public:
+ StyleLayer(const std::string &id, std::map<ClassID, ClassProperties> &&styles,
+ std::unique_ptr<const RasterizeProperties> &&rasterize);
+
+ template <typename T> const T &getProperties() {
+ if (properties.is<T>()) {
+ return properties.get<T>();
+ } else {
+ return defaultStyleProperties<T>();
+ }
+ }
+
+ // Determines whether this layer is the background layer.
+ bool isBackground() const;
+
+ // Updates the StyleProperties information in this layer by evaluating all
+ // pending transitions and applied classes in order.
+ void updateProperties(float z, timestamp now);
+
+ // Sets the list of classes and creates transitions to the currently applied values.
+ void setClasses(const std::vector<std::string> &class_names, timestamp now,
+ const PropertyTransition &defaultTransition);
+
+ bool hasTransitions() const;
+
+private:
+ // Applies all properties from a class, if they haven't been applied already.
+ void applyClassProperties(ClassID class_id, std::set<PropertyKey> &already_applied,
+ timestamp now, const PropertyTransition &defaultTransition);
+
+ // Sets the properties of this object by evaluating all pending transitions and
+ // aplied classes in order.
+ template <typename T> void applyStyleProperties(float z, timestamp now);
+ template <typename T> void applyStyleProperty(PropertyKey key, T &, float z, timestamp now);
+
+ // Removes all expired style transitions.
+ void cleanupAppliedStyleProperties(timestamp now);
+
+public:
+ // The name of this layer.
+ const std::string id;
+
+ StyleLayerType type = StyleLayerType::Unknown;
+
+ // Bucket information, telling the renderer how to generate the geometries
+ // for this layer (feature property filters, tessellation instructions, ...).
+ std::shared_ptr<StyleBucket> bucket;
+
+ // Contains all style classes that can be applied to this layer.
+ const std::map<ClassID, ClassProperties> styles;
+
+private:
+ // For every property, stores a list of applied property values, with
+ // optional transition times.
+ std::map<PropertyKey, AppliedClassProperties> appliedStyle;
+
+public:
+ // Stores the evaluated, and cascaded styling information, specific to this
+ // layer's type.
+ StyleProperties properties;
+
+ // Rasterization properties are used for prerendering the tile to a bitmap,
+ // which is then used as a raster image instead of rendering this layer
+ // directly in every frame.
+ const std::unique_ptr<const RasterizeProperties> rasterize;
+
+ // Child layer array (if this layer has child layers).
+ std::shared_ptr<StyleLayerGroup> layers;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/style_layer_group.hpp b/include/mbgl/style/style_layer_group.hpp
new file mode 100644
index 0000000000..983dd136f0
--- /dev/null
+++ b/include/mbgl/style/style_layer_group.hpp
@@ -0,0 +1,23 @@
+#ifndef MBGL_STYLE_STYLE_LAYER_GROUP
+#define MBGL_STYLE_STYLE_LAYER_GROUP
+
+#include <mbgl/style/style_layer.hpp>
+
+#include <vector>
+
+namespace mbgl {
+
+class StyleLayerGroup {
+public:
+ void setClasses(const std::vector<std::string> &class_names, timestamp now,
+ const PropertyTransition &defaultTransition);
+ void updateProperties(float z, timestamp t);
+
+ bool hasTransitions() const;
+public:
+ std::vector<std::shared_ptr<StyleLayer>> layers;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/style_parser.hpp b/include/mbgl/style/style_parser.hpp
new file mode 100644
index 0000000000..431e3af8db
--- /dev/null
+++ b/include/mbgl/style/style_parser.hpp
@@ -0,0 +1,119 @@
+#ifndef MBGL_STYLE_STYLE_PARSER
+#define MBGL_STYLE_STYLE_PARSER
+
+#include <rapidjson/document.h>
+#include <mbgl/style/style.hpp>
+#include <mbgl/style/style_source.hpp>
+#include <mbgl/style/filter_expression.hpp>
+#include <mbgl/style/class_properties.hpp>
+#include <mbgl/style/rasterize_properties.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+#include <unordered_map>
+#include <forward_list>
+#include <tuple>
+
+namespace mbgl {
+
+enum class ClassID : uint32_t;
+
+class StyleLayer;
+class StyleLayerGroup;
+
+class StyleParser {
+public:
+ using JSVal = const rapidjson::Value&;
+
+ StyleParser();
+
+ void parse(JSVal document);
+
+ std::shared_ptr<StyleLayerGroup> getLayers() {
+ return root;
+ }
+
+ std::string getSprite() const {
+ return sprite;
+ }
+
+ std::string getGlyphURL() const {
+ return glyph_url;
+ }
+
+private:
+ void parseConstants(JSVal value);
+ JSVal replaceConstant(JSVal value);
+
+ void parseSources(JSVal value);
+
+ std::unique_ptr<StyleLayerGroup> createLayers(JSVal value);
+ std::shared_ptr<StyleLayer> createLayer(JSVal value);
+ void parseLayers();
+ void parseLayer(std::pair<JSVal, std::shared_ptr<StyleLayer>> &pair);
+ void parseStyles(JSVal value, std::map<ClassID, ClassProperties> &styles);
+ void parseStyle(JSVal, ClassProperties &properties);
+ std::unique_ptr<RasterizeProperties> parseRasterize(JSVal value);
+ void parseReference(JSVal value, std::shared_ptr<StyleLayer> &layer);
+ void parseBucket(JSVal value, std::shared_ptr<StyleLayer> &layer);
+ void parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer);
+ void parseSprite(JSVal value);
+ void parseGlyphURL(JSVal value);
+
+ // Parses optional properties into a render bucket.
+ template<typename T>
+ bool parseRenderProperty(JSVal value, T &target, const char *name);
+ template <typename T, typename Parser>
+ bool parseRenderProperty(JSVal value, T &target, const char *name, Parser &parser);
+
+ // Parses optional properties into style class properties.
+ template <typename T>
+ bool parseOptionalProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value);
+ template <typename T>
+ bool parseOptionalProperty(const char *property_name, const std::vector<PropertyKey> &keys, ClassProperties &klass, JSVal value);
+ template <typename T>
+ bool parseOptionalProperty(const char *property_name, T &target, JSVal value);
+ template <typename T>
+ bool setProperty(JSVal value, const char *property_name, PropertyKey key, ClassProperties &klass);
+ template <typename T>
+ bool setProperty(JSVal value, const char *property_name, T &target);
+
+ template <typename T>
+ std::tuple<bool, T> parseProperty(JSVal value, const char *property_name);
+
+ template <typename T>
+ bool parseFunction(PropertyKey key, ClassProperties &klass, JSVal value);
+ template <typename T>
+ std::tuple<bool, Function<T>> parseFunction(JSVal value);
+ template <typename T>
+ T parseFunctionArgument(JSVal value);
+
+
+ FilterExpression parseFilter(JSVal, FilterExpression::Operator op);
+ FilterExpression parseFilter(JSVal);
+ Value parseValue(JSVal value);
+ std::vector<Value> parseValues(JSVal values);
+
+private:
+ std::unordered_map<std::string, const rapidjson::Value *> constants;
+
+ std::unordered_map<std::string, const std::shared_ptr<StyleSource>> sources;
+
+ // This stores the root layer.
+ std::shared_ptr<StyleLayerGroup> root;
+
+ // This maps ids to Layer objects, with all items being at the root level.
+ std::unordered_map<std::string, std::pair<JSVal, std::shared_ptr<StyleLayer>>> layers;
+
+ // Store a stack of layers we're parsing right now. This is to prevent reference cycles.
+ std::forward_list<StyleLayer *> stack;
+
+ // Base URL of the sprite image.
+ std::string sprite;
+
+ // URL template for glyph PBFs.
+ std::string glyph_url;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/style/style_properties.hpp b/include/mbgl/style/style_properties.hpp
new file mode 100644
index 0000000000..c7606be254
--- /dev/null
+++ b/include/mbgl/style/style_properties.hpp
@@ -0,0 +1,116 @@
+#ifndef MBGL_STYLE_STYLE_PROPERTIES
+#define MBGL_STYLE_STYLE_PROPERTIES
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/function_properties.hpp>
+
+#include <array>
+#include <string>
+#include <type_traits>
+#include <memory>
+
+namespace mbgl {
+
+struct FillProperties {
+ FillProperties() {}
+ bool antialias = true;
+ float opacity = 1.0f;
+ Color fill_color = {{ 0, 0, 0, 1 }};
+ Color stroke_color = {{ 0, 0, 0, -1 }};
+ std::array<float, 2> translate = {{ 0, 0 }};
+ TranslateAnchorType translateAnchor = TranslateAnchorType::Default;
+ std::string image;
+
+ inline bool isVisible() const {
+ return opacity > 0 && (fill_color[3] > 0 || stroke_color[3] > 0);
+ }
+};
+
+struct LineProperties {
+ inline LineProperties() {}
+ float opacity = 1.0f;
+ Color color = {{ 0, 0, 0, 1 }};
+ std::array<float, 2> translate = {{ 0, 0 }};
+ TranslateAnchorType translateAnchor = TranslateAnchorType::Default;
+ float width = 0;
+ float offset = 0;
+ float blur = 0;
+ std::array<float, 2> dash_array = {{ 1, -1 }};
+ std::string image;
+
+ inline bool isVisible() const {
+ return opacity > 0 && color[3] > 0 && width > 0;
+ }
+};
+
+struct IconProperties {
+ inline IconProperties() {}
+ float opacity = 1.0f;
+ float rotate = 0.0f;
+ RotateAnchorType rotate_anchor = RotateAnchorType::Default;
+
+ inline bool isVisible() const {
+ return opacity > 0;
+ }
+};
+
+struct TextProperties {
+ inline TextProperties() {}
+ float opacity = 1.0f;
+ float size = 12.0f;
+ Color color = {{ 0, 0, 0, 1 }};
+ Color halo_color = {{ 1, 1, 1, 0.75 }};
+ float halo_width = 0.25f;
+ float halo_blur = 1.0f;
+
+ inline bool isVisible() const {
+ return opacity > 0 && (color[3] > 0 || halo_color[3] > 0) && size > 0;
+ }
+};
+
+struct CompositeProperties {
+ inline CompositeProperties() {}
+ float opacity = 1.0f;
+
+ inline bool isVisible() const {
+ return opacity > 0;
+ }
+};
+
+struct RasterProperties {
+ inline RasterProperties() {}
+ float opacity = 1.0f;
+ float spin = 0.0f;
+ std::array<float, 2> brightness = {{ 0, 1 }};
+ float saturation = 0.0f;
+ float contrast = 0.0f;
+ float fade = 0.0f;
+
+ inline bool isVisible() const {
+ return opacity > 0;
+ }
+};
+
+struct BackgroundProperties {
+ inline BackgroundProperties() {}
+ Color color = {{ 1, 1, 1, 1 }};
+};
+
+typedef util::variant<
+ FillProperties,
+ LineProperties,
+ IconProperties,
+ TextProperties,
+ CompositeProperties,
+ RasterProperties,
+ BackgroundProperties,
+ std::false_type
+> StyleProperties;
+
+template <typename T>
+const T &defaultStyleProperties();
+
+}
+
+#endif
diff --git a/include/mbgl/style/style_source.hpp b/include/mbgl/style/style_source.hpp
new file mode 100644
index 0000000000..6b86c30907
--- /dev/null
+++ b/include/mbgl/style/style_source.hpp
@@ -0,0 +1,29 @@
+#ifndef MBGL_STYLE_STYLE_SOURCE
+#define MBGL_STYLE_STYLE_SOURCE
+
+#include <mbgl/style/types.hpp>
+
+#include <memory>
+
+namespace mbgl {
+
+class Source;
+
+class StyleSource {
+public:
+ const SourceType type;
+ const std::string url;
+ const uint32_t tile_size;
+ const int32_t min_zoom;
+ const int32_t max_zoom;
+
+ bool enabled = false;
+ std::shared_ptr<Source> source;
+
+ StyleSource(SourceType type = SourceType::Vector, const std::string &url = "",
+ uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 22)
+ : type(type), url(url), tile_size(tile_size), min_zoom(min_zoom), max_zoom(max_zoom) {}
+};
+};
+
+#endif
diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp
new file mode 100644
index 0000000000..ca2061fa91
--- /dev/null
+++ b/include/mbgl/style/types.hpp
@@ -0,0 +1,160 @@
+#ifndef MBGL_STYLE_TYPES
+#define MBGL_STYLE_TYPES
+
+#include <mbgl/util/enum.hpp>
+
+#include <string>
+#include <array>
+
+namespace mbgl {
+
+// Stores a premultiplied color, with all four channels ranging from 0..1
+typedef std::array<float, 4> Color;
+
+enum class StyleLayerType : uint8_t {
+ Unknown,
+ Fill,
+ Line,
+ Icon,
+ Text,
+ Raster,
+ Composite,
+ Background
+};
+
+MBGL_DEFINE_ENUM_CLASS(StyleLayerTypeClass, StyleLayerType, {
+ { StyleLayerType::Unknown, "unknown" },
+ { StyleLayerType::Fill, "fill" },
+ { StyleLayerType::Line, "line" },
+ { StyleLayerType::Icon, "icon" },
+ { StyleLayerType::Text, "text" },
+ { StyleLayerType::Raster, "raster" },
+ { StyleLayerType::Composite, "composite" },
+ { StyleLayerType::Background, "background" },
+ { StyleLayerType(-1), "unknown" },
+});
+
+
+enum class WindingType : uint8_t {
+ EvenOdd,
+ NonZero,
+ Default = NonZero
+};
+
+enum class CapType : uint8_t {
+ None,
+ Round,
+ Butt,
+ Square,
+ Default = None
+};
+
+enum class JoinType : uint8_t {
+ None,
+ Miter,
+ Bevel,
+ Round,
+ Default = None
+};
+
+enum class TextPathType : uint8_t {
+ Horizontal,
+ Curve,
+ Default = Horizontal
+};
+
+enum class TextTransformType : uint8_t {
+ None,
+ Uppercase,
+ Lowercase,
+ Default = None
+};
+
+enum class TranslateAnchorType : uint8_t {
+ Map,
+ Viewport,
+ Default = Map
+};
+
+enum class RotateAnchorType : uint8_t {
+ Map,
+ Viewport,
+ Default = Viewport
+};
+
+enum class SourceType : uint8_t {
+ Vector,
+ Raster,
+ GeoJSON,
+ Video,
+ Default = Vector
+};
+
+inline WindingType parseWindingType(const std::string &type) {
+ if (type == "even-odd") return WindingType::EvenOdd;
+ if (type == "non-zero") return WindingType::NonZero;
+ return WindingType::Default;
+}
+
+inline CapType parseCapType(const std::string &cap) {
+ if (cap == "round") return CapType::Round;
+ if (cap == "butt") return CapType::Butt;
+ if (cap == "square") return CapType::Square;
+ return CapType::None;
+}
+
+inline JoinType parseJoinType(const std::string &join) {
+ if (join == "miter") return JoinType::Miter;
+ if (join == "bevel") return JoinType::Bevel;
+ if (join == "round") return JoinType::Round;
+ return JoinType::None;
+}
+
+inline TextPathType parseTextPathType(const std::string &path) {
+ if (path == "horizontal") return TextPathType::Horizontal;
+ if (path == "curve") return TextPathType::Curve;
+ return TextPathType::Default;
+}
+
+inline TextTransformType parseTextTransformType(const std::string& transform) {
+ if (transform == "uppercase") return TextTransformType::Uppercase;
+ if (transform == "lowercase") return TextTransformType::Lowercase;
+ return TextTransformType::Default;
+};
+
+inline TranslateAnchorType parseTranslateAnchorType(const std::string &anchor) {
+ if (anchor == "map") return TranslateAnchorType::Map;
+ if (anchor == "viewport") return TranslateAnchorType::Viewport;
+ return TranslateAnchorType::Default;
+}
+
+inline RotateAnchorType parseRotateAnchorType(const std::string &anchor) {
+ if (anchor == "map") return RotateAnchorType::Map;
+ if (anchor == "viewport") return RotateAnchorType::Viewport;
+ return RotateAnchorType::Default;
+}
+
+inline float parseAlignmentType(const std::string &alignment) {
+ if (alignment == "right") return 1.0f;
+ if (alignment == "left") return 0.0f;
+ return 0.5f;
+}
+
+inline float parseVerticalAlignmentType(const std::string &alignment) {
+ if (alignment == "bottom") return 1.0f;
+ if (alignment == "top") return 0.0f;
+ return 0.5f;
+}
+
+inline SourceType parseSourceType(const std::string &source) {
+ if (source == "vector") return SourceType::Vector;
+ if (source == "raster") return SourceType::Raster;
+ if (source == "geojson") return SourceType::GeoJSON;
+ if (source == "video") return SourceType::Video;
+ return SourceType::Default;
+}
+
+}
+
+#endif
+
diff --git a/include/mbgl/style/value.hpp b/include/mbgl/style/value.hpp
new file mode 100644
index 0000000000..5e6260e5a6
--- /dev/null
+++ b/include/mbgl/style/value.hpp
@@ -0,0 +1,43 @@
+#ifndef MBGL_STYLE_VALUE
+#define MBGL_STYLE_VALUE
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/util/pbf.hpp>
+
+#include <cstdlib>
+#include <cerrno>
+
+namespace mbgl {
+
+typedef util::variant<bool, int64_t, uint64_t, double, std::string> Value;
+
+std::string toString(const Value &value);
+
+Value parseValue(pbf data);
+
+namespace util {
+inline bool parseNumericString(const std::string &str, double &result) {
+ char *end = nullptr;
+ const char *begin = str.c_str();
+ result = std::strtod(begin, &end);
+ while (*end != '\0' && isspace(*end)) end++; // eat whitespace after the end
+ return errno == 0 && end - begin == long(str.size());
+}
+}
+
+template <typename T>
+T toNumber(const Value &value) {
+ if (value.is<std::string>()) {
+ double val;
+ return util::parseNumericString(value.get<std::string>(), val) ? val : 0;
+ }
+ else if (value.is<bool>()) return value.get<bool>();
+ else if (value.is<int64_t>()) return value.get<int64_t>();
+ else if (value.is<uint64_t>()) return value.get<uint64_t>();
+ else if (value.is<double>()) return value.get<double>();
+ else return 0;
+}
+
+}
+
+#endif
diff --git a/include/mbgl/style/value_comparison.hpp b/include/mbgl/style/value_comparison.hpp
new file mode 100644
index 0000000000..41c1d44123
--- /dev/null
+++ b/include/mbgl/style/value_comparison.hpp
@@ -0,0 +1,109 @@
+#ifndef MBGL_STYLE_VALUE_COMPARISON
+#define MBGL_STYLE_VALUE_COMPARISON
+
+#include "value.hpp"
+#include <cstdlib>
+#include <cerrno>
+
+namespace mbgl {
+
+namespace util {
+
+namespace detail {
+
+template <typename Operator>
+struct relaxed_operator_visitor {
+ typedef bool result_type;
+
+ inline bool operator()(bool lhs, bool rhs) const { return Operator()(lhs, rhs); }
+
+ template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
+ inline bool operator()(bool lhs, T rhs) const { return Operator()(T(lhs), rhs); }
+
+ template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
+ inline bool operator()(T lhs, bool rhs) const { return Operator()(lhs, T(rhs)); }
+
+ inline bool operator()(int64_t lhs, uint64_t rhs) const {
+ return lhs < 0 ? false : Operator()(uint64_t(lhs), rhs);
+ }
+ inline bool operator()(uint64_t lhs, int64_t rhs) const {
+ return rhs < 0 ? false : Operator()(lhs, uint64_t(rhs));
+ }
+
+ template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
+ inline bool operator()(const std::string &lhs, T rhs) const {
+ double value;
+ return parseNumericString(lhs, value) ? Operator()(value, double(rhs)) : false;
+ }
+
+ template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
+ inline bool operator()(T lhs, const std::string &rhs) const {
+ double value;
+ return parseNumericString(rhs, value) ? Operator()(double(lhs), value) : false;
+ }
+
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return Operator()(lhs, rhs); }
+};
+
+struct relaxed_equal_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs == rhs; }
+};
+
+struct relaxed_not_equal_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs != rhs; }
+};
+
+struct relaxed_greater_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs > rhs; }
+};
+
+struct relaxed_greater_equal_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs >= rhs; }
+};
+
+struct relaxed_less_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs < rhs; }
+};
+
+struct relaxed_less_equal_operator {
+ template <typename T0, typename T1>
+ inline bool operator()(T0 lhs, T1 rhs) const { return lhs <= rhs; }
+};
+
+} // end namespace detail
+
+inline bool relaxed_equal(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_equal_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_not_equal(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_not_equal_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_greater(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_greater_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_greater_equal(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_greater_equal_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_less(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_less_operator>(), lhs, rhs);
+}
+
+inline bool relaxed_less_equal(Value const &lhs, Value const &rhs) {
+ return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_less_equal_operator>(), lhs, rhs);
+}
+
+}
+
+}
+
+#endif
diff --git a/include/mbgl/text/collision.hpp b/include/mbgl/text/collision.hpp
new file mode 100644
index 0000000000..31103a7439
--- /dev/null
+++ b/include/mbgl/text/collision.hpp
@@ -0,0 +1,32 @@
+#ifndef MBGL_TEXT_COLLISION
+#define MBGL_TEXT_COLLISION
+
+#include <mbgl/text/types.hpp>
+
+namespace mbgl {
+
+class Collision {
+
+public:
+ Collision();
+ ~Collision();
+
+ PlacementProperty place(const GlyphBoxes &boxes,
+ const CollisionAnchor &anchor,
+ float minPlacementScale, float maxPlacementScale,
+ float padding, bool horizontal, bool alwaysVisible);
+ float getPlacementScale(const GlyphBoxes &glyphs, float minPlacementScale,
+ float maxPlacementScale, float pad);
+ PlacementRange getPlacementRange(const GlyphBoxes &glyphs,
+ float placementScale, bool horizontal);
+ void insert(const GlyphBoxes &glyphs, const CollisionAnchor &anchor,
+ float placementScale, const PlacementRange &placementRange,
+ bool horizontal, float padding);
+
+private:
+ void *cTree;
+ void *hTree;
+};
+}
+
+#endif
diff --git a/include/mbgl/text/glyph.hpp b/include/mbgl/text/glyph.hpp
new file mode 100644
index 0000000000..899c8fffee
--- /dev/null
+++ b/include/mbgl/text/glyph.hpp
@@ -0,0 +1,61 @@
+#ifndef MBGL_TEXT_GLYPH
+#define MBGL_TEXT_GLYPH
+
+#include <mbgl/util/rect.hpp>
+
+#include <cstdint>
+#include <vector>
+#include <map>
+
+namespace mbgl {
+
+typedef std::pair<uint16_t, uint16_t> GlyphRange;
+
+// Note: this only works for the BMP
+GlyphRange getGlyphRange(char32_t glyph);
+
+struct GlyphMetrics {
+ operator bool() const {
+ return width == 0 && height == 0 && advance == 0;
+ }
+
+ // Glyph metrics.
+ uint32_t width = 0;
+ uint32_t height = 0;
+ int32_t left = 0;
+ int32_t top = 0;
+ uint32_t advance = 0;
+
+};
+
+struct Glyph {
+ inline explicit Glyph() : rect(0, 0, 0, 0), metrics() {}
+ inline explicit Glyph(const Rect<uint16_t> &rect,
+ const GlyphMetrics &metrics)
+ : rect(rect), metrics(metrics) {}
+
+ operator bool() const {
+ return !metrics && !rect;
+ }
+
+ const Rect<uint16_t> rect;
+ const GlyphMetrics metrics;
+};
+
+typedef std::map<uint32_t, Glyph> GlyphPositions;
+
+class GlyphPlacement {
+public:
+ inline explicit GlyphPlacement(uint32_t face, uint32_t glyph, uint32_t x, uint32_t y)
+ : face(face), glyph(glyph), x(x), y(y) {}
+
+ uint32_t face = 0;
+ uint32_t glyph = 0;
+ int32_t x = 0;
+ int32_t y = 0;
+};
+
+typedef std::vector<GlyphPlacement> Shaping;
+}
+
+#endif
diff --git a/include/mbgl/text/glyph_store.hpp b/include/mbgl/text/glyph_store.hpp
new file mode 100644
index 0000000000..9c874b31b0
--- /dev/null
+++ b/include/mbgl/text/glyph_store.hpp
@@ -0,0 +1,95 @@
+#ifndef MBGL_TEXT_GLYPH_STORE
+#define MBGL_TEXT_GLYPH_STORE
+
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/util/pbf.hpp>
+
+#include <cstdint>
+#include <vector>
+#include <future>
+#include <map>
+#include <set>
+#include <unordered_map>
+
+namespace mbgl {
+
+
+class SDFGlyph {
+public:
+ uint32_t id = 0;
+
+ // A signed distance field of the glyph with a border of 3 pixels.
+ std::string bitmap;
+
+ // Glyph metrics
+ GlyphMetrics metrics;
+};
+
+class FontStack {
+public:
+ void insert(uint32_t id, const SDFGlyph &glyph);
+ const std::map<uint32_t, GlyphMetrics> &getMetrics() const;
+ const std::map<uint32_t, SDFGlyph> &getSDFs() const;
+ const Shaping getShaping(const std::u32string &string,
+ const float &maxWidth,
+ const float &lineHeight,
+ const float &alignment,
+ const float &verticalAlignment,
+ const float &letterSpacing) const;
+ void lineWrap(Shaping &shaping,
+ const float &lineHeight,
+ const float &maxWidth,
+ const float &alignment,
+ const float &verticalAlignment) const;
+
+private:
+ std::map<uint32_t, std::string> bitmaps;
+ std::map<uint32_t, GlyphMetrics> metrics;
+ std::map<uint32_t, SDFGlyph> sdfs;
+ mutable std::mutex mtx;
+};
+
+class GlyphPBF {
+public:
+ GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange);
+
+ void parse(FontStack &stack);
+
+ std::shared_future<GlyphPBF &> getFuture();
+
+private:
+ std::string data;
+ std::promise<GlyphPBF &> promise;
+ std::shared_future<GlyphPBF &> future;
+ std::mutex mtx;
+};
+
+// Manages Glyphrange PBF loading.
+class GlyphStore {
+public:
+ GlyphStore(const std::string &glyphURL);
+
+ // Block until all specified GlyphRanges of the specified font stack are loaded.
+ void waitForGlyphRanges(const std::string &fontStack, const std::set<GlyphRange> &glyphRanges);
+
+ FontStack &getFontStack(const std::string &fontStack);
+
+private:
+ // Loads an individual glyph range from the font stack and adds it to rangeSets
+ std::shared_future<GlyphPBF &> loadGlyphRange(const std::string &fontStack, std::map<GlyphRange, std::unique_ptr<GlyphPBF>> &rangeSets, GlyphRange range);
+
+ FontStack &createFontStack(const std::string &fontStack);
+
+public:
+ const std::string glyphURL;
+
+private:
+ std::unordered_map<std::string, std::map<GlyphRange, std::unique_ptr<GlyphPBF>>> ranges;
+ std::unordered_map<std::string, std::unique_ptr<FontStack>> stacks;
+ std::mutex mtx;
+};
+
+
+}
+
+#endif
diff --git a/include/mbgl/text/placement.hpp b/include/mbgl/text/placement.hpp
new file mode 100644
index 0000000000..69a1a10b72
--- /dev/null
+++ b/include/mbgl/text/placement.hpp
@@ -0,0 +1,37 @@
+#ifndef MBGL_TEXT_PLACEMENT
+#define MBGL_TEXT_PLACEMENT
+
+#include <mbgl/text/collision.hpp>
+#include <mbgl/geometry/geometry.hpp>
+#include <mbgl/util/vec.hpp>
+#include <mbgl/text/glyph.hpp>
+#include <vector>
+
+namespace mbgl {
+
+class TextBucket;
+class StyleBucketText;
+
+class Placement {
+public:
+ Placement(int8_t zoom);
+
+ void addFeature(TextBucket &bucket, const std::vector<Coordinate> &line,
+ const StyleBucketText &info,
+ const GlyphPositions &face,
+ const Shaping &shaping);
+
+private:
+ const int8_t zoom;
+ Collision collision;
+ const float zOffset;
+ const float maxPlacementScale;
+
+public:
+ static const int tileExtent;
+ static const int glyphSize;
+ static const float minScale;
+};
+}
+
+#endif
diff --git a/include/mbgl/text/rotation_range.hpp b/include/mbgl/text/rotation_range.hpp
new file mode 100644
index 0000000000..4968fda164
--- /dev/null
+++ b/include/mbgl/text/rotation_range.hpp
@@ -0,0 +1,54 @@
+#ifndef MBGL_TEXT_ROTATION_RANGE
+#define MBGL_TEXT_ROTATION_RANGE
+
+#include <mbgl/util/math.hpp>
+#include <mbgl/text/types.hpp>
+
+#include <vector>
+#include <cassert>
+
+namespace mbgl {
+
+/*
+ * Combine an array of collision ranges to form a continuous
+ * range that includes 0. Collisions within the ignoreRange are ignored
+ */
+CollisionRange mergeCollisions(const CollisionList &collisions,
+ PlacementRange ignoreRange);
+
+/*
+ * Calculate collision ranges for two rotating boxes.e
+ */
+CollisionList rotatingRotatingCollisions(const CollisionRect &a,
+ const CollisionRect &b,
+ const CollisionAnchor &anchorToAnchor);
+
+/*
+ * Return the intersection points of a circle and a line segment;
+ */
+void circleEdgeCollisions(std::back_insert_iterator<CollisionAngles> angles,
+ const CollisionPoint &corner, float radius,
+ const CollisionPoint &p1, const CollisionPoint &p2);
+
+/*
+ * Calculate the ranges for which the corner,
+ * rotatated around the anchor, is within the box;
+ */
+void cornerBoxCollisions(std::back_insert_iterator<CollisionList> collisions,
+ const CollisionPoint &corner,
+ const CollisionCorners &boxCorners, bool flip = false);
+
+/*
+ * Calculate collision ranges for a rotating box and a fixed box;
+ */
+CollisionList rotatingFixedCollisions(const CollisionRect &rotating,
+ const CollisionRect &fixed);
+
+/*
+ * Calculate the range a box conflicts with a second box
+ */
+CollisionRange rotationRange(const GlyphBox &inserting,
+ const PlacementBox &blocker, float scale);
+}
+
+#endif
diff --git a/include/mbgl/text/types.hpp b/include/mbgl/text/types.hpp
new file mode 100644
index 0000000000..9a9284b588
--- /dev/null
+++ b/include/mbgl/text/types.hpp
@@ -0,0 +1,109 @@
+#ifndef MBGL_TEXT_TYPES
+#define MBGL_TEXT_TYPES
+
+#include <mbgl/util/vec.hpp>
+#include <mbgl/util/rect.hpp>
+#include <array>
+#include <vector>
+
+namespace mbgl {
+
+typedef vec2<float> CollisionPoint;
+typedef vec2<float> CollisionAnchor;
+
+typedef std::array<float, 2> PlacementRange;
+typedef float CollisionAngle;
+typedef std::vector<CollisionAngle> CollisionAngles;
+typedef std::array<CollisionAngle, 2> CollisionRange;
+typedef std::vector<CollisionRange> CollisionList;
+typedef std::array<CollisionPoint, 4> CollisionCorners;
+
+struct CollisionRect {
+ CollisionPoint tl;
+ CollisionPoint br;
+ inline explicit CollisionRect() {}
+ inline explicit CollisionRect(CollisionPoint::Type ax,
+ CollisionPoint::Type ay,
+ CollisionPoint::Type bx,
+ CollisionPoint::Type by)
+ : tl(ax, ay), br(bx, by) {}
+ inline explicit CollisionRect(const CollisionPoint &tl,
+ const CollisionPoint &br)
+ : tl(tl), br(br) {}
+};
+
+// These are the glyph boxes that we want to have placed.
+struct GlyphBox {
+ explicit GlyphBox() {}
+ explicit GlyphBox(const CollisionRect &bbox, const CollisionRect &box,
+ float minScale)
+ : bbox(bbox), box(box), minScale(minScale) {}
+ explicit GlyphBox(const CollisionRect &box, float minScale, float maxScale,
+ const CollisionAnchor &anchor, bool rotate)
+ : anchor(anchor),
+ box(box),
+ rotate(rotate),
+ minScale(minScale),
+ maxScale(maxScale) {}
+
+ CollisionAnchor anchor;
+ CollisionRect bbox;
+ CollisionRect box;
+ bool rotate = false;
+ float minScale = 0.0f;
+ float maxScale = std::numeric_limits<float>::infinity();
+};
+
+typedef std::vector<GlyphBox> GlyphBoxes;
+
+
+// TODO: Transform the vec2<float>s to vec2<int16_t> to save bytes
+struct PlacedGlyph {
+ explicit PlacedGlyph(const vec2<float> &tl, const vec2<float> &tr,
+ const vec2<float> &bl, const vec2<float> &br,
+ const Rect<uint16_t> &tex, float angle, const GlyphBox &glyphBox)
+ : tl(tl),
+ tr(tr),
+ bl(bl),
+ br(br),
+ tex(tex),
+ angle(angle),
+ glyphBox(glyphBox) {}
+
+ vec2<float> tl, tr, bl, br;
+ Rect<uint16_t> tex;
+ float angle;
+ GlyphBox glyphBox;
+};
+
+typedef std::vector<PlacedGlyph> PlacedGlyphs;
+
+// These are the placed boxes contained in the rtree.
+struct PlacementBox {
+ CollisionAnchor anchor;
+ CollisionRect bbox;
+ CollisionRect box;
+ bool rotate = false;
+ PlacementRange placementRange = {{0.0f, 0.0f}};
+ float placementScale = 0.0f;
+ float maxScale = std::numeric_limits<float>::infinity();
+ float padding = 0.0f;
+};
+
+struct PlacementProperty {
+ explicit PlacementProperty() {}
+ explicit PlacementProperty(float zoom, const PlacementRange &rotationRange)
+ : zoom(zoom), rotationRange(rotationRange) {}
+
+ inline operator bool() const {
+ return !isnan(zoom) && zoom != std::numeric_limits<float>::infinity() &&
+ rotationRange[0] != rotationRange[1];
+ }
+
+ float zoom = std::numeric_limits<float>::infinity();
+ PlacementRange rotationRange = {{0.0f, 0.0f}};
+};
+
+}
+
+#endif
diff --git a/include/mbgl/util/clip_ids.hpp b/include/mbgl/util/clip_ids.hpp
new file mode 100644
index 0000000000..748d3d8f5f
--- /dev/null
+++ b/include/mbgl/util/clip_ids.hpp
@@ -0,0 +1,19 @@
+#ifndef MBGL_UTIL_CLIP_IDS
+#define MBGL_UTIL_CLIP_IDS
+
+#include <mbgl/map/tile.hpp>
+#include <list>
+#include <set>
+#include <map>
+
+namespace mbgl {
+
+static constexpr uint8_t clipMask[9] { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
+
+void updateClipIDs(const std::list<Tile *> &array);
+
+std::map<Tile::ID, ClipID> computeClipIDs(std::forward_list<Tile::ID> array);
+
+}
+
+#endif
diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp
new file mode 100644
index 0000000000..89e8af2ef1
--- /dev/null
+++ b/include/mbgl/util/constants.hpp
@@ -0,0 +1,33 @@
+#ifndef MBGL_UTIL_CONSTANTS
+#define MBGL_UTIL_CONSTANTS
+
+#include <cmath>
+
+#include "vec.hpp"
+
+namespace mbgl {
+
+namespace util {
+
+extern const float tileSize;
+
+}
+
+namespace debug {
+
+extern const bool tileParseWarnings;
+extern const bool styleParseWarnings;
+extern const bool spriteWarnings;
+extern const bool renderWarnings;
+extern const bool renderTree;
+extern const bool labelTextMissingWarning;
+extern const bool missingFontStackWarning;
+extern const bool missingFontFaceWarning;
+extern const bool glyphWarning;
+extern const bool shapingWarning;
+
+}
+
+}
+
+#endif
diff --git a/include/mbgl/util/enum.hpp b/include/mbgl/util/enum.hpp
new file mode 100644
index 0000000000..195aaab5a5
--- /dev/null
+++ b/include/mbgl/util/enum.hpp
@@ -0,0 +1,55 @@
+#ifndef MBGL_UTIL_ENUM
+#define MBGL_UTIL_ENUM
+
+#include <iosfwd>
+#include <string>
+
+namespace mbgl {
+
+template <typename Type>
+struct EnumValue {
+ const Type value;
+ const char *name;
+};
+
+template <typename EnumName, const EnumValue<EnumName> *names, const size_t length>
+struct Enum {
+ using Type = EnumName;
+ Type value;
+ static const constexpr size_t l = length;
+private:
+ static constexpr inline bool compare(const char *a, const char *b) {
+ return *a == *b && (*a == '\0' || compare(a + 1, b + 1));
+ }
+ static constexpr inline const char *lookup_type(Type e, EnumValue<Type> const * const l, size_t r) {
+ return r == 0 ? "" : l->value == e ? l->name : lookup_type(e, l + 1, r - 1);
+ }
+ static constexpr inline Type lookup_name(const char *n, EnumValue<Type> const * const l, size_t r) {
+ return r == 0 ? Type(-1) : compare(l->name, n) ? l->value : lookup_name(n, l + 1, r - 1);
+ }
+public:
+ inline constexpr Enum(const char *n) : value(lookup_name(n, names, length)) {}
+ inline constexpr Enum(const std::string &n) : value(lookup_name(n.c_str(), names, length)) {}
+ inline constexpr Enum(Type t) : value(t) {}
+
+ inline void operator=(const char *n) { value = lookup_name(n, names, length); }
+ inline void operator=(const std::string &n) { *this = n.c_str(); }
+ inline void operator=(Type t) { value = t; }
+
+ inline constexpr bool valid() const { return value != Type(-1); }
+
+ inline constexpr const char *c_str() const { return lookup_type(value, names, length); }
+ inline std::string str() const { return c_str(); }
+
+ inline constexpr operator Type() const { return value; }
+};
+
+#define MBGL_DEFINE_ENUM_CLASS(name, type, strings...) \
+ const constexpr ::mbgl::EnumValue<type> type##_names[] = strings; \
+ using name = ::mbgl::Enum<type, type##_names, sizeof(type##_names) / sizeof(::mbgl::EnumValue<type>)>; \
+ inline std::ostream& operator<<(std::ostream& os, type t) { return os << name(t).str(); }
+
+}
+
+#endif
+
diff --git a/include/mbgl/util/error.hpp b/include/mbgl/util/error.hpp
new file mode 100644
index 0000000000..99e27f770c
--- /dev/null
+++ b/include/mbgl/util/error.hpp
@@ -0,0 +1,20 @@
+#ifndef MBGL_UTIL_ERROR
+#define MBGL_UTIL_ERROR
+
+#include <stdexcept>
+#include <string>
+
+namespace mbgl {
+namespace error {
+
+struct style_parse : std::exception {
+ inline style_parse(size_t offset, const char *msg) : offset(offset), msg(msg) {}
+ inline const char* what() const noexcept { return msg.c_str(); }
+ const size_t offset;
+ const std::string msg;
+};
+}
+
+}
+
+#endif \ No newline at end of file
diff --git a/include/mbgl/util/image.hpp b/include/mbgl/util/image.hpp
new file mode 100644
index 0000000000..dc8f6a8150
--- /dev/null
+++ b/include/mbgl/util/image.hpp
@@ -0,0 +1,36 @@
+#ifndef MBGL_UTIL_IMAGE
+#define MBGL_UTIL_IMAGE
+
+#include <string>
+#include <cstring>
+#include <stdexcept>
+
+namespace mbgl {
+namespace util {
+
+std::string compress_png(int width, int height, void *rgba, bool flip = false);
+
+
+class Image {
+public:
+ Image(const std::string &img, bool flip = false);
+ ~Image();
+
+ inline const char *getData() const { return img; }
+ inline uint32_t getWidth() const { return width; }
+ inline uint32_t getHeight() const { return height; }
+
+private:
+ // loaded image dimensions
+ uint32_t width = 0, height = 0;
+
+ // the raw image data
+ char *img = nullptr;
+
+};
+
+
+}
+}
+
+#endif
diff --git a/include/mbgl/util/io.hpp b/include/mbgl/util/io.hpp
new file mode 100644
index 0000000000..e95fc16d9d
--- /dev/null
+++ b/include/mbgl/util/io.hpp
@@ -0,0 +1,15 @@
+#ifndef MBGL_UTIL_IO
+#define MBGL_UTIL_IO
+
+#include <string>
+
+namespace mbgl {
+namespace util {
+
+void write_file(const std::string &filename, const std::string &data);
+std::string read_file(const std::string &filename);
+
+}
+}
+
+#endif
diff --git a/include/mbgl/util/mat4.hpp b/include/mbgl/util/mat4.hpp
new file mode 100644
index 0000000000..4279113d21
--- /dev/null
+++ b/include/mbgl/util/mat4.hpp
@@ -0,0 +1,45 @@
+// This is an incomplete port of http://glmatrix.net/
+//
+// Copyright (c) 2013 Brandon Jones, Colin MacKenzie IV
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the
+// use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not claim
+// that you wrote the original software. If you use this software in a
+// product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+
+#ifndef MBGL_UTIL_MAT4
+#define MBGL_UTIL_MAT4
+
+#include <array>
+
+namespace mbgl {
+
+typedef std::array<float, 16> mat4;
+
+namespace matrix {
+
+void identity(mat4& out);
+void ortho(mat4& out, float left, float right, float bottom, float top, float near, float far);
+void copy(mat4& out, const mat4& a);
+void translate(mat4& out, const mat4& a, float x, float y, float z);
+void rotate_z(mat4& out, const mat4& a, float rad);
+void scale(mat4& out, const mat4& a, float x, float y, float z);
+void multiply(mat4& out, const mat4& a, const mat4& b);
+
+}
+}
+
+#endif
diff --git a/include/mbgl/util/math.hpp b/include/mbgl/util/math.hpp
new file mode 100644
index 0000000000..277fdc8fc3
--- /dev/null
+++ b/include/mbgl/util/math.hpp
@@ -0,0 +1,115 @@
+#ifndef MBGL_UTIL_MATH
+#define MBGL_UTIL_MATH
+
+#include <cmath>
+#include <array>
+
+#include "vec.hpp"
+
+namespace mbgl {
+namespace util {
+
+
+template <typename T>
+inline T max(T a, T b) {
+ return b > a ? b : a;
+}
+
+template <typename T>
+inline T max(T a, T b, T c) {
+ return max(max(a, b), c);
+}
+
+template <typename T>
+inline T max(T a, T b, T c, T d) {
+ return max(max(a, b), max(c, d));
+}
+
+template <typename T>
+inline T min(T a, T b) {
+ return b < a ? b : a;
+}
+
+template <typename T>
+inline T min(T a, T b, T c) {
+ return min(min(a, b), c);
+}
+
+template <typename T>
+inline T min(T a, T b, T c, T d) {
+ return min(min(a, b), min(c, d));
+}
+
+// Find the angle of the two vectors, solving the formula for the cross product
+// a x b = |a||b|sin(θ) for θ.
+template <typename T = double, typename S>
+inline T angle_between(S ax, S ay, S bx, S by) {
+ return std::atan2((ax * by - ay * bx), ax * bx + ay * by);
+}
+
+template <typename T = double, typename S>
+inline T angle_between(const vec2<S>& a, const vec2<S>& b) {
+ return angle_between(a.x, a.y, b.x, b.y);
+}
+
+template <typename T = double, typename S>
+inline T angle_to(const vec2<S>& a, const vec2<S>& b) {
+ return std::atan2(a.y - b.y, a.x - b.x);
+}
+
+template <typename T, typename S1, typename S2>
+inline T interp(S1 a, S2 b, T t) {
+ return (a * ((T)1 - t)) + (b * t);
+}
+
+// Reflect an angle around 0 degrees
+template <typename T>
+inline std::array<T, 2> flip(const std::array<T, 2>& c) {
+ return {{
+ static_cast<T>(2 * M_PI - c[0]),
+ static_cast<T>(2 * M_PI - c[1])
+ }};
+}
+
+template <typename T, typename S1, typename S2>
+inline vec2<T> normal(const S1& a, const S2& b) {
+ T dx = b.x - a.x;
+ T dy = b.y - a.y;
+ T c = std::sqrt(dx * dx + dy * dy);
+ return { dx / c, dy / c };
+}
+
+template <typename T, typename S1, typename S2>
+inline T dist(const S1& a, const S2& b) {
+ T dx = b.x - a.x;
+ T dy = b.y - a.y;
+ T c = std::sqrt(dx * dx + dy * dy);
+ return c;
+}
+
+template <typename T>
+inline T length(T a, T b) {
+ return std::sqrt(a * a + b * b);
+}
+
+// Take the magnitude of vector a.
+template <typename T = double, typename S>
+inline T mag(const S& a) {
+ return std::sqrt(a.x * a.x + a.y * a.y);
+}
+
+template <typename T>
+T clamp(T value, T min, T max) {
+ return value < min ? min : (value > max ? max : value);
+}
+
+template <typename T>
+T smoothstep(T edge0, T edge1, T x) {
+ T t = clamp((x - edge0) / (edge1 - edge0), T(0), T(1));
+ return t * t * (T(3) - T(2) * t);
+}
+
+}
+}
+
+#endif
diff --git a/include/mbgl/util/noncopyable.hpp b/include/mbgl/util/noncopyable.hpp
new file mode 100644
index 0000000000..ada701efc6
--- /dev/null
+++ b/include/mbgl/util/noncopyable.hpp
@@ -0,0 +1,23 @@
+#ifndef MBGL_UTIL_NONCOPYABLE
+#define MBGL_UTIL_NONCOPYABLE
+
+namespace mbgl { namespace util {
+
+namespace non_copyable_
+{
+
+class noncopyable
+{
+protected:
+ constexpr noncopyable() = default;
+ ~noncopyable() = default;
+ noncopyable( noncopyable const& ) = delete;
+ noncopyable& operator=(noncopyable const& ) = delete;
+};
+}
+
+typedef non_copyable_::noncopyable noncopyable;
+
+}}
+
+#endif
diff --git a/include/mbgl/util/pbf.hpp b/include/mbgl/util/pbf.hpp
new file mode 100644
index 0000000000..1f78a0072f
--- /dev/null
+++ b/include/mbgl/util/pbf.hpp
@@ -0,0 +1,184 @@
+#ifndef MBGL_UTIL_PBF
+#define MBGL_UTIL_PBF
+
+/*
+ * Some parts are from upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2008-2011 Google Inc. See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ */
+
+#include <string>
+#include <cstring>
+
+namespace mbgl {
+
+struct pbf {
+ struct exception : std::exception { const char *what() const noexcept { return "pbf exception"; } };
+ struct unterminated_varint_exception : exception { const char *what() const noexcept { return "pbf unterminated varint exception"; } };
+ struct varint_too_long_exception : exception { const char *what() const noexcept { return "pbf varint too long exception"; } };
+ struct unknown_field_type_exception : exception { const char *what() const noexcept { return "pbf unknown field type exception"; } };
+ struct end_of_buffer_exception : exception { const char *what() const noexcept { return "pbf end of buffer exception"; } };
+
+ inline pbf(const unsigned char *data, size_t length);
+ inline pbf();
+
+ inline operator bool() const;
+
+ inline bool next();
+ inline bool next(uint32_t tag);
+ template <typename T = uint32_t> inline T varint();
+ template <typename T = uint32_t> inline T svarint();
+
+ template <typename T = uint32_t, int bytes = 4> inline T fixed();
+ inline float float32();
+ inline double float64();
+
+ inline std::string string();
+ inline bool boolean();
+
+ inline pbf message();
+
+ inline void skip();
+ inline void skipValue(uint32_t val);
+ inline void skipBytes(uint32_t bytes);
+
+ const uint8_t *data = nullptr;
+ const uint8_t *end = nullptr;
+ uint32_t value = 0;
+ uint32_t tag = 0;
+};
+
+pbf::pbf(const unsigned char *data, size_t length)
+ : data(data),
+ end(data + length),
+ value(0),
+ tag(0) {
+}
+
+pbf::pbf()
+ : data(nullptr),
+ end(nullptr),
+ value(0),
+ tag(0) {
+}
+
+
+pbf::operator bool() const {
+ return data < end;
+}
+
+bool pbf::next() {
+ if (data < end) {
+ value = static_cast<uint32_t>(varint());
+ tag = value >> 3;
+ return true;
+ }
+ return false;
+}
+
+bool pbf::next(uint32_t requested_tag) {
+ while (next()) {
+ if (tag == requested_tag) {
+ return true;
+ } else {
+ skip();
+ }
+ }
+ return false;
+}
+
+template <typename T>
+T pbf::varint() {
+ uint8_t byte = 0x80;
+ T result = 0;
+ int bitpos;
+ for (bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) {
+ if (data >= end) {
+ throw unterminated_varint_exception();
+ }
+ result |= ((T)(byte = *data) & 0x7F) << bitpos;
+
+ data++;
+ }
+ if (bitpos == 70 && (byte & 0x80)) {
+ throw varint_too_long_exception();
+ }
+
+ return result;
+}
+
+template <typename T>
+T pbf::svarint() {
+ T n = varint<T>();
+ return (n >> 1) ^ -(T)(n & 1);
+}
+
+template <typename T, int bytes>
+T pbf::fixed() {
+ skipBytes(bytes);
+ T result;
+ memcpy(&result, data - bytes, bytes);
+ return result;
+}
+
+float pbf::float32() {
+ return fixed<float, 4>();
+}
+
+double pbf::float64() {
+ return fixed<double, 8>();
+}
+
+std::string pbf::string() {
+ uint32_t bytes = static_cast<uint32_t>(varint());
+ const char *string = reinterpret_cast<const char*>(data);
+ skipBytes(bytes);
+ return std::string(string, bytes);
+}
+
+bool pbf::boolean() {
+ skipBytes(1);
+ return *(bool *)(data - 1);
+}
+
+pbf pbf::message() {
+ uint32_t bytes = static_cast<uint32_t>(varint());
+ const uint8_t *pos = data;
+ skipBytes(bytes);
+ return pbf(pos, bytes);
+}
+
+void pbf::skip() {
+ skipValue(value);
+}
+
+void pbf::skipValue(uint32_t val) {
+ switch (val & 0x7) {
+ case 0: // varint
+ varint();
+ break;
+ case 1: // 64 bit
+ skipBytes(8);
+ break;
+ case 2: // string/message
+ skipBytes(static_cast<uint32_t>(varint()));
+ break;
+ case 5: // 32 bit
+ skipBytes(4);
+ break;
+ default:
+ throw unknown_field_type_exception();
+ }
+}
+
+void pbf::skipBytes(uint32_t bytes) {
+ if (data + bytes > end) {
+ throw end_of_buffer_exception();
+ }
+ data += bytes;
+}
+
+} // end namespace mbgl
+
+#endif
diff --git a/include/mbgl/util/raster.hpp b/include/mbgl/util/raster.hpp
new file mode 100644
index 0000000000..04c85169e2
--- /dev/null
+++ b/include/mbgl/util/raster.hpp
@@ -0,0 +1,70 @@
+#ifndef MBGL_UTIL_RASTER
+#define MBGL_UTIL_RASTER
+
+#include <mbgl/util/transition.hpp>
+#include <mbgl/util/texturepool.hpp>
+#include <mbgl/util/image.hpp>
+
+#include <string>
+#include <mutex>
+#include <memory>
+
+typedef struct uv_loop_s uv_loop_t;
+
+namespace mbgl {
+
+class Raster : public std::enable_shared_from_this<Raster> {
+
+public:
+ Raster(const std::shared_ptr<Texturepool> &texturepool);
+ ~Raster();
+
+ // load image data
+ bool load(const std::string &img);
+
+ // bind current texture
+ void bind(bool linear = false);
+
+ // loaded status
+ bool isLoaded() const;
+
+ // transitions
+ void beginFadeInTransition();
+ bool needsTransition() const;
+ void updateTransitions(timestamp now);
+
+public:
+ // loaded image dimensions
+ uint32_t width = 0, height = 0;
+
+ // has been uploaded to texture
+ bool textured = false;
+
+ // the uploaded texture
+ uint32_t texture = 0;
+
+ // texture opacity
+ double opacity = 0;
+
+private:
+ mutable std::mutex mtx;
+
+ // raw pixels have been loaded
+ bool loaded = false;
+
+ // shared texture pool
+ std::shared_ptr<Texturepool> texturepool;
+
+ // min/mag filter
+ uint32_t filter = 0;
+
+ // the raw pixels
+ std::unique_ptr<util::Image> img;
+
+ // fade in transition
+ std::shared_ptr<util::transition> fade_transition = nullptr;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/util/rect.hpp b/include/mbgl/util/rect.hpp
new file mode 100644
index 0000000000..a216b8e145
--- /dev/null
+++ b/include/mbgl/util/rect.hpp
@@ -0,0 +1,21 @@
+#ifndef MBGL_UTIL_RECT
+#define MBGL_UTIL_RECT
+
+namespace mbgl {
+
+template <typename T>
+struct Rect {
+ explicit Rect(T x, T y, T w, T h) : x(x), y(y), w(w), h(h) {}
+ T x = 0, y = 0;
+ T w = 0, h = 0;
+
+ template <typename Number>
+ Rect operator *(Number value) const {
+ return Rect(x * value, y * value, w * value, h * value);
+ }
+
+ operator bool() const { return w == 0 || h == 0; }
+};
+}
+
+#endif
diff --git a/include/mbgl/util/recursive_wrapper.hpp b/include/mbgl/util/recursive_wrapper.hpp
new file mode 100644
index 0000000000..a616805c0f
--- /dev/null
+++ b/include/mbgl/util/recursive_wrapper.hpp
@@ -0,0 +1,127 @@
+#ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
+#define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
+
+#include <utility>
+
+namespace mbgl { namespace util {
+
+template <typename T>
+class recursive_wrapper
+{
+public:
+ using type = T;
+private:
+
+ T* p_;
+
+public:
+
+ ~recursive_wrapper();
+ recursive_wrapper();
+
+ recursive_wrapper(recursive_wrapper const& operand);
+ recursive_wrapper(T const& operand);
+ recursive_wrapper(recursive_wrapper&& operand);
+ recursive_wrapper(T&& operand);
+
+private:
+
+ void assign(const T& rhs);
+
+public:
+
+ inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
+ {
+ assign( rhs.get() );
+ return *this;
+ }
+
+ inline recursive_wrapper& operator=(T const& rhs)
+ {
+ assign( rhs );
+ return *this;
+ }
+
+ inline void swap(recursive_wrapper& operand) noexcept
+ {
+ T* temp = operand.p_;
+ operand.p_ = p_;
+ p_ = temp;
+ }
+
+
+ recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
+ {
+ swap(rhs);
+ return *this;
+ }
+
+ recursive_wrapper& operator=(T&& rhs)
+ {
+ get() = std::move(rhs);
+ return *this;
+ }
+
+
+public:
+
+ T& get() { return *get_pointer(); }
+ const T& get() const { return *get_pointer(); }
+ T* get_pointer() { return p_; }
+ const T* get_pointer() const { return p_; }
+ operator T const&() const { return this->get(); }
+ operator T&() { return this->get(); }
+};
+
+template <typename T>
+recursive_wrapper<T>::~recursive_wrapper()
+{
+ delete p_;
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper()
+ : p_(new T)
+{
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper(recursive_wrapper const& operand)
+ : p_(new T( operand.get() ))
+{
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper(T const& operand)
+ : p_(new T(operand))
+{
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper(recursive_wrapper&& operand)
+ : p_(operand.p_)
+{
+ operand.p_ = nullptr;
+}
+
+template <typename T>
+recursive_wrapper<T>::recursive_wrapper(T&& operand)
+ : p_(new T( std::move(operand) ))
+{
+}
+
+template <typename T>
+void recursive_wrapper<T>::assign(const T& rhs)
+{
+ this->get() = rhs;
+}
+
+template <typename T>
+inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
+{
+ lhs.swap(rhs);
+}
+
+}}
+
+#endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
diff --git a/include/mbgl/util/std.hpp b/include/mbgl/util/std.hpp
new file mode 100644
index 0000000000..051f89bb60
--- /dev/null
+++ b/include/mbgl/util/std.hpp
@@ -0,0 +1,38 @@
+#ifndef MBGL_UTIL_STD
+#define MBGL_UTIL_STD
+
+#include <memory>
+
+namespace std {
+
+// C++14 backfill from http://herbsutter.com/gotw/_102/
+template<typename T, typename ...Args>
+::std::unique_ptr<T> make_unique(Args&& ...args) {
+ return ::std::unique_ptr<T>(new T(::std::forward<Args>(args)...));
+}
+
+}
+
+namespace mbgl {
+namespace util {
+
+template <typename Container, typename ForwardIterator, typename Predicate>
+void erase_if(Container &container, ForwardIterator it, const ForwardIterator end, Predicate pred) {
+ while (it != end) {
+ if (pred(*it)) {
+ container.erase(it++);
+ } else {
+ ++it;
+ }
+ }
+}
+
+template <typename Container, typename Predicate>
+void erase_if(Container &container, Predicate pred) {
+ erase_if(container, container.begin(), container.end(), pred);
+}
+
+}
+}
+
+#endif
diff --git a/include/mbgl/util/string.hpp b/include/mbgl/util/string.hpp
new file mode 100644
index 0000000000..f17d55cec3
--- /dev/null
+++ b/include/mbgl/util/string.hpp
@@ -0,0 +1,24 @@
+#ifndef MBGL_UTIL_STRING
+#define MBGL_UTIL_STRING
+
+#include <string>
+
+namespace mbgl {
+namespace util {
+
+template<size_t max, typename... Args>
+inline std::string sprintf(const char *msg, Args... args) {
+ char res[max];
+ int len = snprintf(res, sizeof(res), msg, args...);
+ return std::string(res, len);
+}
+
+template<size_t max, typename... Args>
+inline std::string sprintf(const std::string &msg, Args... args) {
+ return sprintf<max>(msg.c_str(), args...);
+}
+
+}
+}
+
+#endif
diff --git a/include/mbgl/util/texturepool.hpp b/include/mbgl/util/texturepool.hpp
new file mode 100644
index 0000000000..566d8c1750
--- /dev/null
+++ b/include/mbgl/util/texturepool.hpp
@@ -0,0 +1,25 @@
+#ifndef MBGL_UTIL_TEXTUREPOOL
+#define MBGL_UTIL_TEXTUREPOOL
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/platform/gl.hpp>
+
+#include <set>
+#include <mutex>
+
+namespace mbgl {
+
+class Texturepool : private util::noncopyable {
+
+public:
+ GLuint getTextureID();
+ void removeTextureID(GLuint texture_id);
+ void clearTextureIDs();
+
+private:
+ std::set<GLuint> texture_ids;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/util/threadpool.hpp b/include/mbgl/util/threadpool.hpp
new file mode 100644
index 0000000000..497d4e3083
--- /dev/null
+++ b/include/mbgl/util/threadpool.hpp
@@ -0,0 +1,45 @@
+#ifndef MBGL_UTIL_THREADPOOL
+#define MBGL_UTIL_THREADPOOL
+
+#include <pthread.h>
+#include <forward_list>
+#include <queue>
+
+namespace mbgl {
+namespace util {
+
+class Threadpool {
+private:
+ class Worker {
+ public:
+ Worker(Threadpool& pool);
+ ~Worker();
+ static void *loop(void *ptr);
+
+ private:
+ Threadpool& pool;
+ pthread_t thread;
+ };
+
+public:
+ Threadpool(int max_workers = 4);
+ typedef void (*Callback)(void *);
+ void add(Callback callback, void *data);
+
+private:
+ typedef std::pair<Callback, void *> Task;
+ const int max_workers;
+ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ pthread_cond_t condition = PTHREAD_COND_INITIALIZER;
+ std::forward_list<Worker> workers;
+ int worker_count = 0;
+ std::queue<Task> tasks;
+};
+
+extern std::unique_ptr<Threadpool> threadpool;
+
+}
+}
+
+#endif
+
diff --git a/include/mbgl/util/time.hpp b/include/mbgl/util/time.hpp
new file mode 100644
index 0000000000..eacee2c982
--- /dev/null
+++ b/include/mbgl/util/time.hpp
@@ -0,0 +1,42 @@
+#ifndef MBGL_UTIL_TIME
+#define MBGL_UTIL_TIME
+
+#include <uv.h>
+
+namespace mbgl {
+
+typedef uint64_t timestamp;
+
+namespace util {
+
+
+// Returns time in nanoseconds since an arbitrary point in the past. This has
+// no relation to the current time, but is continuously increasing, so
+// comparisons between different timestamps produce meaningful values.
+inline timestamp now() {
+ return uv_hrtime();
+}
+}
+
+// used for time conversions
+constexpr timestamp operator"" _nanoseconds (long double ns) { return ns; }
+constexpr timestamp operator"" _nanosecond (long double ns) { return ns; }
+constexpr timestamp operator"" _microseconds (long double us) { return us * 1e3; }
+constexpr timestamp operator"" _microsecond (long double us) { return us * 1e3; }
+constexpr timestamp operator"" _milliseconds (long double ms) { return ms * 1e6; }
+constexpr timestamp operator"" _millisecond (long double ms) { return ms * 1e6; }
+constexpr timestamp operator"" _seconds (long double s) { return s * 1e9; }
+constexpr timestamp operator"" _second (long double s) { return s * 1e9; }
+
+constexpr timestamp operator"" _nanoseconds (unsigned long long ns) { return ns; }
+constexpr timestamp operator"" _nanosecond (unsigned long long ns) { return ns; }
+constexpr timestamp operator"" _microseconds (unsigned long long us) { return us * 1e3; }
+constexpr timestamp operator"" _microsecond (unsigned long long us) { return us * 1e3; }
+constexpr timestamp operator"" _milliseconds (unsigned long long ms) { return ms * 1e6; }
+constexpr timestamp operator"" _millisecond (unsigned long long ms) { return ms * 1e6; }
+constexpr timestamp operator"" _seconds (unsigned long long s) { return s * 1e9; }
+constexpr timestamp operator"" _second (unsigned long long s) { return s * 1e9; }
+
+}
+
+#endif
diff --git a/include/mbgl/util/timer.hpp b/include/mbgl/util/timer.hpp
new file mode 100644
index 0000000000..8171c2f5d1
--- /dev/null
+++ b/include/mbgl/util/timer.hpp
@@ -0,0 +1,40 @@
+#ifndef MBGL_UTIL_TIMER
+#define MBGL_UTIL_TIMER
+
+#include <mbgl/platform/event.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace util {
+
+#ifndef DISABLE_TIMER
+class timer {
+public:
+ timer(Event event = Event::General);
+ timer(EventSeverity severity, Event event = Event::General);
+ timer(const std::string &name, Event event = Event::General);
+ timer(const std::string &name, EventSeverity severity, Event event = Event::General);
+ void report(const std::string &name);
+ ~timer();
+
+private:
+ const std::string name;
+ EventSeverity severity = EventSeverity::Debug;
+ Event event = Event::General;
+ uint64_t start;
+};
+#else
+class timer {
+ inline timer(Event event = Event::General);
+ inline timer(EventSeverity severity, Event event = Event::General);
+ inline timer(const std::string &name, Event event = Event::General);
+ inline timer(const std::string &name, EventSeverity severity, Event event = Event::General);
+ inline void report(const std::string &name) {}
+ inline ~timer() {}
+};
+#endif
+}
+}
+
+#endif
diff --git a/include/mbgl/util/token.hpp b/include/mbgl/util/token.hpp
new file mode 100644
index 0000000000..a794e0489c
--- /dev/null
+++ b/include/mbgl/util/token.hpp
@@ -0,0 +1,52 @@
+#ifndef MBGL_UTIL_TOKEN
+#define MBGL_UTIL_TOKEN
+
+#ifdef __linux__
+#include <boost/regex.hpp>
+namespace regex_impl = boost;
+#else
+#include <regex>
+namespace regex_impl = std;
+#endif
+
+#include <map>
+
+namespace mbgl {
+namespace util {
+
+namespace detail {
+const regex_impl::regex tokenRegex("\\{(\\w+)\\}");
+const regex_impl::sregex_token_iterator tokensEnd = regex_impl::sregex_token_iterator();
+}
+
+template <typename Lookup>
+std::string replaceTokens(const std::string &source, const Lookup &lookup) {
+ std::string result;
+ result.reserve(source.size());
+
+ bool token = false;
+ for (auto token_it = regex_impl::sregex_token_iterator(source.begin(), source.end(),
+ detail::tokenRegex, {-1, 1});
+ token_it != detail::tokensEnd; ++token_it, token = !token) {
+ if (!token_it->matched) {
+ continue;
+ }
+
+ result += token ? lookup(token_it->str()) : token_it->str();
+ }
+
+ return result;
+}
+
+template <typename T>
+inline std::string replaceTokens(const std::string &source, const std::map<std::string, T> &properties) {
+ return replaceTokens(source, [&properties](const std::string &token) -> std::string {
+ const auto it_prop = properties.find(token);
+ return it_prop != properties.end() ? toString(it_prop->second) : "";
+ });
+}
+
+} // end namespace util
+} // end namespace mbgl
+
+#endif
diff --git a/include/mbgl/util/transition.hpp b/include/mbgl/util/transition.hpp
new file mode 100644
index 0000000000..b12527124e
--- /dev/null
+++ b/include/mbgl/util/transition.hpp
@@ -0,0 +1,84 @@
+#ifndef MBGL_UTIL_TRANSITION
+#define MBGL_UTIL_TRANSITION
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/time.hpp>
+#include <mbgl/style/types.hpp>
+
+namespace mbgl {
+namespace util {
+
+class transition : private noncopyable {
+public:
+ enum state {
+ running,
+ complete
+ };
+
+ inline transition(timestamp start, timestamp duration)
+ : start(start),
+ duration(duration) {}
+
+ inline float progress(timestamp now) const {
+ if (duration == 0) return 1;
+ if (start > now) return 0;
+
+ return (float)(now - start) / duration;
+ }
+
+ virtual state update(timestamp now) const = 0;
+ virtual ~transition();
+
+protected:
+ double interpolateDouble(double from, double to, double t) const;
+ float interpolateFloat(float from, float to, double t) const;
+ Color interpolateColor(Color from, Color to, double t) const;
+ std::array<float, 2> interpolateFloatArray(std::array<float, 2> from, std::array<float, 2> to, double t) const;
+
+protected:
+ const timestamp start, duration;
+};
+
+template <typename T>
+class ease_transition : public transition {
+public:
+ ease_transition(T from, T to, T& value, timestamp start, timestamp duration)
+ : transition(start, duration),
+ from(from),
+ to(to),
+ value(value) {}
+
+ state update(timestamp now) const;
+
+private:
+ const T from, to;
+ T& value;
+
+};
+
+template <typename T>
+class timeout : public transition {
+public:
+ timeout(T final_value, T& value, timestamp start, timestamp duration)
+ : transition(start, duration),
+ final_value(final_value),
+ value(value) {}
+
+ state update(timestamp now) const {
+ if (progress(now) >= 1) {
+ value = final_value;
+ return complete;
+ } else {
+ return running;
+ }
+ }
+
+private:
+ const T final_value;
+ T& value;
+};
+
+}
+}
+
+#endif
diff --git a/include/mbgl/util/unitbezier.hpp b/include/mbgl/util/unitbezier.hpp
new file mode 100644
index 0000000000..095e15f809
--- /dev/null
+++ b/include/mbgl/util/unitbezier.hpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MBGL_UTIL_UNITBEZIER
+#define MBGL_UTIL_UNITBEZIER
+
+#include <cmath>
+
+namespace mbgl {
+namespace util {
+
+struct UnitBezier {
+ UnitBezier(double p1x, double p1y, double p2x, double p2y) {
+ // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
+ cx = 3.0 * p1x;
+ bx = 3.0 * (p2x - p1x) - cx;
+ ax = 1.0 - cx - bx;
+
+ cy = 3.0 * p1y;
+ by = 3.0 * (p2y - p1y) - cy;
+ ay = 1.0 - cy - by;
+ }
+
+ double sampleCurveX(double t) {
+ // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
+ return ((ax * t + bx) * t + cx) * t;
+ }
+
+ double sampleCurveY(double t) {
+ return ((ay * t + by) * t + cy) * t;
+ }
+
+ double sampleCurveDerivativeX(double t) {
+ return (3.0 * ax * t + 2.0 * bx) * t + cx;
+ }
+
+ // Given an x value, find a parametric value it came from.
+ double solveCurveX(double x, double epsilon) {
+ double t0;
+ double t1;
+ double t2;
+ double x2;
+ double d2;
+ int i;
+
+ // First try a few iterations of Newton's method -- normally very fast.
+ for (t2 = x, i = 0; i < 8; ++i) {
+ x2 = sampleCurveX(t2) - x;
+ if (fabs (x2) < epsilon)
+ return t2;
+ d2 = sampleCurveDerivativeX(t2);
+ if (fabs(d2) < 1e-6)
+ break;
+ t2 = t2 - x2 / d2;
+ }
+
+ // Fall back to the bisection method for reliability.
+ t0 = 0.0;
+ t1 = 1.0;
+ t2 = x;
+
+ if (t2 < t0)
+ return t0;
+ if (t2 > t1)
+ return t1;
+
+ while (t0 < t1) {
+ x2 = sampleCurveX(t2);
+ if (fabs(x2 - x) < epsilon)
+ return t2;
+ if (x > x2)
+ t0 = t2;
+ else
+ t1 = t2;
+ t2 = (t1 - t0) * .5 + t0;
+ }
+
+ // Failure.
+ return t2;
+ }
+
+ double solve(double x, double epsilon) {
+ return sampleCurveY(solveCurveX(x, epsilon));
+ }
+
+private:
+ double ax;
+ double bx;
+ double cx;
+
+ double ay;
+ double by;
+ double cy;
+};
+
+}
+}
+
+#endif
diff --git a/include/mbgl/util/utf.hpp b/include/mbgl/util/utf.hpp
new file mode 100644
index 0000000000..5dfc4ad2d1
--- /dev/null
+++ b/include/mbgl/util/utf.hpp
@@ -0,0 +1,50 @@
+#ifndef MBGL_UTIL_UTF
+#define MBGL_UTIL_UTF
+
+#include <memory>
+
+// g++/libstdc++ is missing c++11 codecvt support
+#ifdef __linux__
+#pragma GCC diagnostic push
+#ifndef __clang__
+#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
+#endif
+#include <boost/locale.hpp>
+#pragma GCC diagnostic pop
+#else
+#include <codecvt>
+#include <locale>
+#endif
+
+namespace mbgl {
+
+namespace util {
+
+#ifdef __linux__
+
+class utf8_to_utf32 {
+ public:
+ explicit utf8_to_utf32() {}
+ std::u32string convert(std::string const& utf8) {
+ return boost::locale::conv::utf_to_utf<char32_t>(utf8);
+ }
+};
+
+#else
+
+class utf8_to_utf32 {
+ public:
+ explicit utf8_to_utf32()
+ : utf32conv_() {}
+ std::u32string convert(std::string const& utf8) {
+ return utf32conv_.from_bytes(utf8);
+ }
+ private:
+ std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> utf32conv_;
+};
+
+#endif
+
+}}
+
+#endif
diff --git a/include/mbgl/util/uv.hpp b/include/mbgl/util/uv.hpp
new file mode 100644
index 0000000000..f36da83e4d
--- /dev/null
+++ b/include/mbgl/util/uv.hpp
@@ -0,0 +1,141 @@
+#ifndef MBGL_UTIL_UV
+#define MBGL_UTIL_UV
+
+#include <uv.h>
+#include <functional>
+#include <cassert>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#endif
+
+#include <boost/lockfree/queue.hpp>
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+
+namespace uv {
+
+class loop {
+public:
+ inline loop() : l(uv_loop_new()) {}
+ inline ~loop() { uv_loop_delete(l); }
+
+ inline uv_loop_t *operator*() { return l; }
+
+private:
+ uv_loop_t *l;
+};
+
+class mutex {
+public:
+ inline mutex() {
+ if (uv_mutex_init(&mtx) != 0) {
+ throw std::runtime_error("failed to initialize mutex");
+ }
+ }
+ inline ~mutex() { uv_mutex_destroy(&mtx); }
+ inline void lock() { uv_mutex_lock(&mtx); }
+ inline void unlock() { uv_mutex_unlock(&mtx); }
+
+private:
+ uv_mutex_t mtx;
+};
+
+class lock {
+public:
+ lock(mutex &mtx) : mtx(mtx) { mtx.lock(); }
+ ~lock() { mtx.unlock(); }
+
+private:
+ mutex &mtx;
+};
+
+class rwlock {
+public:
+ inline rwlock() {
+ if (uv_rwlock_init(&mtx) != 0) {
+ throw std::runtime_error("failed to initialize read-write lock");
+ }
+ }
+ inline ~rwlock() { uv_rwlock_destroy(&mtx); }
+ inline void rdlock() { uv_rwlock_rdlock(&mtx); }
+ inline void wrlock() { uv_rwlock_wrlock(&mtx); }
+ inline void rdunlock() { uv_rwlock_rdunlock(&mtx); }
+ inline void wrunlock() { uv_rwlock_wrunlock(&mtx); }
+
+private:
+ uv_rwlock_t mtx;
+};
+
+class readlock {
+public:
+ inline readlock(rwlock &mtx) : mtx(mtx) { mtx.rdlock(); }
+ inline ~readlock() { mtx.rdunlock(); }
+
+private:
+ rwlock &mtx;
+};
+
+class writelock {
+public:
+ inline writelock(rwlock &mtx) : mtx(mtx) { mtx.wrlock(); }
+ inline ~writelock() { mtx.wrunlock(); }
+
+private:
+ rwlock &mtx;
+};
+
+class once {
+public:
+ typedef void (*callback)();
+ void operator()(void (*callback)(void)) {
+ uv_once(&o, callback);
+ }
+
+private:
+ uv_once_t o = UV_ONCE_INIT;
+};
+
+template <typename T>
+class work {
+public:
+ typedef void (*work_callback)(T &object);
+ typedef void (*after_work_callback)(T &object);
+
+ template<typename... Args>
+ work(const std::shared_ptr<loop> &loop, work_callback work_cb, after_work_callback after_work_cb, Args&&... args)
+ : loop(loop),
+ data(std::forward<Args>(args)...),
+ work_cb(work_cb),
+ after_work_cb(after_work_cb) {
+ req.data = this;
+ uv_queue_work(**loop, &req, do_work, after_work);
+ }
+
+private:
+ static void do_work(uv_work_t *req) {
+ work<T> *w = static_cast<work<T> *>(req->data);
+ w->work_cb(w->data);
+ }
+
+ static void after_work(uv_work_t *req, int) {
+ work<T> *w = static_cast<work<T> *>(req->data);
+ w->after_work_cb(w->data);
+ delete w;
+ }
+
+private:
+ std::shared_ptr<uv::loop> loop;
+ uv_work_t req;
+ T data;
+ work_callback work_cb;
+ after_work_callback after_work_cb;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/util/variant.hpp b/include/mbgl/util/variant.hpp
new file mode 100644
index 0000000000..ddc82ee311
--- /dev/null
+++ b/include/mbgl/util/variant.hpp
@@ -0,0 +1,731 @@
+#ifndef MAPBOX_UTIL_VARIANT_HPP
+#define MAPBOX_UTIL_VARIANT_HPP
+
+#include <utility>
+#include <typeinfo>
+#include <type_traits>
+#include <algorithm> // std::move/swap
+#include <stdexcept> // runtime_error
+#include <new> // operator new
+#include <cstddef> // size_t
+#include <iosfwd>
+#include <string>
+
+#include "recursive_wrapper.hpp"
+
+#ifdef _MSC_VER
+ // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx
+ #ifdef NDEBUG
+ #define VARIANT_INLINE __forceinline
+ #else
+ #define VARIANT_INLINE __declspec(noinline)
+ #endif
+#else
+ #ifdef NDEBUG
+ #define VARIANT_INLINE inline __attribute__((always_inline))
+ #else
+ #define VARIANT_INLINE __attribute__((noinline))
+ #endif
+#endif
+
+#define VARIANT_MAJOR_VERSION 0
+#define VARIANT_MINOR_VERSION 1
+#define VARIANT_PATCH_VERSION 0
+
+// translates to 100
+#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION)
+
+namespace mbgl { namespace util { namespace detail {
+
+static constexpr std::size_t invalid_value = std::size_t(-1);
+
+template <typename T, typename...Types>
+struct direct_type;
+
+template <typename T, typename First, typename...Types>
+struct direct_type<T, First, Types...>
+{
+ static constexpr std::size_t index = std::is_same<T, First>::value
+ ? sizeof...(Types) : direct_type<T, Types...>::index;
+};
+
+template <typename T>
+struct direct_type<T>
+{
+ static constexpr std::size_t index = invalid_value;
+};
+
+template <typename T, typename...Types>
+struct convertible_type;
+
+template <typename T, typename First, typename...Types>
+struct convertible_type<T, First, Types...>
+{
+ static constexpr std::size_t index = std::is_convertible<T, First>::value
+ ? sizeof...(Types) : convertible_type<T, Types...>::index;
+};
+
+template <typename T>
+struct convertible_type<T>
+{
+ static constexpr std::size_t index = invalid_value;
+};
+
+template <typename T, typename...Types>
+struct value_traits
+{
+ static constexpr std::size_t direct_index = direct_type<T, Types...>::index;
+ static constexpr std::size_t index =
+ (direct_index == invalid_value) ? convertible_type<T, Types...>::index : direct_index;
+};
+
+template <typename T, typename...Types>
+struct is_valid_type;
+
+template <typename T, typename First, typename... Types>
+struct is_valid_type<T, First, Types...>
+{
+ static constexpr bool value = std::is_convertible<T, First>::value
+ || is_valid_type<T, Types...>::value;
+};
+
+template <typename T>
+struct is_valid_type<T> : std::false_type {};
+
+template <std::size_t N, typename ... Types>
+struct select_type
+{
+ static_assert(N < sizeof...(Types), "index out of bounds");
+};
+
+template <std::size_t N, typename T, typename ... Types>
+struct select_type<N, T, Types...>
+{
+ using type = typename select_type<N - 1, Types...>::type;
+};
+
+template <typename T, typename ... Types>
+struct select_type<0, T, Types...>
+{
+ using type = T;
+};
+
+} // namespace detail
+
+// static visitor
+template <typename R = void>
+struct static_visitor
+{
+ using result_type = R;
+protected:
+ static_visitor() {}
+ ~static_visitor() {}
+};
+
+
+template <std::size_t arg1, std::size_t ... others>
+struct static_max;
+
+template <std::size_t arg>
+struct static_max<arg>
+{
+ static const std::size_t value = arg;
+};
+
+template <std::size_t arg1, std::size_t arg2, std::size_t ... others>
+struct static_max<arg1, arg2, others...>
+{
+ static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value :
+ static_max<arg2, others...>::value;
+};
+
+template<typename... Types>
+struct variant_helper;
+
+template<typename T, typename... Types>
+struct variant_helper<T, Types...>
+{
+ VARIANT_INLINE static void destroy(const std::size_t id, void * data)
+ {
+ if (id == sizeof...(Types))
+ {
+ reinterpret_cast<T*>(data)->~T();
+ }
+ else
+ {
+ variant_helper<Types...>::destroy(id, data);
+ }
+ }
+
+ VARIANT_INLINE static void move(const std::size_t old_id, void * old_value, void * new_value)
+ {
+ if (old_id == sizeof...(Types))
+ {
+ new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
+ //std::memcpy(new_value, old_value, sizeof(T));
+ // ^^ DANGER: this should only be considered for relocatable types e.g built-in types
+ // Also, I don't see any measurable performance benefit just yet
+ }
+ else
+ {
+ variant_helper<Types...>::move(old_id, old_value, new_value);
+ }
+ }
+
+ VARIANT_INLINE static void copy(const std::size_t old_id, const void * old_value, void * new_value)
+ {
+ if (old_id == sizeof...(Types))
+ {
+ new (new_value) T(*reinterpret_cast<const T*>(old_value));
+ }
+ else
+ {
+ variant_helper<Types...>::copy(old_id, old_value, new_value);
+ }
+ }
+};
+
+template<> struct variant_helper<>
+{
+ VARIANT_INLINE static void destroy(const std::size_t, void *) {}
+ VARIANT_INLINE static void move(const std::size_t, void *, void *) {}
+ VARIANT_INLINE static void copy(const std::size_t, const void *, void *) {}
+};
+
+namespace detail {
+
+template <typename T>
+struct unwrapper
+{
+ T const& operator() (T const& obj) const
+ {
+ return obj;
+ }
+
+ T& operator() (T & obj) const
+ {
+ return obj;
+ }
+};
+
+
+template <typename T>
+struct unwrapper<recursive_wrapper<T>>
+{
+ auto operator() (recursive_wrapper<T> const& obj) const
+ -> typename recursive_wrapper<T>::type const&
+ {
+ return obj.get();
+ }
+};
+
+
+template <typename F, typename V, typename...Types>
+struct dispatcher;
+
+template <typename F, typename V, typename T, typename...Types>
+struct dispatcher<F, V, T, Types...>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const& v, F f)
+ {
+ if (v.get_type_index() == sizeof...(Types))
+ {
+ return f(unwrapper<T>()(v. template get<T>()));
+ }
+ else
+ {
+ return dispatcher<F, V, Types...>::apply_const(v, f);
+ }
+ }
+
+ VARIANT_INLINE static result_type apply(V & v, F f)
+ {
+ if (v.get_type_index() == sizeof...(Types))
+ {
+ return f(unwrapper<T>()(v. template get<T>()));
+ }
+ else
+ {
+ return dispatcher<F, V, Types...>::apply(v, f);
+ }
+ }
+};
+
+template<typename F, typename V>
+struct dispatcher<F, V>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const&, F)
+ {
+ throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
+ }
+
+ VARIANT_INLINE static result_type apply(V &, F)
+ {
+ throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
+ }
+};
+
+
+template <typename F, typename V, typename T, typename...Types>
+struct binary_dispatcher_rhs;
+
+template <typename F, typename V, typename T0, typename T1, typename...Types>
+struct binary_dispatcher_rhs<F, V, T0, T1, Types...>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
+ {
+ if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
+ {
+ return f(unwrapper<T0>()(lhs. template get<T0>()),
+ unwrapper<T1>()(rhs. template get<T1>()));
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, T0, Types...>::apply_const(lhs, rhs, f);
+ }
+ }
+
+ VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
+ {
+ if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
+ {
+ return f(unwrapper<T0>()(lhs. template get<T0>()),
+ unwrapper<T1>()(rhs. template get<T1>()));
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, T0, Types...>::apply(lhs, rhs, f);
+ }
+ }
+
+};
+
+template<typename F, typename V, typename T>
+struct binary_dispatcher_rhs<F, V, T>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+ {
+ throw std::runtime_error("binary dispatch: FAIL");
+ }
+ VARIANT_INLINE static result_type apply(V &, V &, F)
+ {
+ throw std::runtime_error("binary dispatch: FAIL");
+ }
+};
+
+
+template <typename F, typename V, typename T, typename...Types>
+struct binary_dispatcher_lhs;
+
+template <typename F, typename V, typename T0, typename T1, typename...Types>
+struct binary_dispatcher_lhs<F, V, T0, T1, Types...>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
+ {
+ if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
+ {
+ return f(lhs. template get<T1>(), rhs. template get<T0>());
+ }
+ else
+ {
+ return binary_dispatcher_lhs<F, V, T0, Types...>::apply_const(lhs, rhs, f);
+ }
+ }
+
+ VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
+ {
+ if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
+ {
+ return f(lhs. template get<T1>(), rhs. template get<T0>());
+ }
+ else
+ {
+ return binary_dispatcher_lhs<F, V, T0, Types...>::apply(lhs, rhs, f);
+ }
+ }
+
+};
+
+template<typename F, typename V, typename T>
+struct binary_dispatcher_lhs<F, V, T>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+ {
+ throw std::runtime_error("binary dispatch: FAIL");
+ }
+
+ VARIANT_INLINE static result_type apply(V &, V &, F)
+ {
+ throw std::runtime_error("binary dispatch: FAIL");
+ }
+};
+
+template <typename F, typename V, typename...Types>
+struct binary_dispatcher;
+
+template <typename F, typename V, typename T, typename...Types>
+struct binary_dispatcher<F, V, T, Types...>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f)
+ {
+ if (v0.get_type_index() == sizeof...(Types))
+ {
+ if (v0.get_type_index() == v1.get_type_index())
+ {
+ return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, T, Types...>::apply_const(v0, v1, f);
+ }
+ }
+ else if (v1.get_type_index() == sizeof...(Types))
+ {
+ return binary_dispatcher_lhs<F, V, T, Types...>::apply_const(v0, v1, f);
+ }
+ return binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f);
+ }
+
+ VARIANT_INLINE static result_type apply(V & v0, V & v1, F f)
+ {
+ if (v0.get_type_index() == sizeof...(Types))
+ {
+ if (v0.get_type_index() == v1.get_type_index())
+ {
+ return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, T, Types...>::apply(v0, v1, f);
+ }
+ }
+ else if (v1.get_type_index() == sizeof...(Types))
+ {
+ return binary_dispatcher_lhs<F, V, T, Types...>::apply(v0, v1, f);
+ }
+ return binary_dispatcher<F, V, Types...>::apply(v0, v1, f);
+ }
+};
+
+template<typename F, typename V>
+struct binary_dispatcher<F, V>
+{
+ using result_type = typename F::result_type;
+ VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
+ {
+ throw std::runtime_error("binary dispatch: FAIL");
+ }
+
+ VARIANT_INLINE static result_type apply(V &, V &, F)
+ {
+ throw std::runtime_error("binary dispatch: FAIL");
+ }
+};
+
+// comparator functors
+struct equal_comp
+{
+ template <typename T>
+ bool operator()(T const& lhs, T const& rhs) const
+ {
+ return lhs == rhs;
+ }
+};
+
+struct less_comp
+{
+ template <typename T>
+ bool operator()(T const& lhs, T const& rhs) const
+ {
+ return lhs < rhs;
+ }
+};
+
+template <typename Variant, typename Comp>
+class comparer : public static_visitor<bool>
+{
+public:
+ explicit comparer(Variant const& lhs) noexcept
+ : lhs_(lhs) {}
+ comparer& operator=(comparer const&) = delete;
+ // visitor
+ template<typename T>
+ bool operator()(T const& rhs_content) const
+ {
+ T const& lhs_content = lhs_.template get<T>();
+ return Comp()(lhs_content, rhs_content);
+ }
+private:
+ Variant const& lhs_;
+};
+
+// operator<< helper
+template <typename Out>
+class printer : public static_visitor<>
+{
+public:
+ explicit printer(Out & out)
+ : out_(out) {}
+ printer& operator=(printer const&) = delete;
+
+// visitor
+ template <typename T>
+ void operator()(T const& operand) const
+ {
+ out_ << operand;
+ }
+private:
+ Out & out_;
+};
+
+} // namespace detail
+
+template<typename... Types>
+class variant
+{
+private:
+
+ static const std::size_t data_size = static_max<sizeof(Types)...>::value;
+ static const std::size_t data_align = static_max<alignof(Types)...>::value;
+
+ using data_type = typename std::aligned_storage<data_size, data_align>::type;
+ using helper_type = variant_helper<Types...>;
+
+ std::size_t type_index;
+ data_type data;
+
+public:
+
+ VARIANT_INLINE variant()
+ : type_index(sizeof...(Types) - 1)
+ {
+ new (&data) typename detail::select_type<0, Types...>::type();
+ }
+
+ template <typename T, class = typename std::enable_if<
+ detail::is_valid_type<T, Types...>::value>::type>
+ VARIANT_INLINE explicit variant(T const& val) noexcept
+ : type_index(detail::value_traits<T, Types...>::index)
+ {
+ constexpr std::size_t index = sizeof...(Types) - detail::value_traits<T, Types...>::index - 1;
+ using target_type = typename detail::select_type<index, Types...>::type;
+ new (&data) target_type(val);
+ }
+
+ template <typename T, class = typename std::enable_if<
+ detail::is_valid_type<T, Types...>::value>::type>
+ VARIANT_INLINE variant(T && val) noexcept
+ : type_index(detail::value_traits<T, Types...>::index)
+ {
+ constexpr std::size_t index = sizeof...(Types) - detail::value_traits<T, Types...>::index - 1;
+ using target_type = typename detail::select_type<index, Types...>::type;
+ new (&data) target_type(std::forward<T>(val)); // nothrow
+ }
+
+ VARIANT_INLINE variant(variant<Types...> const& old)
+ : type_index(old.type_index)
+ {
+ helper_type::copy(old.type_index, &old.data, &data);
+ }
+
+ VARIANT_INLINE variant(variant<Types...>&& old) noexcept
+ : type_index(old.type_index)
+ {
+ helper_type::move(old.type_index, &old.data, &data);
+ }
+
+ friend void swap(variant<Types...> & first, variant<Types...> & second)
+ {
+ using std::swap; //enable ADL
+ swap(first.type_index, second.type_index);
+ swap(first.data, second.data);
+ }
+
+ VARIANT_INLINE variant<Types...>& operator=(variant<Types...> other)
+ {
+ swap(*this, other);
+ return *this;
+ }
+
+ // conversions
+ // move-assign
+ template <typename T>
+ VARIANT_INLINE variant<Types...>& operator=(T && rhs) noexcept
+ {
+ variant<Types...> temp(std::move(rhs));
+ swap(*this, temp);
+ return *this;
+ }
+
+ // copy-assign
+ template <typename T>
+ VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
+ {
+ variant<Types...> temp(rhs);
+ swap(*this, temp);
+ return *this;
+ }
+
+ template<typename T>
+ VARIANT_INLINE bool is() const
+ {
+ return (type_index == detail::direct_type<T, Types...>::index);
+ }
+
+ VARIANT_INLINE bool valid() const
+ {
+ return (type_index != detail::invalid_value);
+ }
+
+ template<typename T, typename... Args>
+ VARIANT_INLINE void set(Args&&... args)
+ {
+ helper_type::destroy(type_index, &data);
+ new (&data) T(std::forward<Args>(args)...);
+ type_index = detail::direct_type<T, Types...>::index;
+ }
+
+ template<typename T>
+ VARIANT_INLINE T& get()
+ {
+ if (type_index == detail::direct_type<T, Types...>::index)
+ {
+ return *reinterpret_cast<T*>(&data);
+ }
+ else
+ {
+ throw std::runtime_error("in get()");
+ }
+ }
+
+ template<typename T>
+ VARIANT_INLINE T const& get() const
+ {
+ if (type_index == detail::direct_type<T, Types...>::index)
+ {
+ return *reinterpret_cast<T const*>(&data);
+ }
+ else
+ {
+ throw std::runtime_error("in get()");
+ }
+ }
+
+ VARIANT_INLINE std::size_t get_type_index() const
+ {
+ return type_index;
+ }
+
+ // visitor
+ // unary
+ template <typename F, typename V>
+ auto VARIANT_INLINE
+ static visit(V const& v, F f)
+ -> decltype(detail::dispatcher<F, V, Types...>::apply_const(v, f))
+ {
+ return detail::dispatcher<F, V, Types...>::apply_const(v, f);
+ }
+ // non-const
+ template <typename F, typename V>
+ auto VARIANT_INLINE
+ static visit(V & v, F f)
+ -> decltype(detail::dispatcher<F, V, Types...>::apply(v, f))
+ {
+ return detail::dispatcher<F, V, Types...>::apply(v, f);
+ }
+
+ // binary
+ // const
+ template <typename F, typename V>
+ auto VARIANT_INLINE
+ static binary_visit(V const& v0, V const& v1, F f)
+ -> decltype(detail::binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f))
+ {
+ return detail::binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f);
+ }
+ // non-const
+ template <typename F, typename V>
+ auto VARIANT_INLINE
+ static binary_visit(V& v0, V& v1, F f)
+ -> decltype(detail::binary_dispatcher<F, V, Types...>::apply(v0, v1, f))
+ {
+ return detail::binary_dispatcher<F, V, Types...>::apply(v0, v1, f);
+ }
+
+ ~variant() noexcept
+ {
+ helper_type::destroy(type_index, &data);
+ }
+
+ // comparison operators
+ // equality
+ VARIANT_INLINE bool operator==(variant const& rhs) const
+ {
+ if (this->get_type_index() != rhs.get_type_index())
+ return false;
+ detail::comparer<variant, detail::equal_comp> visitor(*this);
+ return visit(rhs, visitor);
+ }
+ // less than
+ VARIANT_INLINE bool operator<(variant const& rhs) const
+ {
+ if (this->get_type_index() != rhs.get_type_index())
+ {
+ return this->get_type_index() < rhs.get_type_index();
+ // ^^ borrowed from boost::variant
+ }
+ detail::comparer<variant, detail::less_comp> visitor(*this);
+ return visit(rhs, visitor);
+ }
+};
+
+// unary visitor interface
+
+// const
+template <typename V, typename F>
+auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f))
+{
+ return V::visit(v, f);
+}
+// non-const
+template <typename V, typename F>
+auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f))
+{
+ return V::visit(v, f);
+}
+
+// binary visitor interface
+// const
+template <typename V, typename F>
+auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f))
+{
+ return V::binary_visit(v0, v1, f);
+}
+// non-const
+template <typename V, typename F>
+auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f))
+{
+ return V::binary_visit(v0, v1, f);
+}
+
+
+// operator<<
+template <typename charT, typename traits, typename Variant>
+VARIANT_INLINE std::basic_ostream<charT, traits>&
+operator<< (std::basic_ostream<charT, traits>& out, Variant const& rhs)
+{
+ detail::printer<std::basic_ostream<charT, traits>> visitor(out);
+ apply_visitor(visitor, rhs);
+ return out;
+}
+
+}}
+
+#endif // MAPBOX_UTIL_VARIANT_HPP
diff --git a/include/mbgl/util/vec.hpp b/include/mbgl/util/vec.hpp
new file mode 100644
index 0000000000..0b9bf63d53
--- /dev/null
+++ b/include/mbgl/util/vec.hpp
@@ -0,0 +1,117 @@
+#ifndef MBGL_UTIL_VEC
+#define MBGL_UTIL_VEC
+
+#include <limits>
+#include <type_traits>
+#include <cmath>
+#include <cstdint>
+#include <array>
+
+namespace mbgl {
+
+template <typename T = double>
+struct vec2 {
+ struct null {};
+ typedef T Type;
+
+ T x, y;
+
+ inline vec2() {}
+
+ template<typename U = T, typename std::enable_if<std::numeric_limits<U>::has_quiet_NaN, int>::type = 0>
+ inline vec2(null) : x(std::numeric_limits<T>::quiet_NaN()), y(std::numeric_limits<T>::quiet_NaN()) {}
+
+ template<typename U = T, typename std::enable_if<!std::numeric_limits<U>::has_quiet_NaN, int>::type = 0>
+ inline vec2(null) : x(std::numeric_limits<T>::min()), y(std::numeric_limits<T>::min()) {}
+
+ inline vec2(const vec2& o) : x(o.x), y(o.y) {}
+
+ template<typename U>
+ inline vec2(const U& u) : x(u.x), y(u.y) {}
+
+ inline vec2(T x, T y) : x(x), y(y) {}
+
+ inline bool operator==(const vec2& rhs) const {
+ return x == rhs.x && y == rhs.y;
+ }
+
+ template <typename O>
+ inline typename std::enable_if<std::is_arithmetic<O>::value, vec2>::type
+ operator*(O o) const {
+ return {x * o, y * o};
+ }
+
+ template <typename O>
+ inline typename std::enable_if<std::is_arithmetic<O>::value, vec2>::type &
+ operator*=(O o) {
+ x *= o;
+ y *= o;
+ }
+
+ inline vec2<T> operator *(const std::array<float, 16>& matrix) {
+ return { x * matrix[0] + y * matrix[4] + matrix[12], x * matrix[1] + y * matrix[5] + matrix[13] };
+ }
+
+ template <typename O>
+ inline typename std::enable_if<std::is_arithmetic<O>::value, vec2>::type
+ operator-(O o) const {
+ return {x - o, y - o};
+ }
+
+ template <typename O>
+ inline typename std::enable_if<!std::is_arithmetic<O>::value, vec2>::type
+ operator-(const O &o) const {
+ return {x - o.x, y - o.y};
+ }
+
+ template <typename M>
+ inline vec2 matMul(const M &m) const {
+ return {m[0] * x + m[1] * y, m[2] * x + m[3] * y};
+ }
+
+ template<typename U = T, typename std::enable_if<std::numeric_limits<U>::has_quiet_NaN, int>::type = 0>
+ inline operator bool() const {
+ return !isnan(x) && !isnan(y);
+ }
+
+ template<typename U = T, typename std::enable_if<!std::numeric_limits<U>::has_quiet_NaN, int>::type = 0>
+ inline operator bool() const {
+ return x != std::numeric_limits<T>::min() && y != std::numeric_limits<T>::min();
+ }
+};
+
+template <typename T = double>
+struct vec3 {
+ T x, y, z;
+
+ inline vec3() {}
+ inline vec3(const vec3& o) : x(o.x), y(o.y), z(o.z) {}
+ inline vec3(T x, T y, T z) : x(x), y(y), z(z) {}
+ inline bool operator==(const vec3& rhs) const {
+ return x == rhs.x && y == rhs.y && z == rhs.z;
+ }
+};
+
+template <typename T = double>
+struct vec4 {
+ T x, y, z, w;
+
+ inline vec4() {}
+ inline vec4(const vec4& o) : x(o.x), y(o.y), z(o.z), w(o.w) {}
+ inline vec4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {}
+ inline bool operator==(const vec4& rhs) const {
+ return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w;
+ }
+};
+
+
+struct box {
+ vec2<double> tl, tr, bl, br;
+ vec2<double> center;
+};
+
+typedef vec2<int16_t> Coordinate;
+
+}
+
+#endif