diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2014-07-16 18:53:56 -0700 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2014-07-16 18:53:56 -0700 |
commit | 4ea281c750c5afcc68f2832bb42d98a1cbce6735 (patch) | |
tree | 60bc7d3ccba2c54859e2e023997cc027cc67aea7 /include/mbgl | |
parent | c1a64dc5fa73b54cc5de77629781dfc74302a1e7 (diff) | |
download | qtlocation-mapboxgl-4ea281c750c5afcc68f2832bb42d98a1cbce6735.tar.gz |
rename llmr => mbgl
Diffstat (limited to 'include/mbgl')
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 ↦ + 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 ↦ + + // 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 |