diff options
-rw-r--r-- | include/llmr/map/tile.hpp | 12 | ||||
-rw-r--r-- | include/llmr/platform/platform.hpp | 8 | ||||
-rw-r--r-- | macosx/main.mm | 78 | ||||
-rw-r--r-- | src/map/map.cpp | 14 | ||||
-rw-r--r-- | src/map/tile.cpp | 44 | ||||
-rw-r--r-- | src/map/vector_tile.cpp | 1 |
6 files changed, 53 insertions, 104 deletions
diff --git a/include/llmr/map/tile.hpp b/include/llmr/map/tile.hpp index bd5d667f82..24fdebec42 100644 --- a/include/llmr/map/tile.hpp +++ b/include/llmr/map/tile.hpp @@ -14,6 +14,7 @@ #include <llmr/util/vec.hpp> #include <string> #include <map> +#include <memory> namespace llmr { @@ -25,7 +26,7 @@ class BucketDescription; -class Tile { +class Tile : public std::enable_shared_from_this<Tile> { public: struct exception : std::exception {}; struct geometry_too_long_exception : exception {}; @@ -52,8 +53,10 @@ public: Tile& operator=(const Tile&) = delete; Tile& operator=(const Tile && ) = delete; + // Start loading the tile. + void request(); + // Other functions - void setData(uint8_t *data, uint32_t bytes); bool parse(); void parseStyleLayers(const std::vector<LayerDescription>& layers); std::shared_ptr<Bucket> createBucket(const BucketDescription& bucket_desc); @@ -83,11 +86,10 @@ public: private: // Source data - uint8_t *data; - uint32_t bytes; + std::vector<char> data; VectorTile tile; - std::mutex mtx; + // std::mutex mtx; const Style& style; }; diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp index ae34dc7ba9..2b46d0fcf6 100644 --- a/include/llmr/platform/platform.hpp +++ b/include/llmr/platform/platform.hpp @@ -15,12 +15,6 @@ namespace platform { // controlling application. void restart(void *obj); -// Download a tile. Obtain the z/x/y from the tile shared_ptr. -// You should perform the download and parsing of the tile in a separate thread! -// Then, call map.tileLoaded(tile); or map.tileFailed(tile); in the main thread. -void request(void *obj, std::shared_ptr<Tile> tile); - - struct Response { Response(int16_t code, const char *body, size_t length) : code(code), @@ -33,6 +27,8 @@ struct Response { void request_http(std::string url, std::function<void(const Response&)> func); +void async(std::function<void()> fn, std::function<void()> cb); + // Returns a relative timestamp in seconds. This value must be monotonic. double time(); diff --git a/macosx/main.mm b/macosx/main.mm index 1bcadad725..d342734ea6 100644 --- a/macosx/main.mm +++ b/macosx/main.mm @@ -3,9 +3,10 @@ #import <Foundation/Foundation.h> #import <AppKit/AppKit.h> #include <llmr/platform/platform.hpp> -#include <llmr/map/tile.hpp> #include "settings.hpp" +#include <thread> + class MapView { public: MapView() : @@ -202,7 +203,6 @@ public: llmr::Map map; }; -NSOperationQueue *queue = NULL; MapView *view; namespace llmr { @@ -212,86 +212,36 @@ void restart(void *) { view->dirty = true; } -void request(void *, Tile::Ptr tile) { - assert((bool)tile); - - // NSString *urlTemplate = @"http://api.tiles.mapbox.com/v3/mapbox.mapbox-streets-v4/%d/%d/%d.vector.pbf"; - NSString *urlTemplate = @"http://localhost:3333/gl/tiles/plain/%d-%d-%d.vector.pbf"; - NSString *urlString = [NSString - stringWithFormat:urlTemplate, - tile->id.z, - tile->id.x, - tile->id.y]; - NSURL *url = [NSURL URLWithString:urlString]; - // NSLog(@"Requesting %@", urlString); - - NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url]; - - if (!queue) { - queue = [[NSOperationQueue alloc] init]; - } - - [NSURLConnection - sendAsynchronousRequest:urlRequest - queue:queue - completionHandler: ^ (NSURLResponse * response, - NSData * data, - NSError * error) { - if (error == nil) { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; - int code = [httpResponse statusCode]; - - if (code == 200) { - tile->setData((uint8_t *)[data bytes], [data length]); - if (tile->parse()) { - dispatch_async(dispatch_get_main_queue(), ^ { - view->map.tileLoaded(tile); - }); - return; - } - // fall through to report tileFailed - } - // fall through to report tileFailed - } - // fall through to report tileFailed - - dispatch_async(dispatch_get_main_queue(), ^ { - view->map.tileFailed(tile); +void async(std::function<void()> fn, std::function<void()> cb) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ + fn(); + dispatch_async(dispatch_get_main_queue(), ^(void){ + cb(); }); - }]; + }); } - void request_http(std::string url, std::function<void(const Response&)> func) { NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithUTF8String:url.c_str()]]]; - if (!queue) { - queue = [[NSOperationQueue alloc] init]; - } - [NSURLConnection sendAsynchronousRequest:urlRequest - queue:queue + queue:[NSOperationQueue mainQueue] completionHandler: ^ (NSURLResponse* response, NSData* data, NSError* error) { if (error == nil) { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; dispatch_async(dispatch_get_main_queue(), ^ { - func({ - [httpResponse statusCode], - (const char *)[data bytes], - [data length] - }); + int code = [httpResponse statusCode]; + const char *body = (const char *)[data bytes]; + size_t length = [data length]; + func({ code, body, length }); }); } else { dispatch_async(dispatch_get_main_queue(), ^ { - func({ - -1, - 0, - 0 - }); + func({ -1, 0, 0 }); }); } }]; diff --git a/src/map/map.cpp b/src/map/map.cpp index bda787b6ae..39a07edd97 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -132,7 +132,6 @@ Tile::Ptr Map::addTile(const Tile::ID& id) { // std::cerr << "init " << id.z << "/" << id.x << "/" << id.y << std::endl; // std::cerr << "add " << tile->toString() << std::endl; tiles.push_front(tile); - historic_tiles.push_front(tile); } return tile; @@ -252,8 +251,7 @@ void Map::updateTiles() { if (tile->state == Tile::initial) { // If the tile is new, we have to make sure to load it. - tile->state = Tile::loading; - platform::request(this, tile); + tile->request(); } } @@ -274,16 +272,6 @@ void Map::updateTiles() { tiles.sort([](const Tile::Ptr& a, const Tile::Ptr& b) { return a->id.z > b->id.z; }); - - - // Remove all tiles that are only in the list of historic tiles. We do this - // to make sure that the destructor (triggered by shared_ptr count falling - // to 0) is triggered from the main thread. - // TODO: Find a better solution by forcing the destructor to run in the - // main thread, e.g. with a custom deleter on shared_ptr construction? - historic_tiles.remove_if([](const Tile::Ptr& tile) { - return tile.unique(); - }); } bool Map::render() { diff --git a/src/map/tile.cpp b/src/map/tile.cpp index 01235c9d1d..ff0279ad8b 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -11,6 +11,9 @@ #include <llmr/renderer/fill_bucket.hpp> #include <llmr/renderer/line_bucket.hpp> #include <llmr/style/style.hpp> +#include <llmr/platform/platform.hpp> +#include <llmr/util/string.hpp> + #include <cmath> using namespace llmr; @@ -47,8 +50,6 @@ Tile::Tile(ID id, const Style& style) debugFontBuffer(std::make_shared<DebugFontBuffer>()), fillBuffer(std::make_shared<FillBuffer>()), lineBuffer(std::make_shared<LineBuffer>()), - data(0), - bytes(0), style(style) { // Initialize tile debug coordinates @@ -58,24 +59,35 @@ Tile::Tile(ID id, const Style& style) } Tile::~Tile() { - std::lock_guard<std::mutex> lock(mtx); - - // fprintf(stderr, "[%p] deleting tile %d/%d/%d\n", this, id.z, id.x, id.y); - if (this->data) { - free(this->data); - this->data = NULL; - } } const std::string Tile::toString() const { return util::sprintf("[tile %d/%d/%d]", id.z, id.x, id.y); } - -void Tile::setData(uint8_t *data, uint32_t bytes) { - this->data = (uint8_t *)malloc(bytes); - this->bytes = bytes; - memcpy(this->data, data, bytes); +void Tile::request() { + state = Tile::loading; + + // Create http request + std::string url = util::sprintf("http://localhost:3333/gl/tiles/plain/%d-%d-%d.vector.pbf", + id.z, id.x, id.y); + + // Note: Somehow this feels slower than the change to request_http() + std::shared_ptr<Tile> tile = shared_from_this(); + platform::request_http(url, [=](const platform::Response& res) { + if (res.code == 200) { + tile->data.assign(res.body, res.body + res.length); + + platform::async([tile]() { + tile->parse(); + }, []() { + // TODO: Make sure this gets passed the correct map ID/pointer. + platform::restart(NULL); + }); + } else { + fprintf(stderr, "tile loading failed\n"); + } + }); } void Tile::cancel() { @@ -88,14 +100,14 @@ void Tile::cancel() { } bool Tile::parse() { - std::lock_guard<std::mutex> lock(mtx); + // std::lock_guard<std::mutex> lock(mtx); if (state == obsolete) { return false; } try { - tile = VectorTile(pbf(data, bytes)); + tile = VectorTile(pbf((const uint8_t *)data.data(), data.size())); parseStyleLayers(style.layers); } catch (const std::exception& ex) { fprintf(stderr, "[%p] exception [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what()); diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp index b6011bd109..777dd299eb 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -6,6 +6,7 @@ using namespace llmr; VectorTile::VectorTile() {} + VectorTile::VectorTile(pbf tile) { while (tile.next()) { if (tile.tag == 3) { // layer |