rename Tile to TileData
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#define LLMR_MAP_MAP
|
||||
|
||||
#include <llmr/map/tile.hpp>
|
||||
#include <llmr/map/tile_data.hpp>
|
||||
#include <llmr/map/transform.hpp>
|
||||
#include <llmr/style/style.hpp>
|
||||
#include <llmr/renderer/painter.hpp>
|
||||
@@ -64,8 +65,8 @@ 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);
|
||||
bool updateTiles();
|
||||
std::shared_ptr<Tile> addTile(const Tile::ID& id);
|
||||
std::shared_ptr<Tile> hasTile(const Tile::ID& id);
|
||||
std::shared_ptr<TileData> addTile(const Tile::ID& id);
|
||||
std::shared_ptr<TileData> hasTile(const Tile::ID& id);
|
||||
|
||||
|
||||
void update();
|
||||
@@ -81,8 +82,8 @@ private:
|
||||
|
||||
float pixel_ratio;
|
||||
|
||||
std::forward_list<std::shared_ptr<Tile>> tiles;
|
||||
std::forward_list<std::shared_ptr<Tile>> historic_tiles;
|
||||
std::forward_list<std::shared_ptr<TileData>> tiles;
|
||||
std::forward_list<std::shared_ptr<TileData>> historic_tiles;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -2,104 +2,19 @@
|
||||
#define LLMR_MAP_TILE
|
||||
|
||||
#include <llmr/util/vec.hpp>
|
||||
#include <llmr/util/mat4.hpp>
|
||||
#include <llmr/util/noncopyable.hpp>
|
||||
#include <llmr/geometry/debug_font_buffer.hpp>
|
||||
#include <llmr/geometry/vao.hpp>
|
||||
#include <llmr/platform/platform.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <forward_list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
class Style;
|
||||
class Bucket;
|
||||
class LayerDescription;
|
||||
class BucketDescription;
|
||||
class VectorTile;
|
||||
class VectorTileLayer;
|
||||
class FillVertexBuffer;
|
||||
class LineVertexBuffer;
|
||||
class PointVertexBuffer;
|
||||
class TriangleElementsBuffer;
|
||||
class LineElementsBuffer;
|
||||
class PointElementsBuffer;
|
||||
class PlainShader;
|
||||
|
||||
class Tile : public std::enable_shared_from_this<Tile>,
|
||||
private util::noncopyable {
|
||||
class Tile {
|
||||
public:
|
||||
struct exception : std::exception {};
|
||||
struct geometry_too_long_exception : exception {};
|
||||
|
||||
public:
|
||||
typedef std::shared_ptr<Tile> Ptr;
|
||||
|
||||
typedef vec3<int32_t> ID;
|
||||
|
||||
enum state {
|
||||
initial,
|
||||
loading,
|
||||
loaded,
|
||||
parsed,
|
||||
obsolete
|
||||
};
|
||||
|
||||
public:
|
||||
Tile(ID id, const Style& style);
|
||||
~Tile();
|
||||
|
||||
// Start loading the tile.
|
||||
void request();
|
||||
|
||||
// Other functions
|
||||
bool parse();
|
||||
void parseStyleLayers(const VectorTile& tile, const std::vector<LayerDescription>& layers);
|
||||
std::shared_ptr<Bucket> createBucket(const VectorTile& tile, const BucketDescription& bucket_desc);
|
||||
std::shared_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc);
|
||||
std::shared_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc);
|
||||
std::shared_ptr<Bucket> createPointBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc);
|
||||
|
||||
void cancel();
|
||||
|
||||
const std::string toString() const;
|
||||
|
||||
static ID parent(const ID& id, int32_t z);
|
||||
static std::forward_list<ID> children(const ID& id, int32_t z);
|
||||
|
||||
public:
|
||||
const ID id;
|
||||
uint8_t clip_id;
|
||||
std::atomic<state> state;
|
||||
|
||||
// Holds the actual geometries in this tile.
|
||||
DebugFontBuffer debugFontBuffer;
|
||||
VertexArrayObject debugFontArray;
|
||||
|
||||
std::shared_ptr<FillVertexBuffer> fillVertexBuffer;
|
||||
std::shared_ptr<LineVertexBuffer> lineVertexBuffer;
|
||||
std::shared_ptr<PointVertexBuffer> pointVertexBuffer;
|
||||
|
||||
std::shared_ptr<TriangleElementsBuffer> triangleElementsBuffer;
|
||||
std::shared_ptr<LineElementsBuffer> lineElementsBuffer;
|
||||
std::shared_ptr<PointElementsBuffer> pointElementsBuffer;
|
||||
|
||||
// Holds the buckets of this tile.
|
||||
// They contain the location offsets in the buffers stored above
|
||||
std::map<std::string, std::shared_ptr<Bucket>> buckets;
|
||||
|
||||
mat4 matrix;
|
||||
private:
|
||||
// Source data
|
||||
std::string data;
|
||||
const Style& style;
|
||||
platform::Request *req = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
103
include/llmr/map/tile_data.hpp
Normal file
103
include/llmr/map/tile_data.hpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#ifndef LLMR_MAP_TILE_DATA
|
||||
#define LLMR_MAP_TILE_DATA
|
||||
|
||||
#include <llmr/map/tile.hpp>
|
||||
#include <llmr/util/vec.hpp>
|
||||
#include <llmr/util/mat4.hpp>
|
||||
#include <llmr/util/noncopyable.hpp>
|
||||
#include <llmr/geometry/debug_font_buffer.hpp>
|
||||
#include <llmr/geometry/vao.hpp>
|
||||
#include <llmr/platform/platform.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <forward_list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
class Style;
|
||||
class Bucket;
|
||||
class LayerDescription;
|
||||
class BucketDescription;
|
||||
class VectorTile;
|
||||
class VectorTileLayer;
|
||||
class FillVertexBuffer;
|
||||
class LineVertexBuffer;
|
||||
class PointVertexBuffer;
|
||||
class TriangleElementsBuffer;
|
||||
class LineElementsBuffer;
|
||||
class PointElementsBuffer;
|
||||
class PlainShader;
|
||||
|
||||
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 state {
|
||||
initial,
|
||||
loading,
|
||||
loaded,
|
||||
parsed,
|
||||
obsolete
|
||||
};
|
||||
|
||||
public:
|
||||
TileData(Tile::ID id, const Style& style);
|
||||
~TileData();
|
||||
|
||||
// Start loading the tile.
|
||||
void request();
|
||||
|
||||
// Other functions
|
||||
bool parse();
|
||||
void parseStyleLayers(const VectorTile& tile, const std::vector<LayerDescription>& layers);
|
||||
std::shared_ptr<Bucket> createBucket(const VectorTile& tile, const BucketDescription& bucket_desc);
|
||||
std::shared_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc);
|
||||
std::shared_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc);
|
||||
std::shared_ptr<Bucket> createPointBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc);
|
||||
|
||||
void cancel();
|
||||
|
||||
const std::string toString() const;
|
||||
|
||||
public:
|
||||
const Tile::ID id;
|
||||
uint8_t clip_id;
|
||||
std::atomic<state> state;
|
||||
|
||||
// Holds the actual geometries in this tile.
|
||||
DebugFontBuffer debugFontBuffer;
|
||||
VertexArrayObject debugFontArray;
|
||||
|
||||
std::shared_ptr<FillVertexBuffer> fillVertexBuffer;
|
||||
std::shared_ptr<LineVertexBuffer> lineVertexBuffer;
|
||||
std::shared_ptr<PointVertexBuffer> pointVertexBuffer;
|
||||
|
||||
std::shared_ptr<TriangleElementsBuffer> triangleElementsBuffer;
|
||||
std::shared_ptr<LineElementsBuffer> lineElementsBuffer;
|
||||
std::shared_ptr<PointElementsBuffer> pointElementsBuffer;
|
||||
|
||||
// Holds the buckets of this tile.
|
||||
// They contain the location offsets in the buffers stored above
|
||||
std::map<std::string, std::shared_ptr<Bucket>> buckets;
|
||||
|
||||
mat4 matrix;
|
||||
private:
|
||||
// Source data
|
||||
std::string data;
|
||||
const Style& style;
|
||||
platform::Request *req = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef LLMR_RENDERER_PAINTER
|
||||
#define LLMR_RENDERER_PAINTER
|
||||
|
||||
#include <llmr/map/tile.hpp>
|
||||
#include <llmr/map/tile_data.hpp>
|
||||
#include <llmr/geometry/vao.hpp>
|
||||
#include <llmr/geometry/vertex_buffer.hpp>
|
||||
#include <llmr/util/mat4.hpp>
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
void setup();
|
||||
void clear();
|
||||
void changeMatrix();
|
||||
void render(const std::shared_ptr<Tile>& tile);
|
||||
void render(const std::shared_ptr<TileData>& tile);
|
||||
void renderMatte();
|
||||
void renderBackground();
|
||||
void renderFill(FillBucket& bucket, const std::string& layer_name, const Tile::ID& id);
|
||||
@@ -45,8 +45,8 @@ public:
|
||||
void finishClippingMask();
|
||||
private:
|
||||
void setupShaders();
|
||||
void renderLayers(const std::shared_ptr<Tile>& tile, const std::vector<LayerDescription>& layers);
|
||||
void renderDebug(const std::shared_ptr<Tile>& tile);
|
||||
void renderLayers(const std::shared_ptr<TileData>& tile, const std::vector<LayerDescription>& layers);
|
||||
void renderDebug(const std::shared_ptr<TileData>& tile);
|
||||
|
||||
void useProgram(uint32_t program);
|
||||
void lineWidth(float lineWidth);
|
||||
|
||||
@@ -238,22 +238,22 @@ void Map::update() {
|
||||
}
|
||||
|
||||
|
||||
Tile::Ptr Map::hasTile(const Tile::ID& id) {
|
||||
for (Tile::Ptr& tile : tiles) {
|
||||
TileData::Ptr Map::hasTile(const Tile::ID& id) {
|
||||
for (TileData::Ptr& tile : tiles) {
|
||||
if (tile->id == id) {
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
|
||||
return Tile::Ptr();
|
||||
return TileData::Ptr();
|
||||
}
|
||||
|
||||
Tile::Ptr Map::addTile(const Tile::ID& id) {
|
||||
Tile::Ptr tile = hasTile(id);
|
||||
TileData::Ptr Map::addTile(const Tile::ID& id) {
|
||||
TileData::Ptr tile = hasTile(id);
|
||||
|
||||
if (!tile.get()) {
|
||||
// We couldn't find the tile in the list. Create a new one.
|
||||
tile = std::make_shared<Tile>(id, style);
|
||||
tile = std::make_shared<TileData>(id, style);
|
||||
assert(tile);
|
||||
// std::cerr << "init " << id.z << "/" << id.x << "/" << id.y << std::endl;
|
||||
// std::cerr << "add " << tile->toString() << std::endl;
|
||||
@@ -278,8 +278,8 @@ bool Map::findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std::f
|
||||
|
||||
auto ids = Tile::children(id, z + 1);
|
||||
for (const Tile::ID& child_id : ids) {
|
||||
const Tile::Ptr& tile = hasTile(child_id);
|
||||
if (tile && tile->state == Tile::parsed) {
|
||||
const TileData::Ptr& tile = hasTile(child_id);
|
||||
if (tile && tile->state == TileData::parsed) {
|
||||
assert(tile);
|
||||
retain.emplace_front(tile->id);
|
||||
} else {
|
||||
@@ -305,8 +305,8 @@ bool Map::findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std::f
|
||||
bool Map::findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std::forward_list<Tile::ID>& retain) {
|
||||
for (int32_t z = id.z - 1; z >= minCoveringZoom; --z) {
|
||||
const Tile::ID parent_id = Tile::parent(id, z);
|
||||
const Tile::Ptr tile = hasTile(parent_id);
|
||||
if (tile && tile->state == Tile::parsed) {
|
||||
const TileData::Ptr tile = hasTile(parent_id);
|
||||
if (tile && tile->state == TileData::parsed) {
|
||||
assert(tile);
|
||||
retain.emplace_front(tile->id);
|
||||
return true;
|
||||
@@ -344,10 +344,10 @@ bool Map::updateTiles() {
|
||||
|
||||
// Add existing child/parent tiles if the actual tile is not yet loaded
|
||||
for (const Tile::ID& id : required) {
|
||||
Tile::Ptr tile = addTile(id);
|
||||
TileData::Ptr tile = addTile(id);
|
||||
assert(tile);
|
||||
|
||||
if (tile->state != Tile::parsed) {
|
||||
if (tile->state != TileData::parsed) {
|
||||
// The tile we require is not yet loaded. Try to find a parent or
|
||||
// child tile that we already have.
|
||||
|
||||
@@ -362,7 +362,7 @@ bool Map::updateTiles() {
|
||||
}
|
||||
}
|
||||
|
||||
if (tile->state == Tile::initial) {
|
||||
if (tile->state == TileData::initial) {
|
||||
// If the tile is new, we have to make sure to load it.
|
||||
tile->request();
|
||||
changed = true;
|
||||
@@ -371,7 +371,7 @@ bool Map::updateTiles() {
|
||||
|
||||
// Remove tiles that we definitely don't need, i.e. tiles that are not on
|
||||
// the required list.
|
||||
tiles.remove_if([&retain, &changed](const Tile::Ptr& tile) {
|
||||
tiles.remove_if([&retain, &changed](const TileData::Ptr& tile) {
|
||||
assert(tile);
|
||||
bool obsolete = std::find(retain.begin(), retain.end(), tile->id) == retain.end();
|
||||
if (obsolete) {
|
||||
@@ -384,7 +384,7 @@ bool Map::updateTiles() {
|
||||
// Sort tiles by zoom level, front to back.
|
||||
// We're painting front-to-back, so we want to draw more detailed tiles first
|
||||
// before filling in other parts with lower zoom levels.
|
||||
tiles.sort([](const Tile::Ptr& a, const Tile::Ptr& b) {
|
||||
tiles.sort([](const TileData::Ptr& a, const TileData::Ptr& b) {
|
||||
return a->id.z > b->id.z;
|
||||
});
|
||||
|
||||
@@ -406,9 +406,9 @@ bool Map::render() {
|
||||
// the stencil buffer.
|
||||
uint8_t i = 1;
|
||||
painter.prepareClippingMask();
|
||||
for (Tile::Ptr& tile : tiles) {
|
||||
for (TileData::Ptr& tile : tiles) {
|
||||
assert(tile);
|
||||
if (tile->state == Tile::parsed) {
|
||||
if (tile->state == TileData::parsed) {
|
||||
// The position matrix.
|
||||
transform.matrixFor(tile->matrix, tile->id);
|
||||
matrix::multiply(tile->matrix, painter.projMatrix, tile->matrix);
|
||||
@@ -418,8 +418,8 @@ bool Map::render() {
|
||||
}
|
||||
painter.finishClippingMask();
|
||||
|
||||
for (Tile::Ptr& tile : tiles) {
|
||||
if (tile->state == Tile::parsed) {
|
||||
for (TileData::Ptr& tile : tiles) {
|
||||
if (tile->state == TileData::parsed) {
|
||||
painter.render(tile);
|
||||
}
|
||||
}
|
||||
|
||||
209
src/map/tile.cpp
209
src/map/tile.cpp
@@ -1,18 +1,6 @@
|
||||
#include <llmr/map/tile.hpp>
|
||||
|
||||
#include <llmr/style/style.hpp>
|
||||
#include <llmr/map/vector_tile.hpp>
|
||||
#include <llmr/geometry/fill_buffer.hpp>
|
||||
#include <llmr/geometry/line_buffer.hpp>
|
||||
#include <llmr/geometry/point_buffer.hpp>
|
||||
#include <llmr/geometry/elements_buffer.hpp>
|
||||
#include <llmr/renderer/fill_bucket.hpp>
|
||||
#include <llmr/renderer/line_bucket.hpp>
|
||||
#include <llmr/renderer/point_bucket.hpp>
|
||||
#include <llmr/util/pbf.hpp>
|
||||
#include <llmr/util/string.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
|
||||
using namespace llmr;
|
||||
|
||||
@@ -41,198 +29,3 @@ std::forward_list<Tile::ID> Tile::children(const ID& id, int32_t z) {
|
||||
return children;
|
||||
}
|
||||
|
||||
|
||||
Tile::Tile(ID id, const Style& style)
|
||||
: id(id),
|
||||
state(initial),
|
||||
fillVertexBuffer(std::make_shared<FillVertexBuffer>()),
|
||||
lineVertexBuffer(std::make_shared<LineVertexBuffer>()),
|
||||
pointVertexBuffer(std::make_shared<PointVertexBuffer>()),
|
||||
triangleElementsBuffer(std::make_shared<TriangleElementsBuffer>()),
|
||||
lineElementsBuffer(std::make_shared<LineElementsBuffer>()),
|
||||
pointElementsBuffer(std::make_shared<PointElementsBuffer>()),
|
||||
style(style) {
|
||||
|
||||
// Initialize tile debug coordinates
|
||||
char coord[32];
|
||||
snprintf(coord, sizeof(coord), "%d/%d/%d", id.z, id.x, id.y);
|
||||
debugFontBuffer.addText(coord, 50, 200, 5);
|
||||
}
|
||||
|
||||
Tile::~Tile() {
|
||||
}
|
||||
|
||||
const std::string Tile::toString() const {
|
||||
return util::sprintf("[tile %d/%d/%d]", id.z, id.x, id.y);
|
||||
}
|
||||
|
||||
void Tile::request() {
|
||||
state = Tile::loading;
|
||||
|
||||
// Create http request
|
||||
std::string url = util::sprintf(kTileURL,
|
||||
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 *request = platform::request_http(url, [=](platform::Response& res) {
|
||||
if (res.code == 200 && tile->state != obsolete) {
|
||||
tile->state = Tile::loaded;
|
||||
tile->data.swap(res.body);
|
||||
tile->parse();
|
||||
} else if (tile->state != obsolete) {
|
||||
fprintf(stderr, "tile loading failed\n");
|
||||
}
|
||||
}, []() {
|
||||
platform::restart();
|
||||
});
|
||||
req = request;
|
||||
}
|
||||
|
||||
void Tile::cancel() {
|
||||
// TODO: thread safety
|
||||
if (state != obsolete) {
|
||||
state = obsolete;
|
||||
platform::cancel_request_http(req);
|
||||
} else {
|
||||
assert((!"logic error? multiple cancelleations"));
|
||||
}
|
||||
}
|
||||
|
||||
bool Tile::parse() {
|
||||
// std::lock_guard<std::mutex> lock(mtx);
|
||||
|
||||
if (state != loaded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
VectorTile tile(pbf((const uint8_t *)data.data(), data.size()));
|
||||
parseStyleLayers(tile, 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());
|
||||
cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state == obsolete) {
|
||||
return false;
|
||||
} else {
|
||||
state = parsed;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Tile::parseStyleLayers(const VectorTile& tile, const std::vector<LayerDescription>& layers) {
|
||||
for (const LayerDescription& layer_desc : layers) {
|
||||
if (layer_desc.child_layer.size()) {
|
||||
// This is a layer group.
|
||||
// TODO: create framebuffer
|
||||
parseStyleLayers(tile, layer_desc.child_layer);
|
||||
// TODO: render framebuffer on previous framebuffer
|
||||
} else {
|
||||
// This is a singular layer. Check if this bucket already exists. If not,
|
||||
// parse this bucket.
|
||||
auto bucket_it = buckets.find(layer_desc.bucket_name);
|
||||
if (bucket_it == buckets.end()) {
|
||||
auto bucket_it = style.buckets.find(layer_desc.bucket_name);
|
||||
if (bucket_it != style.buckets.end()) {
|
||||
// Only create the new bucket if we have an actual specification
|
||||
// for it.
|
||||
std::shared_ptr<Bucket> bucket = createBucket(tile, bucket_it->second);
|
||||
if (bucket) {
|
||||
// Bucket creation might fail because the data tile may not
|
||||
// contain any data that falls into this bucket.
|
||||
buckets[layer_desc.bucket_name] = bucket;
|
||||
}
|
||||
} else {
|
||||
// There is no proper specification for this bucket, even though
|
||||
// it is referenced in the stylesheet.
|
||||
fprintf(stderr, "Stylesheet specifies bucket %s, but it is not defined\n", layer_desc.bucket_name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Bucket> Tile::createBucket(const VectorTile& tile, const BucketDescription& bucket_desc) {
|
||||
auto layer_it = tile.layers.find(bucket_desc.source_layer);
|
||||
if (layer_it != tile.layers.end()) {
|
||||
const VectorTileLayer& layer = layer_it->second;
|
||||
if (bucket_desc.type == BucketType::Fill) {
|
||||
return createFillBucket(layer, bucket_desc);
|
||||
} else if (bucket_desc.type == BucketType::Line) {
|
||||
return createLineBucket(layer, bucket_desc);
|
||||
} else if (bucket_desc.type == BucketType::Point) {
|
||||
return createPointBucket(layer, bucket_desc);
|
||||
} else {
|
||||
// TODO: create other bucket types.
|
||||
}
|
||||
} else {
|
||||
// The layer specified in the bucket does not exist. Do nothing.
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Bucket> Tile::createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) {
|
||||
std::shared_ptr<FillBucket> bucket = std::make_shared<FillBucket>(fillVertexBuffer, triangleElementsBuffer, lineElementsBuffer, bucket_desc);
|
||||
|
||||
// auto init_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
FilteredVectorTileLayer filtered_layer(layer, bucket_desc);
|
||||
for (pbf feature : filtered_layer) {
|
||||
while (feature.next(4)) { // geometry
|
||||
pbf geometry_pbf = feature.message();
|
||||
if (geometry_pbf) {
|
||||
bucket->addGeometry(geometry_pbf);
|
||||
bucket->tessellate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// auto init_end = std::chrono::high_resolution_clock::now();
|
||||
// auto init = (double)std::chrono::duration_cast<std::chrono::microseconds>(init_end - init_start).count() / 1000.0;
|
||||
|
||||
// auto tess_start = std::chrono::high_resolution_clock::now();
|
||||
// auto tess_end = std::chrono::high_resolution_clock::now();
|
||||
// auto tess = (double)std::chrono::duration_cast<std::chrono::microseconds>(tess_end - tess_start).count() / 1000.0;
|
||||
|
||||
|
||||
// fprintf(stderr, "%s/%s init: %f tess: %f\n", bucket_desc.source_layer.c_str(), bucket_desc.source_field.c_str(), init, tess);
|
||||
|
||||
return bucket;
|
||||
}
|
||||
|
||||
std::shared_ptr<Bucket> Tile::createLineBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) {
|
||||
std::shared_ptr<LineBucket> bucket = std::make_shared<LineBucket>(lineVertexBuffer, triangleElementsBuffer, pointElementsBuffer, bucket_desc);
|
||||
|
||||
FilteredVectorTileLayer filtered_layer(layer, bucket_desc);
|
||||
for (pbf feature : filtered_layer) {
|
||||
while (feature.next(4)) { // geometry
|
||||
pbf geometry_pbf = feature.message();
|
||||
if (geometry_pbf) {
|
||||
bucket->addGeometry(geometry_pbf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bucket;
|
||||
}
|
||||
|
||||
std::shared_ptr<Bucket> Tile::createPointBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) {
|
||||
std::shared_ptr<PointBucket> bucket = std::make_shared<PointBucket>(pointVertexBuffer, bucket_desc);
|
||||
|
||||
FilteredVectorTileLayer filtered_layer(layer, bucket_desc);
|
||||
for (pbf feature : filtered_layer) {
|
||||
while (feature.next(4)) { // geometry
|
||||
pbf geometry_pbf = feature.message();
|
||||
if (geometry_pbf) {
|
||||
bucket->addGeometry(geometry_pbf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bucket;
|
||||
}
|
||||
|
||||
215
src/map/tile_data.cpp
Normal file
215
src/map/tile_data.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
#include <llmr/map/tile_data.hpp>
|
||||
|
||||
#include <llmr/style/style.hpp>
|
||||
#include <llmr/map/vector_tile.hpp>
|
||||
#include <llmr/geometry/fill_buffer.hpp>
|
||||
#include <llmr/geometry/line_buffer.hpp>
|
||||
#include <llmr/geometry/point_buffer.hpp>
|
||||
#include <llmr/geometry/elements_buffer.hpp>
|
||||
#include <llmr/renderer/fill_bucket.hpp>
|
||||
#include <llmr/renderer/line_bucket.hpp>
|
||||
#include <llmr/renderer/point_bucket.hpp>
|
||||
#include <llmr/util/pbf.hpp>
|
||||
#include <llmr/util/string.hpp>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
using namespace llmr;
|
||||
|
||||
TileData::TileData(Tile::ID id, const Style& style)
|
||||
: id(id),
|
||||
state(initial),
|
||||
fillVertexBuffer(std::make_shared<FillVertexBuffer>()),
|
||||
lineVertexBuffer(std::make_shared<LineVertexBuffer>()),
|
||||
pointVertexBuffer(std::make_shared<PointVertexBuffer>()),
|
||||
triangleElementsBuffer(std::make_shared<TriangleElementsBuffer>()),
|
||||
lineElementsBuffer(std::make_shared<LineElementsBuffer>()),
|
||||
pointElementsBuffer(std::make_shared<PointElementsBuffer>()),
|
||||
style(style) {
|
||||
|
||||
// Initialize tile debug coordinates
|
||||
char coord[32];
|
||||
snprintf(coord, sizeof(coord), "%d/%d/%d", id.z, id.x, id.y);
|
||||
debugFontBuffer.addText(coord, 50, 200, 5);
|
||||
}
|
||||
|
||||
TileData::~TileData() {
|
||||
}
|
||||
|
||||
const std::string TileData::toString() const {
|
||||
return util::sprintf("[tile %d/%d/%d]", id.z, id.x, id.y);
|
||||
}
|
||||
|
||||
void TileData::request() {
|
||||
state = loading;
|
||||
|
||||
// Create http request
|
||||
std::string url = util::sprintf(kTileURL,
|
||||
id.z, id.x, id.y);
|
||||
|
||||
// Note: Somehow this feels slower than the change to request_http()
|
||||
std::shared_ptr<TileData> tile = shared_from_this();
|
||||
platform::Request *request = platform::request_http(url, [=](platform::Response& res) {
|
||||
if (res.code == 200 && tile->state != obsolete) {
|
||||
tile->state = loaded;
|
||||
tile->data.swap(res.body);
|
||||
tile->parse();
|
||||
} else if (tile->state != obsolete) {
|
||||
fprintf(stderr, "tile loading failed\n");
|
||||
}
|
||||
}, []() {
|
||||
platform::restart();
|
||||
});
|
||||
req = request;
|
||||
}
|
||||
|
||||
void TileData::cancel() {
|
||||
if (state != obsolete) {
|
||||
state = obsolete;
|
||||
platform::cancel_request_http(req);
|
||||
} else {
|
||||
assert((!"logic error? multiple cancelleations"));
|
||||
}
|
||||
}
|
||||
|
||||
bool TileData::parse() {
|
||||
if (state != loaded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
double parse_time_start = platform::time();
|
||||
VectorTile tile(pbf((const uint8_t *)data.data(), data.size()));
|
||||
parseStyleLayers(tile, style.layers);
|
||||
double parse_time = (platform::time() - parse_time_start) * 1000.0;
|
||||
if (state == obsolete) {
|
||||
fprintf(stderr, "[%p] parsing [%d/%d/%d] cancelled after %8.3fms\n", this, id.z, id.x, id.y, parse_time);
|
||||
} else {
|
||||
fprintf(stderr, "[%p] parsing [%d/%d/%d] took %8.3fms\n", this, id.z, id.x, id.y, parse_time);
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
fprintf(stderr, "[%p] exception [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, ex.what());
|
||||
cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state == obsolete) {
|
||||
return false;
|
||||
} else {
|
||||
state = parsed;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TileData::parseStyleLayers(const VectorTile& tile, const std::vector<LayerDescription>& layers) {
|
||||
for (const LayerDescription& layer_desc : layers) {
|
||||
// Cancel early when parsing.
|
||||
if (state == obsolete) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (layer_desc.child_layer.size()) {
|
||||
// This is a layer group.
|
||||
// TODO: create framebuffer
|
||||
parseStyleLayers(tile, layer_desc.child_layer);
|
||||
// TODO: render framebuffer on previous framebuffer
|
||||
} else {
|
||||
// This is a singular layer. Check if this bucket already exists. If not,
|
||||
// parse this bucket.
|
||||
auto bucket_it = buckets.find(layer_desc.bucket_name);
|
||||
if (bucket_it == buckets.end()) {
|
||||
auto bucket_it = style.buckets.find(layer_desc.bucket_name);
|
||||
if (bucket_it != style.buckets.end()) {
|
||||
// Only create the new bucket if we have an actual specification
|
||||
// for it.
|
||||
std::shared_ptr<Bucket> bucket = createBucket(tile, bucket_it->second);
|
||||
if (bucket) {
|
||||
// Bucket creation might fail because the data tile may not
|
||||
// contain any data that falls into this bucket.
|
||||
buckets[layer_desc.bucket_name] = bucket;
|
||||
}
|
||||
} else {
|
||||
// There is no proper specification for this bucket, even though
|
||||
// it is referenced in the stylesheet.
|
||||
fprintf(stderr, "Stylesheet specifies bucket %s, but it is not defined\n", layer_desc.bucket_name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Bucket> TileData::createBucket(const VectorTile& tile, const BucketDescription& bucket_desc) {
|
||||
auto layer_it = tile.layers.find(bucket_desc.source_layer);
|
||||
if (layer_it != tile.layers.end()) {
|
||||
const VectorTileLayer& layer = layer_it->second;
|
||||
if (bucket_desc.type == BucketType::Fill) {
|
||||
return createFillBucket(layer, bucket_desc);
|
||||
} else if (bucket_desc.type == BucketType::Line) {
|
||||
return createLineBucket(layer, bucket_desc);
|
||||
} else if (bucket_desc.type == BucketType::Point) {
|
||||
return createPointBucket(layer, bucket_desc);
|
||||
} else {
|
||||
// TODO: create other bucket types.
|
||||
}
|
||||
} else {
|
||||
// The layer specified in the bucket does not exist. Do nothing.
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Bucket> TileData::createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) {
|
||||
std::shared_ptr<FillBucket> bucket = std::make_shared<FillBucket>(fillVertexBuffer, triangleElementsBuffer, lineElementsBuffer, bucket_desc);
|
||||
|
||||
FilteredVectorTileLayer filtered_layer(layer, bucket_desc);
|
||||
for (pbf feature : filtered_layer) {
|
||||
if (state == obsolete) return nullptr;
|
||||
|
||||
while (feature.next(4)) { // geometry
|
||||
pbf geometry_pbf = feature.message();
|
||||
if (geometry_pbf) {
|
||||
bucket->addGeometry(geometry_pbf);
|
||||
bucket->tessellate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bucket;
|
||||
}
|
||||
|
||||
std::shared_ptr<Bucket> TileData::createLineBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) {
|
||||
std::shared_ptr<LineBucket> bucket = std::make_shared<LineBucket>(lineVertexBuffer, triangleElementsBuffer, pointElementsBuffer, bucket_desc);
|
||||
|
||||
FilteredVectorTileLayer filtered_layer(layer, bucket_desc);
|
||||
for (pbf feature : filtered_layer) {
|
||||
if (state == obsolete) return nullptr;
|
||||
|
||||
while (feature.next(4)) { // geometry
|
||||
pbf geometry_pbf = feature.message();
|
||||
if (geometry_pbf) {
|
||||
bucket->addGeometry(geometry_pbf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bucket;
|
||||
}
|
||||
|
||||
std::shared_ptr<Bucket> TileData::createPointBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) {
|
||||
std::shared_ptr<PointBucket> bucket = std::make_shared<PointBucket>(pointVertexBuffer, bucket_desc);
|
||||
|
||||
FilteredVectorTileLayer filtered_layer(layer, bucket_desc);
|
||||
for (pbf feature : filtered_layer) {
|
||||
if (state == obsolete) return nullptr;
|
||||
|
||||
while (feature.next(4)) { // geometry
|
||||
pbf geometry_pbf = feature.message();
|
||||
if (geometry_pbf) {
|
||||
bucket->addGeometry(geometry_pbf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bucket;
|
||||
}
|
||||
@@ -130,8 +130,8 @@ void Painter::clear() {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void Painter::render(const Tile::Ptr& tile) {
|
||||
if (tile->state != Tile::parsed) {
|
||||
void Painter::render(const TileData::Ptr& tile) {
|
||||
if (tile->state != TileData::parsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ void Painter::render(const Tile::Ptr& tile) {
|
||||
renderBackground();
|
||||
}
|
||||
|
||||
void Painter::renderLayers(const std::shared_ptr<Tile>& tile, const std::vector<LayerDescription>& layers) {
|
||||
void Painter::renderLayers(const std::shared_ptr<TileData>& tile, const std::vector<LayerDescription>& layers) {
|
||||
// Render everything top-to-bottom by using reverse iterators
|
||||
typedef std::vector<LayerDescription>::const_reverse_iterator iterator;
|
||||
for (iterator it = layers.rbegin(), end = layers.rend(); it != end; ++it) {
|
||||
@@ -423,7 +423,7 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co
|
||||
bucket.drawPoints(*pointShader);
|
||||
}
|
||||
|
||||
void Painter::renderDebug(const Tile::Ptr& tile) {
|
||||
void Painter::renderDebug(const TileData::Ptr& tile) {
|
||||
// Disable depth test and don't count this towards the depth buffer,
|
||||
// but *don't* disable stencil test, as we want to clip the red tile border
|
||||
// to the tile viewport.
|
||||
|
||||
Reference in New Issue
Block a user