@@ -65,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<TileData> addTile(const Tile::ID& id);
|
||||
std::shared_ptr<TileData> hasTile(const Tile::ID& id);
|
||||
const Tile *addTile(const Tile::ID& id);
|
||||
const Tile *hasTile(const Tile::ID& id);
|
||||
|
||||
|
||||
void update();
|
||||
@@ -82,8 +82,8 @@ private:
|
||||
|
||||
float pixel_ratio;
|
||||
|
||||
std::forward_list<std::shared_ptr<TileData>> tiles;
|
||||
std::forward_list<std::shared_ptr<TileData>> historic_tiles;
|
||||
std::forward_list<Tile> tiles;
|
||||
std::forward_list<std::weak_ptr<TileData>> tile_data;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -2,19 +2,34 @@
|
||||
#define LLMR_MAP_TILE
|
||||
|
||||
#include <llmr/util/vec.hpp>
|
||||
#include <llmr/util/mat4.hpp>
|
||||
#include <llmr/util/noncopyable.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <forward_list>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
class Tile {
|
||||
class TileData;
|
||||
|
||||
class Tile : private util::noncopyable {
|
||||
public:
|
||||
typedef vec3<int32_t> ID;
|
||||
|
||||
public:
|
||||
Tile(const ID& id);
|
||||
|
||||
static ID parent(const ID& id, int32_t z);
|
||||
static ID normalize(const ID& id);
|
||||
static std::forward_list<ID> children(const ID& id, int32_t z);
|
||||
|
||||
|
||||
public:
|
||||
const Tile::ID id;
|
||||
uint8_t clip_id;
|
||||
mat4 matrix;
|
||||
std::shared_ptr<TileData> data;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ public:
|
||||
|
||||
public:
|
||||
const Tile::ID id;
|
||||
uint8_t clip_id;
|
||||
std::atomic<state> state;
|
||||
|
||||
// Holds the actual geometries in this tile.
|
||||
@@ -89,8 +88,6 @@ public:
|
||||
// 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;
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
void setup();
|
||||
void clear();
|
||||
void changeMatrix();
|
||||
void render(const std::shared_ptr<TileData>& tile);
|
||||
void render(const Tile& tile);
|
||||
void renderMatte();
|
||||
void renderBackground();
|
||||
void renderFill(FillBucket& bucket, const std::string& layer_name, const Tile::ID& id);
|
||||
|
||||
@@ -69,11 +69,10 @@ std::forward_list<llmr::vec3<int32_t>> llmr::covering_tiles(int32_t zoom, const
|
||||
std::forward_list<vec3<int32_t>> tiles;
|
||||
|
||||
auto scanLine = [&tiles, zoom](int32_t x0, int32_t x1, int32_t y, int32_t ymax) {
|
||||
int32_t x, wx;
|
||||
int32_t x;
|
||||
if (y >= 0 && y <= ymax) {
|
||||
for (x = x0; x < x1; x++) {
|
||||
wx = (x + ymax) % ymax;
|
||||
tiles.emplace_front(wx, y, zoom);
|
||||
tiles.emplace_front(x, y, zoom);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -238,29 +238,42 @@ void Map::update() {
|
||||
}
|
||||
|
||||
|
||||
TileData::Ptr Map::hasTile(const Tile::ID& id) {
|
||||
for (TileData::Ptr& tile : tiles) {
|
||||
if (tile->id == id) {
|
||||
return tile;
|
||||
const Tile *Map::hasTile(const Tile::ID& id) {
|
||||
for (const Tile& tile : tiles) {
|
||||
if (tile.id == id) {
|
||||
return &tile;
|
||||
}
|
||||
}
|
||||
|
||||
return TileData::Ptr();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TileData::Ptr Map::addTile(const Tile::ID& id) {
|
||||
TileData::Ptr tile = hasTile(id);
|
||||
const Tile *Map::addTile(const Tile::ID& id) {
|
||||
const Tile *tile = hasTile(id);
|
||||
|
||||
if (!tile.get()) {
|
||||
// We couldn't find the tile in the list. Create a new one.
|
||||
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;
|
||||
tiles.push_front(tile);
|
||||
if (tile) {
|
||||
return tile;
|
||||
}
|
||||
|
||||
return tile;
|
||||
tiles.emplace_front(id);
|
||||
Tile& new_tile = tiles.front();
|
||||
|
||||
// We couldn't find the tile in the list. Create a new one.
|
||||
// Try to find the associated TileData object.
|
||||
const Tile::ID normalized_id = Tile::normalize(id);
|
||||
|
||||
auto it = std::find_if(tile_data.begin(), tile_data.end(), [&normalized_id](const std::weak_ptr<TileData>& tile_data) {
|
||||
return !tile_data.expired() && tile_data.lock()->id == normalized_id;
|
||||
});
|
||||
if (it != tile_data.end() && !it->expired()) {
|
||||
// There is already a tile data object and it's not yet expired, so we're
|
||||
// going to reuse it.
|
||||
new_tile.data = it->lock();
|
||||
} else {
|
||||
new_tile.data = std::make_shared<TileData>(normalized_id, style);
|
||||
tile_data.push_front(new_tile.data);
|
||||
}
|
||||
return &new_tile;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,9 +291,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 TileData::Ptr& tile = hasTile(child_id);
|
||||
if (tile && tile->state == TileData::parsed) {
|
||||
assert(tile);
|
||||
const Tile *tile = hasTile(child_id);
|
||||
if (tile && tile->data && tile->data->state == TileData::parsed) {
|
||||
retain.emplace_front(tile->id);
|
||||
} else {
|
||||
complete = false;
|
||||
@@ -305,9 +317,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 TileData::Ptr tile = hasTile(parent_id);
|
||||
if (tile && tile->state == TileData::parsed) {
|
||||
assert(tile);
|
||||
const Tile *tile = hasTile(parent_id);
|
||||
if (tile && tile->data && tile->data->state == TileData::parsed) {
|
||||
retain.emplace_front(tile->id);
|
||||
return true;
|
||||
}
|
||||
@@ -344,10 +355,10 @@ bool Map::updateTiles() {
|
||||
|
||||
// Add existing child/parent tiles if the actual tile is not yet loaded
|
||||
for (const Tile::ID& id : required) {
|
||||
TileData::Ptr tile = addTile(id);
|
||||
const Tile *tile = addTile(id);
|
||||
assert(tile);
|
||||
|
||||
if (tile->state != TileData::parsed) {
|
||||
if (tile && tile->data && tile->data->state != TileData::parsed) {
|
||||
// The tile we require is not yet loaded. Try to find a parent or
|
||||
// child tile that we already have.
|
||||
|
||||
@@ -362,20 +373,18 @@ bool Map::updateTiles() {
|
||||
}
|
||||
}
|
||||
|
||||
if (tile->state == TileData::initial) {
|
||||
if (tile && tile->data && tile->data->state == TileData::initial) {
|
||||
// If the tile is new, we have to make sure to load it.
|
||||
tile->request();
|
||||
tile->data->request();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove tiles that we definitely don't need, i.e. tiles that are not on
|
||||
// the required list.
|
||||
tiles.remove_if([&retain, &changed](const TileData::Ptr& tile) {
|
||||
assert(tile);
|
||||
bool obsolete = std::find(retain.begin(), retain.end(), tile->id) == retain.end();
|
||||
tiles.remove_if([&retain, &changed](const Tile & tile) {
|
||||
bool obsolete = std::find(retain.begin(), retain.end(), tile.id) == retain.end();
|
||||
if (obsolete) {
|
||||
tile->cancel();
|
||||
changed = true;
|
||||
}
|
||||
return obsolete;
|
||||
@@ -384,8 +393,13 @@ 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 TileData::Ptr& a, const TileData::Ptr& b) {
|
||||
return a->id.z > b->id.z;
|
||||
tiles.sort([](const Tile & a, const Tile & b) {
|
||||
return a.id.z > b.id.z;
|
||||
});
|
||||
|
||||
// Remove all the expired pointers from the list.
|
||||
tile_data.remove_if([](const std::weak_ptr<TileData>& tile_data) {
|
||||
return tile_data.expired();
|
||||
});
|
||||
|
||||
return changed;
|
||||
@@ -406,20 +420,19 @@ bool Map::render() {
|
||||
// the stencil buffer.
|
||||
uint8_t i = 1;
|
||||
painter.prepareClippingMask();
|
||||
for (TileData::Ptr& tile : tiles) {
|
||||
assert(tile);
|
||||
if (tile->state == TileData::parsed) {
|
||||
for (Tile& tile : tiles) {
|
||||
if (tile.data && tile.data->state == TileData::parsed) {
|
||||
// The position matrix.
|
||||
transform.matrixFor(tile->matrix, tile->id);
|
||||
matrix::multiply(tile->matrix, painter.projMatrix, tile->matrix);
|
||||
tile->clip_id = i++;
|
||||
painter.drawClippingMask(tile->matrix, tile->clip_id);
|
||||
transform.matrixFor(tile.matrix, tile.id);
|
||||
matrix::multiply(tile.matrix, painter.projMatrix, tile.matrix);
|
||||
tile.clip_id = i++;
|
||||
painter.drawClippingMask(tile.matrix, tile.clip_id);
|
||||
}
|
||||
}
|
||||
painter.finishClippingMask();
|
||||
|
||||
for (TileData::Ptr& tile : tiles) {
|
||||
if (tile->state == TileData::parsed) {
|
||||
for (const Tile& tile : tiles) {
|
||||
if (tile.data && tile.data->state == TileData::parsed) {
|
||||
painter.render(tile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
using namespace llmr;
|
||||
|
||||
Tile::Tile(const ID& id)
|
||||
: id(id) {
|
||||
}
|
||||
|
||||
Tile::ID Tile::parent(const ID& id, int32_t z) {
|
||||
assert(z < id.z);
|
||||
ID pos(id);
|
||||
@@ -29,3 +33,11 @@ std::forward_list<Tile::ID> Tile::children(const ID& id, int32_t z) {
|
||||
return children;
|
||||
}
|
||||
|
||||
|
||||
Tile::ID Tile::normalize(const ID& id) {
|
||||
ID pos(id);
|
||||
int32_t dim = pow(2, id.z);
|
||||
while (pos.x < 0) pos.x += dim;
|
||||
while (pos.x >= dim) pos.x -= dim;
|
||||
return pos;
|
||||
}
|
||||
@@ -83,9 +83,9 @@ bool TileData::parse() {
|
||||
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);
|
||||
// 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);
|
||||
// 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());
|
||||
|
||||
@@ -130,24 +130,25 @@ void Painter::clear() {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void Painter::render(const TileData::Ptr& tile) {
|
||||
if (tile->state != TileData::parsed) {
|
||||
void Painter::render(const Tile& tile) {
|
||||
assert(tile.data);
|
||||
if (tile.data->state != TileData::parsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
matrix = tile->matrix;
|
||||
glStencilFunc(GL_EQUAL, tile->clip_id, 0xFF);
|
||||
matrix = tile.matrix;
|
||||
glStencilFunc(GL_EQUAL, tile.clip_id, 0xFF);
|
||||
|
||||
renderLayers(tile, style.layers);
|
||||
renderLayers(tile.data, style.layers);
|
||||
|
||||
if (settings.debug) {
|
||||
renderDebug(tile);
|
||||
renderDebug(tile.data);
|
||||
}
|
||||
|
||||
renderBackground();
|
||||
}
|
||||
|
||||
void Painter::renderLayers(const std::shared_ptr<TileData>& tile, const std::vector<LayerDescription>& layers) {
|
||||
void Painter::renderLayers(const std::shared_ptr<TileData>& tile_data, 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) {
|
||||
@@ -156,15 +157,15 @@ void Painter::renderLayers(const std::shared_ptr<TileData>& tile, const std::vec
|
||||
if (layer_desc.child_layer.size()) {
|
||||
// This is a layer group.
|
||||
// TODO: create framebuffer
|
||||
renderLayers(tile, layer_desc.child_layer);
|
||||
renderLayers(tile_data, layer_desc.child_layer);
|
||||
// TODO: render framebuffer on previous framebuffer
|
||||
} else {
|
||||
// This is a singular layer. Try to find the bucket associated with
|
||||
// this layer and render it.
|
||||
auto bucket_it = tile->buckets.find(layer_desc.bucket_name);
|
||||
if (bucket_it != tile->buckets.end()) {
|
||||
auto bucket_it = tile_data->buckets.find(layer_desc.bucket_name);
|
||||
if (bucket_it != tile_data->buckets.end()) {
|
||||
assert(bucket_it->second);
|
||||
bucket_it->second->render(*this, layer_desc.name, tile->id);
|
||||
bucket_it->second->render(*this, layer_desc.name, tile_data->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -423,7 +424,7 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co
|
||||
bucket.drawPoints(*pointShader);
|
||||
}
|
||||
|
||||
void Painter::renderDebug(const TileData::Ptr& tile) {
|
||||
void Painter::renderDebug(const TileData::Ptr& tile_data) {
|
||||
// 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.
|
||||
@@ -442,13 +443,13 @@ void Painter::renderDebug(const TileData::Ptr& tile) {
|
||||
glDrawArrays(GL_LINE_STRIP, 0, (GLsizei)tileBorderBuffer.index());
|
||||
|
||||
// draw debug info
|
||||
tile->debugFontArray.bind(*plainShader, tile->debugFontBuffer, BUFFER_OFFSET(0));
|
||||
tile_data->debugFontArray.bind(*plainShader, tile_data->debugFontBuffer, BUFFER_OFFSET(0));
|
||||
plainShader->setColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
lineWidth(4.0f * transform.pixelRatio);
|
||||
glDrawArrays(GL_LINES, 0, (GLsizei)tile->debugFontBuffer.index());
|
||||
glDrawArrays(GL_LINES, 0, (GLsizei)tile_data->debugFontBuffer.index());
|
||||
plainShader->setColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
lineWidth(2.0f * transform.pixelRatio);
|
||||
glDrawArrays(GL_LINES, 0, (GLsizei)tile->debugFontBuffer.index());
|
||||
glDrawArrays(GL_LINES, 0, (GLsizei)tile_data->debugFontBuffer.index());
|
||||
|
||||
// Revert blending mode to blend to the back.
|
||||
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
|
||||
|
||||
Reference in New Issue
Block a user