saving current state

This commit is contained in:
Konstantin Käfer
2014-06-23 18:05:06 +02:00
parent f51fd9be58
commit ba4294ae0c
56 changed files with 3078 additions and 6223 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -78,15 +78,8 @@ void GLFWView::key(GLFWwindow *window, int key, int /*scancode*/, int action, in
break;
case GLFW_KEY_R:
if (!mods) {
std::set<std::string> newAppliedClasses;
if (view->map->getAppliedClasses().count("night")) {
newAppliedClasses.insert("default");
} else {
newAppliedClasses.insert("default");
newAppliedClasses.insert(newAppliedClasses.end(), "night");
}
view->map->setDefaultTransitionDuration(300);
view->map->setAppliedClasses(newAppliedClasses);
view->map->toggleClass("night");
}
break;
case GLFW_KEY_N:

View File

@@ -32,6 +32,10 @@ public:
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) {

View File

@@ -21,8 +21,6 @@ namespace llmr {
class Source;
typedef std::map<std::string, const std::unique_ptr<Source>> Sources;
class Map : private util::noncopyable {
public:
explicit Map(View &view);
@@ -53,8 +51,9 @@ public:
void resize(uint16_t width, uint16_t height, float ratio, uint16_t fb_width, uint16_t fb_height);
// Styling
void setAppliedClasses(std::set<std::string> appliedClasses);
std::set<std::string> getAppliedClasses() const;
void toggleClass(const std::string &name);
// void setAppliedClasses(const std::vector<std::string> &appliedClasses);
// const std::vector<std::string> &getAppliedClasses() const;
void setDefaultTransitionDuration(uint64_t duration_milliseconds = 0);
void setStyleJSON(std::string newStyleJSON);
std::string getStyleJSON() const;
@@ -108,7 +107,7 @@ public:
inline std::shared_ptr<Texturepool> getTexturepool() { return texturepool; }
inline std::shared_ptr<uv::loop> getLoop() { return loop; }
inline time getAnimationTime() const { return animationTime; }
inline const Sources &getSources() { return sources; }
inline time getTime() const { return animationTime; }
private:
// uv async callbacks
@@ -133,8 +132,8 @@ private:
// Unconditionally performs a render with the current map state.
void render();
void renderLayers(const std::vector<LayerDescription>& layers);
void renderLayer(const LayerDescription& layer_desc, RenderPass pass);
void renderLayers(std::shared_ptr<StyleLayerGroup> layers);
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*
@@ -162,8 +161,6 @@ private:
Painter painter;
Sources sources;
std::string styleJSON = "";
bool debug = false;

View File

@@ -16,8 +16,8 @@ public:
~RasterTileData();
virtual void parse();
virtual void render(Painter &painter, const LayerDescription& layer_desc);
virtual bool hasData(const LayerDescription& layer_desc) const;
virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc);
virtual bool hasData(std::shared_ptr<StyleLayer> layer_desc) const;
protected:
RasterBucket bucket;

View File

@@ -16,60 +16,49 @@
namespace llmr {
class Map;
class TransformState;
class Painter;
class Texturepool;
class Source : public std::enable_shared_from_this<Source>, private util::noncopyable {
public:
enum class Type {
vector,
raster
};
Source(SourceType type = SourceType::Vector, const std::string &url = "", const std::string &glyphs = "",
uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 22);
public:
Source(Map &map, Painter &painter,
const char *url = "", Type type = Type::vector, std::vector<uint32_t> zooms = {0},
uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 14,
bool enabled = true);
bool update();
void updateMatrices(const TransformState &transform);
void drawClippingMasks();
bool update(Map &map);
void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
void drawClippingMasks(Painter &painter);
size_t getTileCount() const;
void render(const LayerDescription& layer_desc, const BucketDescription &bucket_desc);
void finishRender();
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);
public:
bool enabled;
const SourceType type;
const std::string url;
const std::string glyphs;
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(int32_t zoom, const box& points);
std::forward_list<Tile::ID> covering_tiles(const TransformState &state, int32_t clamped_zoom, const box& points);
bool updateTiles();
bool updateTiles(Map &map);
TileData::State addTile(const Tile::ID& id);
TileData::State addTile(Map &map, const Tile::ID& id);
TileData::State hasTile(const Tile::ID& id);
double getZoom() const;
double getZoom(const TransformState &state) const;
private:
Map& map;
Painter& painter;
const Type type;
const std::vector<uint32_t> zooms;
const std::string url;
const uint32_t tile_size;
const int32_t min_zoom;
const int32_t max_zoom;
// Stores the time when this source was most recently updated.
time updated = 0;
std::map<Tile::ID, std::unique_ptr<Tile>> tiles;
std::map<Tile::ID, std::weak_ptr<TileData>> tile_data;

View File

@@ -16,7 +16,7 @@ namespace llmr {
class Map;
class Painter;
class LayerDescription;
class StyleLayer;
class TileData : public std::enable_shared_from_this<TileData>,
private util::noncopyable {
@@ -49,8 +49,8 @@ public:
virtual void beforeParse();
virtual void parse() = 0;
virtual void afterParse();
virtual void render(Painter &painter, const LayerDescription& layer_desc) = 0;
virtual bool hasData(const LayerDescription& layer_desc) const = 0;
virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc) = 0;
virtual bool hasData(std::shared_ptr<StyleLayer> layer_desc) const = 0;
public:

View File

@@ -6,6 +6,7 @@
#include <llmr/text/glyph_store.hpp>
#include <llmr/text/glyph.hpp>
#include <llmr/util/utf.hpp>
#include <llmr/map/filter_expression.hpp>
namespace llmr {
@@ -14,8 +15,13 @@ class GlyphAtlas;
class GlyphStore;
class SpriteAtlas;
class VectorTileData;
class StyleLayer;
typedef std::vector<std::shared_ptr<StyleLayer>> StyleLayerGroup;
class StyleBucket;
class StyleBucketFill;
class StyleBucketLine;
class StyleBucketIcon;
class LayerDescription;
class Bucket;
class TileParser {
@@ -32,15 +38,17 @@ public:
private:
bool obsolete() const;
void parseGlyphs();
void parseStyleLayers(const std::vector<LayerDescription>& layers);
void parseStyleLayers(std::shared_ptr<StyleLayerGroup> layers);
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(const BucketDescription& bucket_desc);
std::unique_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc);
std::unique_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc);
std::unique_ptr<Bucket> createIconBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc);
std::unique_ptr<Bucket> createTextBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc);
template <class Bucket> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc);
template <class Bucket, typename ...Args> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc, Args&& ...args);
std::unique_ptr<Bucket> createBucket(std::shared_ptr<StyleBucket> bucket_desc);
std::unique_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketFill &fill);
std::unique_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketLine &line);
std::unique_ptr<Bucket> createIconBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketIcon &icon);
std::unique_ptr<Bucket> createTextBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketText &text);
template <class Bucket> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter);
template <class Bucket, typename ...Args> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter, Args&& ...args);
private:
const VectorTile vector_data;

View File

@@ -67,14 +67,14 @@ public:
};
public:
FilteredVectorTileLayer(const VectorTileLayer& layer, const BucketDescription& bucket_desc);
FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression);
iterator begin() const;
iterator end() const;
private:
const VectorTileLayer& layer;
const BucketDescription& bucket_desc;
const PropertyFilterExpression& filterExpression;
};
std::ostream& operator<<(std::ostream&, const GlyphPlacement& placement);

View File

@@ -29,8 +29,8 @@ public:
virtual void beforeParse();
virtual void parse();
virtual void afterParse();
virtual void render(Painter &painter, const LayerDescription& layer_desc);
virtual bool hasData(const LayerDescription& layer_desc) const;
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.

View File

@@ -10,10 +10,11 @@
namespace llmr {
class Painter;
class StyleLayer;
class Bucket : private util::noncopyable {
public:
virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id) = 0;
virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) = 0;
virtual bool hasData() const = 0;
virtual ~Bucket() {}

View File

@@ -21,7 +21,7 @@ class DebugBucket : public Bucket {
public:
DebugBucket(DebugFontBuffer& fontBuffer);
virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id);
virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
virtual bool hasData() const;
void drawLines(PlainShader& shader);

View File

@@ -41,10 +41,10 @@ public:
FillBucket(FillVertexBuffer& vertexBuffer,
TriangleElementsBuffer& triangleElementsBuffer,
LineElementsBuffer& lineElementsBuffer,
const BucketFillDescription& properties);
const StyleBucketFill& properties);
~FillBucket();
virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id);
virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
virtual bool hasData() const;
void addGeometry(pbf& data);
@@ -55,7 +55,7 @@ public:
void drawVertices(OutlineShader& shader);
public:
const BucketFillDescription &properties;
const StyleBucketFill &properties;
private:
TESSalloc *allocator;

View File

@@ -26,9 +26,9 @@ class VectorTileFeature;
class IconBucket : public Bucket {
public:
IconBucket(IconVertexBuffer& vertexBuffer,
const BucketIconDescription& properties);
const StyleBucketIcon& properties);
virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id);
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);
@@ -37,7 +37,7 @@ public:
void drawIcons(DotShader& shader);
public:
const BucketIconDescription &properties;
const StyleBucketIcon &properties;
private:

View File

@@ -25,9 +25,9 @@ public:
LineBucket(LineVertexBuffer& vertexBuffer,
TriangleElementsBuffer& triangleElementsBuffer,
PointElementsBuffer& pointElementsBuffer,
const BucketLineDescription& properties);
const StyleBucketLine& properties);
virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id);
virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
virtual bool hasData() const;
void addGeometry(pbf& data);
@@ -39,7 +39,7 @@ public:
void drawPoints(LinejoinShader& shader);
public:
const BucketLineDescription &properties;
const StyleBucketLine &properties;
private:

View File

@@ -24,6 +24,7 @@
#include <llmr/map/transform_state.hpp>
#include <map>
#include <unordered_map>
namespace llmr {
@@ -42,8 +43,6 @@ class RasterBucket;
class LayerDescription;
class RasterTileData;
typedef std::map<std::string, const std::unique_ptr<Source>> Sources;
class Painter : private util::noncopyable {
public:
Painter(Map &map);
@@ -64,7 +63,7 @@ public:
void changeMatrix();
// Renders a particular layer from a tile.
void renderTileLayer(const Tile& tile, const LayerDescription &layer_desc);
void renderTileLayer(const Tile& tile, std::shared_ptr<StyleLayer> layer_desc);
// Renders debug information for a tile.
void renderTileDebug(const Tile& tile);
@@ -79,15 +78,15 @@ public:
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, const std::string& layer_name, const Tile::ID& id);
void renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& id);
void renderIcon(IconBucket& bucket, const std::string& layer_name, const Tile::ID& id);
void renderText(TextBucket& bucket, const std::string& layer_name, const Tile::ID& id);
void renderRaster(RasterBucket& bucket, const std::string& layer_name, const Tile::ID& id);
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);
void renderPrerenderedTexture(PrerenderedTexture &texture, const GenericProperties &properties);
// void renderPrerenderedTexture(PrerenderedTexture &texture, const GenericProperties &properties);
void resize();
@@ -101,7 +100,7 @@ public:
// Configures the painter strata that is used for early z-culling of fragments.
void setStrata(float strata);
void drawClippingMasks(const Sources &sources);
void drawClippingMasks(const std::set<std::shared_ptr<Source>> &sources);
void drawClippingMask(const mat4& matrix, const ClipID& clip);
void clearFramebuffers();
@@ -115,7 +114,7 @@ public:
bool needsAnimation() const;
private:
void setupShaders();
const mat4 &translatedMatrix(const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchor anchor = TranslateAnchor::Map);
const mat4 &translatedMatrix(const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchorType anchor = parseTranslateAnchorType());
void prepareTile(const Tile& tile);

View File

@@ -15,7 +15,7 @@ class RasterBucket : public Bucket {
public:
RasterBucket(const std::shared_ptr<Texturepool> &texturepool);
virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id);
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);

View File

@@ -28,9 +28,9 @@ public:
TextBucket(
TextVertexBuffer &vertexBuffer,
TriangleElementsBuffer &triangleElementsBuffer,
const BucketTextDescription &properties, Placement &placement);
const StyleBucketText &properties, Placement &placement);
virtual void render(Painter &painter, const std::string &layer_name, const Tile::ID &id);
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,
@@ -43,7 +43,7 @@ public:
void drawGlyphs(TextShader &shader);
public:
const BucketTextDescription &properties;
const StyleBucketText &properties;
private:
TextVertexBuffer& vertexBuffer;

View File

@@ -8,125 +8,11 @@
#include <llmr/util/vec.hpp>
#include <llmr/map/filter_expression.hpp>
#include <llmr/style/value.hpp>
#include <llmr/style/style_bucket.hpp>
namespace llmr {
enum class BucketType {
None = 0,
Fill = 1,
Line = 2,
Icon = 3,
Text = 4,
Raster = 5
};
enum class CapType {
None = 0,
Round = 1,
Butt = 2,
Square = 3
};
enum class JoinType {
None = 0,
Miter = 1,
Bevel = 2,
Round = 3
};
enum class TextPathType {
Horizontal = 0,
Curve = 1
};
inline BucketType bucketType(const std::string& type) {
if (type == "fill") return BucketType::Fill;
else if (type == "line") return BucketType::Line;
else if (type == "point") return BucketType::Icon;
else if (type == "text") return BucketType::Text;
else if (type == "raster") return BucketType::Raster;
else return BucketType::None;
}
inline CapType capType(const std::string& cap) {
if (cap == "round") return CapType::Round;
else if (cap == "butt") return CapType::Butt;
else if (cap == "square") return CapType::Square;
else return CapType::None;
}
inline JoinType joinType(const std::string& join) {
if (join == "miter") return JoinType::Miter;
else if (join == "bevel") return JoinType::Bevel;
else if (join == "round") return JoinType::Round;
else return JoinType::None;
}
inline TextPathType textPathType(const std::string& path) {
if (path == "horizontal") return TextPathType::Horizontal;
else if (path == "curve") return TextPathType::Curve;
else return TextPathType::Horizontal;
};
inline float alignmentType(const std::string& alignment) {
if (alignment == "right") return 1.0f;
else if (alignment == "left") return 0.0f;
else return 0.5;
};
inline float verticalAlignmentType(const std::string& alignment) {
if (alignment == "bottom") return 1.0f;
else if (alignment == "top") return 0.0f;
else return 0.5;
};
class BucketFillDescription {
public:
};
class BucketLineDescription {
public:
CapType cap = CapType::None;
JoinType join = JoinType::None;
float miter_limit = 2.0f;
float round_limit = 1.0f;
};
class BucketIconDescription {
public:
uint16_t size = 16;
vec2<float> translate {0, 0};
std::string icon;
};
class BucketTextDescription {
public:
std::string field;
TextPathType path = TextPathType::Horizontal;
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};
float max_angle_delta = M_PI;
float min_distance = 250.0f;
float rotate = 0.0f; // what is this?
float padding = 2.0f;
bool always_visible = false;
};
class BucketRasterDescription {
public:
};
typedef util::variant<BucketFillDescription, BucketLineDescription, BucketIconDescription,
BucketTextDescription, BucketRasterDescription> BucketRenderDescription;
// Deprecated
class BucketDescription {
public:
BucketType feature_type = BucketType::None;
@@ -139,7 +25,7 @@ public:
PropertyFilterExpression filter = std::true_type();
// Specifies how the geometry for this bucket should be created
BucketRenderDescription render;
StyleBucketRender render;
};
std::ostream& operator<<(std::ostream&, const BucketDescription& bucket);

View File

@@ -5,17 +5,17 @@
#include <vector>
namespace llmr {
class LayerDescription {
public:
std::string name;
std::string bucket_name;
std::vector<LayerDescription> child_layer;
size_t size() const;
};
std::ostream& operator<<(std::ostream&, const LayerDescription& layer);
//
//class LayerDescription {
//public:
// std::string name;
// std::string bucket_name;
// std::vector<LayerDescription> child_layer;
//
// size_t size() const;
//};
//
//std::ostream& operator<<(std::ostream&, const LayerDescription& layer);
}

View File

@@ -13,16 +13,14 @@
#include <boost/optional.hpp>
#include <llmr/util/variant.hpp>
#include <llmr/style/types.hpp>
namespace llmr {
// Stores a premultiplied color, with all four channels ranging from 0..1
typedef std::array<float, 4> Color;
struct PropertyTransition {
inline PropertyTransition(uint16_t duration, uint16_t delay = 0)
: duration(duration), delay(delay) {}
inline PropertyTransition(const PropertyTransition &transition)
: duration(transition.duration), delay(transition.delay) {}
struct ClassPropertyTransition {
uint16_t duration = 0;
uint16_t delay = 0;
};
@@ -43,32 +41,12 @@ enum class TransitionablePropertyKey {
HaloBlur = 13,
};
enum class Winding {
EvenOdd = 1,
NonZero = 2
};
// enum LineCap {
// Round = 1
// };
// enum LineJoin {
// Butt = 1,
// Bevel = 2
// };
enum class Property {
Null = 1,
Constant = 2,
Stops = 3,
Linear = 4
};
enum class TranslateAnchor : uint8_t {
Map = 1,
Viewport = 2
};
namespace functions {
float null(float z, const std::vector<float>&);
@@ -104,88 +82,73 @@ struct FunctionProperty {
template <typename T> inline T evaluate(float z) const { return function(z, values); }
};
enum class RenderType {
Fill,
Line,
Icon,
Text,
Raster,
Composite,
Background
};
enum class ClassPropertyKey {
Enabled,
TranslateX,
TranslateY,
TranslateTransition,
TranslateAnchor,
Opacity,
OpacityTransition,
Prerender,
PrerenderBuffer,
PrerenderSize,
PrerenderBlur,
FillWinding,
FillEnabled,
FillAntialias,
FillOpacity,
FillColor,
FillColorTransition,
FillStrokeColor,
FillStrokeColorTransition,
FillOutlineColor,
FillTranslate, // for transitions only
FillTranslateX,
FillTranslateY,
FillTranslateAnchor,
FillImage,
LineWidth,
LineWidthTransition,
LineOffset,
LineOffsetTransition,
LineEnabled,
LineOpacity,
LineColor,
LineColorTransition,
LineTranslate, // for transitions only
LineTranslateX,
LineTranslateY,
LineTranslateAnchor,
LineWidth,
LineOffset,
LineBlur,
LineDashArray, // for transitions only
LineDashLand,
LineDashGap,
LineDashTransition,
LineImage,
IconSize,
IconColor,
IconColorTransition,
IconImage,
IconRadius,
IconRadiusTransition,
IconBlur,
IconBlurTransition,
IconEnabled,
IconOpacity,
IconRotate,
IconRotateAnchor,
TextColor,
TextColorTransition,
TextHaloColor,
TextHaloColorTransition,
TextHaloRadius,
TextHaloRadiusTransition,
TextHaloBlur,
TextHaloBlurTransition,
TextEnabled,
TextOpacity,
TextSize,
TextRotate,
TextAlwaysVisible,
TextColor,
TextHaloColor,
TextHaloWidth,
TextHaloBlur,
BackgroundColor,
BackgroundColorTransition,
CompositeEnabled,
CompositeOpacity,
RasterSpin,
RasterBrightnessLow,
RasterBrightnessHigh,
RasterSaturation,
RasterContrast,
RasterFade,
BackgroundColor
};
typedef util::variant<
FunctionProperty,
PropertyTransition,
TranslateAnchor,
TranslateAnchorType,
RotateAnchorType,
Color,
Winding,
std::string,
bool
> ClassPropertyValue;
class ClassProperties {
public:
inline ClassProperties(RenderType type) : type(type) {}
inline ClassProperties() {}
inline ClassProperties(ClassProperties &&properties)
: type(properties.type), properties(std::move(properties.properties)) {}
: properties(std::move(properties.properties)) {}
template <typename T>
inline const T *get(ClassPropertyKey key) const {
@@ -196,16 +159,27 @@ public:
return nullptr;
}
}
template <typename ...Args>
inline void emplace(Args&& ...args) {
properties.emplace(::std::forward<Args>(args)...);
inline const ClassPropertyTransition *getTransition(ClassPropertyKey key) const {
const auto it = transitions.find(key);
if (it != transitions.end()) {
return ::std::addressof(it->second);
} else {
return nullptr;
}
}
const RenderType type;
template <typename ...Args>
inline void set(Args&& ...args) {
properties.emplace(::std::forward<Args>(args)...);
}
template <typename ...Args>
inline void setTransition(Args&& ...args) {
transitions.emplace(::std::forward<Args>(args)...);
}
private:
public:
std::map<ClassPropertyKey, ClassPropertyValue> properties;
std::map<ClassPropertyKey, ClassPropertyTransition> transitions;
};
struct PrerenderProperties {
@@ -213,99 +187,164 @@ struct PrerenderProperties {
uint16_t size = 256;
uint16_t blur = 0;
};
//
//struct GenericProperties {
// bool enabled = true;
// std::array<float, 2> translate = {{ 0, 0 }};
// TranslateAnchorType translateAnchor = parseTranslateAnchorType();
// float opacity = 1.0;
//
// // These are unresolved properties because the value here is per tile, so it might differ.
// boost::optional<FunctionProperty> prerender;
// boost::optional<FunctionProperty> prerenderBuffer;
// boost::optional<FunctionProperty> prerenderSize;
// boost::optional<FunctionProperty> prerenderBlur;
//
// inline bool getPrerender(int8_t z) const {
// return prerender && prerender.get().evaluate<bool>(z);
// }
//
// // Obtains prerender properties by integer zoom level.
// inline PrerenderProperties getPrerenderProperties(int8_t z) const {
// PrerenderProperties props;
// if (prerenderBuffer) props.buffer = prerenderBuffer.get().evaluate<float>(z);
// if (prerenderSize) props.size = prerenderSize.get().evaluate<uint16_t>(z);
// if (prerenderBlur) props.blur = prerenderBlur.get().evaluate<uint16_t>(z);
// return props;
// }
//
// virtual bool isVisible() const {
// if (!enabled) { return false; }
// if (opacity <= 0) { return false; }
// return true;
// }
//};
struct GenericProperties {
struct FillProperties {
FillProperties() {}
bool enabled = true;
std::array<float, 2> translate = {{ 0, 0 }};
TranslateAnchor translateAnchor = TranslateAnchor::Map;
float opacity = 1.0;
// These are unresolved properties because the value here is per tile, so it might differ.
boost::optional<FunctionProperty> prerender;
boost::optional<FunctionProperty> prerenderBuffer;
boost::optional<FunctionProperty> prerenderSize;
boost::optional<FunctionProperty> prerenderBlur;
inline bool getPrerender(int8_t z) const {
return prerender && prerender.get().evaluate<bool>(z);
}
// Obtains prerender properties by integer zoom level.
inline PrerenderProperties getPrerenderProperties(int8_t z) const {
PrerenderProperties props;
if (prerenderBuffer) props.buffer = prerenderBuffer.get().evaluate<float>(z);
if (prerenderSize) props.size = prerenderSize.get().evaluate<uint16_t>(z);
if (prerenderBlur) props.blur = prerenderBlur.get().evaluate<uint16_t>(z);
return props;
}
virtual bool isVisible() const {
if (!enabled) { return false; }
if (opacity <= 0) { return false; }
return true;
}
};
struct IconProperties : public GenericProperties {
inline IconProperties() : GenericProperties() {}
float size = 0;
Color color = {{ 1, 1, 1, 1 }};
std::string image;
float radius = 0;
float blur = 0;
};
struct LineProperties : public GenericProperties {
inline LineProperties() : GenericProperties() {}
float width = 0;
float offset = 0;
Color color = {{ 0, 0, 0, 1 }};
std::array<float, 2> dash_array = {{ 1, -1 }};
};
struct FillProperties : public GenericProperties {
inline FillProperties() : GenericProperties() {}
Winding winding = Winding::NonZero;
bool antialias = true;
float opacity = 1.0f;
Color fill_color = {{ 0, 0, 0, 1 }};
Color stroke_color = {{ 0, 0, 0, 1 }};
float blur = 0.0f;
std::array<float, 2> translate = {{ 0, 0 }};
TranslateAnchorType translateAnchor = parseTranslateAnchorType();
std::string image;
inline bool isVisible() const {
return enabled && opacity > 0 && (fill_color[3] > 0 || stroke_color[3] > 0);
}
};
struct TextProperties : public GenericProperties {
inline TextProperties() : GenericProperties() {}
struct LineProperties {
inline LineProperties() {}
bool enabled = true;
float opacity = 1.0f;
Color color = {{ 0, 0, 0, 1 }};
Color halo = {{ 1, 1, 1, 0.75 }};
float halo_radius = 0.25f;
float halo_blur = 1.0f;
float size = 12.0f;
float rotate = 0.0f;
bool always_visible = false;
std::array<float, 2> translate = {{ 0, 0 }};
TranslateAnchorType translateAnchor = parseTranslateAnchorType();
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 enabled && opacity > 0 && color[3] > 0 && width > 0;
}
};
struct BackgroundProperties : public GenericProperties {
inline BackgroundProperties() : GenericProperties() {}
struct IconProperties {
inline IconProperties() {}
bool enabled = true;
float opacity = 1.0f;
float rotate = 0.0f;
RotateAnchorType rotate_anchor = parseRotateAnchorType();
inline bool isVisible() const {
return enabled && opacity > 0;
}
};
struct TextProperties {
inline TextProperties() {}
bool enabled = true;
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 enabled && opacity > 0 && (color[3] > 0 || halo_color[3] > 0) && size > 0;
}
};
struct CompositeProperties {
inline CompositeProperties() {}
bool enabled = true;
float opacity = 1.0f;
inline bool isVisible() const {
return enabled && opacity > 0;
}
};
struct RasterProperties {
inline RasterProperties() {}
bool enabled = true;
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 enabled && opacity > 0;
}
};
struct BackgroundProperties {
inline BackgroundProperties() {}
Color color = {{ 1, 1, 1, 1 }};
};
struct RasterProperties : public GenericProperties {
inline RasterProperties() : GenericProperties() {}
typedef util::variant<
FillProperties,
LineProperties,
IconProperties,
TextProperties,
CompositeProperties,
RasterProperties,
BackgroundProperties,
std::false_type
> StyleProperties;
template <typename T>
const T &defaultStyleProperties();
//class StyleSource {
//public:
// typedef std::shared_ptr<StyleSource> Ptr;
//
// enum { Vector, Raster } type = Vector;
// std::string url;
// float tileSize = 512.0f;
//};
class RasterizeProperties {
public:
boost::optional<FunctionProperty> enabled;
boost::optional<FunctionProperty> buffer;
boost::optional<FunctionProperty> size;
boost::optional<FunctionProperty> blur;
};
struct CompositeProperties : public GenericProperties {
inline CompositeProperties() : GenericProperties() {}
};
const IconProperties defaultIconProperties;
const LineProperties defaultLineProperties;
const FillProperties defaultFillProperties;
const TextProperties defaultTextProperties;
const BackgroundProperties defaultBackgroundProperties;
const RasterProperties defaultRasterProperties;
const CompositeProperties defaultCompositeProperties;
}

View File

@@ -21,6 +21,33 @@ namespace llmr {
class Sprite;
class StyleLayer;
typedef std::vector<std::shared_ptr<StyleLayer>> StyleLayerGroup;
class StyleLayer {
public:
typedef std::shared_ptr<StyleLayer> Ptr;
public:
template <typename T> const T &getProperties() {
if (style.is<T>()) {
return style.get<T>();
} else {
return defaultStyleProperties<T>();
}
}
public:
std::string id;
StyleBucket::Ptr bucket;
std::unordered_map<std::string, ClassProperties> styles;
StyleProperties style;
std::unique_ptr<RasterizeProperties> rasterize;
std::shared_ptr<StyleLayerGroup> layers;
};
class Style {
public:
struct exception : std::runtime_error { exception(const char *msg) : std::runtime_error(msg) {} };
@@ -41,69 +68,90 @@ public:
void setDefaultTransitionDuration(uint64_t duration_milliseconds = 0);
void updateSources();
const std::set<std::shared_ptr<Source>> getActiveSources() const;
void toggleClass(const std::string &name);
public:
std::shared_ptr<Sprite> sprite;
std::shared_ptr<StyleLayerGroup> layers;
std::shared_ptr<StyleLayer> background;
std::vector<std::string> appliedClasses;
// This is static information parsed from the stylesheet.
std::map<std::string, BucketDescription> buckets;
std::vector<LayerDescription> layers;
std::map<std::string, ClassDescription> classes;
// Currently applied settings.
std::set<std::string> appliedClasses;
struct {
BackgroundProperties background;
std::unordered_map<std::string, FillProperties> fills;
std::unordered_map<std::string, LineProperties> lines;
std::unordered_map<std::string, IconProperties> icons;
std::unordered_map<std::string, TextProperties> texts;
std::unordered_map<std::string, RasterProperties> rasters;
std::unordered_map<std::string, CompositeProperties> composites;
std::unordered_map<std::string, std::unordered_map<TransitionablePropertyKey, std::string>> effective_classes;
} computed;
private:
bool transitionInProgress(const std::string &layer_name, TransitionablePropertyKey key, time start);
bool transitionExists(const std::string &layer_name, TransitionablePropertyKey key) const;
bool inNeedOfTransition(const std::string &layer_name, TransitionablePropertyKey key) const;
uint64_t transitionDuration(const std::string &layer_name, TransitionablePropertyKey key) const;
uint64_t transitionDelay(const std::string &layer_name, TransitionablePropertyKey key) const;
void updateSources(const std::shared_ptr<StyleLayerGroup> &layers);
void cascade(const std::shared_ptr<StyleLayerGroup> &layers, float z);
void cascadeProperties(GenericProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
void cascadeProperties(FillProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
void cascadeProperties(LineProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
void cascadeProperties(IconProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
void cascadeProperties(TextProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
void cascadeProperties(RasterProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
void cascadeProperties(CompositeProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
void cascadeProperties(BackgroundProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
private:
std::set<std::shared_ptr<Source>> activeSources;
// This is static information parsed from the stylesheet.
// // This is unused!!!
// std::map<std::string, BucketDescription> buckets;
//
//
// std::vector<LayerDescription> layers;
//
// // These are unused!!!
// std::map<std::string, ClassDescription> classes;
//
// // Currently applied settings.
// struct {
// BackgroundProperties background;
// std::unordered_map<std::string, FillProperties> fills;
// std::unordered_map<std::string, LineProperties> lines;
// std::unordered_map<std::string, IconProperties> icons;
// std::unordered_map<std::string, TextProperties> texts;
// std::unordered_map<std::string, RasterProperties> rasters;
// std::unordered_map<std::string, CompositeProperties> composites;
// std::unordered_map<std::string, std::unordered_map<TransitionablePropertyKey, std::string>> effective_classes;
// } computed;
private:
// bool transitionInProgress(const std::string &layer_name, TransitionablePropertyKey key, time start);
// bool transitionExists(const std::string &layer_name, TransitionablePropertyKey key) const;
// bool inNeedOfTransition(const std::string &layer_name, TransitionablePropertyKey key) const;
// uint64_t transitionDuration(const std::string &layer_name, TransitionablePropertyKey key) const;
// uint64_t transitionDelay(const std::string &layer_name, TransitionablePropertyKey key) const;
//
// void cascadeProperties(GenericProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
// void cascadeProperties(FillProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
// void cascadeProperties(LineProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
// void cascadeProperties(IconProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
// void cascadeProperties(TextProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
// void cascadeProperties(RasterProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
// void cascadeProperties(CompositeProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
// void cascadeProperties(BackgroundProperties &properties, const ClassProperties& klass, const std::string& layer_name, const std::string& class_name, float z);
private:
// Last applied settings.
struct {
BackgroundProperties background;
std::unordered_map<std::string, FillProperties> fills;
std::unordered_map<std::string, LineProperties> lines;
std::unordered_map<std::string, IconProperties> icons;
std::unordered_map<std::string, TextProperties> texts;
std::unordered_map<std::string, RasterProperties> rasters;
std::unordered_map<std::string, CompositeProperties> composites;
std::unordered_map<std::string, std::unordered_map<TransitionablePropertyKey, std::string>> effective_classes;
} previous;
// struct {
// BackgroundProperties background;
// std::unordered_map<std::string, FillProperties> fills;
// std::unordered_map<std::string, LineProperties> lines;
// std::unordered_map<std::string, IconProperties> icons;
// std::unordered_map<std::string, TextProperties> texts;
// std::unordered_map<std::string, RasterProperties> rasters;
// std::unordered_map<std::string, CompositeProperties> composites;
// std::unordered_map<std::string, std::unordered_map<TransitionablePropertyKey, std::string>> effective_classes;
// } previous;
// Settings values currently being transitioned.
struct {
BackgroundProperties background;
std::unordered_map<std::string, FillProperties> fills;
std::unordered_map<std::string, LineProperties> lines;
std::unordered_map<std::string, IconProperties> icons;
std::unordered_map<std::string, TextProperties> texts;
std::unordered_map<std::string, RasterProperties> rasters;
std::unordered_map<std::string, CompositeProperties> composites;
} transitioning;
// // Settings values currently being transitioned.
// struct {
// BackgroundProperties background;
// std::unordered_map<std::string, FillProperties> fills;
// std::unordered_map<std::string, LineProperties> lines;
// std::unordered_map<std::string, IconProperties> icons;
// std::unordered_map<std::string, TextProperties> texts;
// std::unordered_map<std::string, RasterProperties> rasters;
// std::unordered_map<std::string, CompositeProperties> composites;
// } transitioning;
std::unordered_map<std::string, std::unordered_map<TransitionablePropertyKey, PropertyTransition>> properties_to_transition;
std::unordered_map<std::string, std::unordered_map<TransitionablePropertyKey, std::shared_ptr<util::transition>>> transitions;
// std::unordered_map<std::string, std::unordered_map<TransitionablePropertyKey, ClassPropertyTransition>> properties_to_transition;
// std::unordered_map<std::string, std::unordered_map<TransitionablePropertyKey, std::shared_ptr<util::transition>>> transitions;
uint64_t default_transition_duration = 0;
bool initial_render_complete = false;

View File

@@ -0,0 +1,82 @@
#ifndef LLMR_STYLE_STYLE_BUCKET
#define LLMR_STYLE_STYLE_BUCKET
#include <llmr/style/types.hpp>
#include <llmr/map/filter_expression.hpp>
#include <llmr/util/vec.hpp>
#include <llmr/util/variant.hpp>
namespace llmr {
class Source;
class StyleBucketFill {
public:
WindingType winding = parseWindingType();
};
class StyleBucketLine {
public:
CapType cap = parseCapType();
JoinType join = parseJoinType();
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 = parseTranslateAnchorType();
std::string icon;
float spacing = 0.0f;
float padding = 2.0f;
};
class StyleBucketText {
public:
std::string field;
TextPathType path = parseTextPathType();
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 = parseTranslateAnchorType();
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;
BucketType type = BucketType::None;
std::string name;
std::shared_ptr<Source> source;
std::string source_layer;
PropertyFilterExpression filter = std::true_type();
StyleBucketRender render = std::false_type();
};
};
#endif

View File

@@ -3,63 +3,74 @@
#include <rapidjson/document.h>
#include <llmr/style/style.hpp>
#include <llmr/map/source.hpp>
#include <unordered_map>
#include <forward_list>
namespace llmr {
class StyleLayer;
typedef std::vector<std::shared_ptr<StyleLayer>> StyleLayerGroup;
class StyleParser {
public:
using JSVal = const rapidjson::Value&;
void parseBuckets(JSVal value, std::map<std::string, BucketDescription>& buckets);
void parseLayers(JSVal value, std::vector<LayerDescription>& layers);
void parseConstants(JSVal value);
void parseClasses(JSVal value, std::map<std::string, ClassDescription> &classes,
const std::map<std::string, BucketDescription> &buckets,
const std::vector<LayerDescription> &layers);
void parse(JSVal document);
private:
LayerDescription parseLayer(JSVal value);
BucketDescription parseBucket(JSVal value);
std::pair<std::string, ClassDescription>
parseClassDescription(JSVal value,
const std::map<std::string, BucketDescription> &buckets,
const std::map<std::string, std::string> &layerBuckets);
void parseClass(const std::string &name, JSVal value, ClassDescription &class_desc,
const std::map<std::string, BucketDescription> &buckets,
const std::map<std::string, std::string> &layerBuckets);
void parseGenericClass(ClassProperties &klass, JSVal value);
ClassProperties parseFillClass(JSVal value);
ClassProperties parseLineClass(JSVal value);
ClassProperties parseIconClass(JSVal value);
ClassProperties parseTextClass(JSVal value);
ClassProperties parseBackgroundClass(JSVal value);
ClassProperties parseRasterClass(JSVal value);
ClassProperties parseCompositeClass(JSVal value);
PropertyFilterExpression parseFilterOrExpression(JSVal value);
JSVal replaceConstant(JSVal value);
Value parseValue(JSVal value);
template <typename T>
T parse(JSVal value);
template <typename T>
inline void parse(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value) {
if (value.HasMember(property_name)) {
klass.emplace(key, parse<T>(value[property_name]));
}
std::shared_ptr<StyleLayerGroup> getLayers() {
return root;
}
void parseTransition(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value);
void parseFunctionArray(const char *property_name, const std::vector<ClassPropertyKey> &keys, ClassProperties &klass, JSVal value);
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::shared_ptr<StyleLayer> &layer);
void parseStyle(JSVal, ClassProperties &properties);
void parseRasterize(JSVal value, std::shared_ptr<StyleLayer> &layer);
void parseReference(JSVal value, std::shared_ptr<StyleLayer> &layer);
void parseBucket(JSVal value, std::shared_ptr<StyleLayer> &layer);
void parseFilter(JSVal value, std::shared_ptr<StyleLayer> &layer);
void parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer);
// 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 parseStyleProperty(const char *property_name, ClassPropertyKey key, ClassProperties &klass, JSVal value);
template <typename T>
bool parseStyleProperty(const char *property_name, const std::vector<ClassPropertyKey> &keys, ClassProperties &klass, JSVal value);
// PropertyFilterExpression parseFilterOrExpression(JSVal value);
// Value parseValue(JSVal value);
//
private:
std::map<std::string, const rapidjson::Value *> constants;
std::unordered_map<std::string, const rapidjson::Value *> constants;
std::unordered_map<std::string, const std::shared_ptr<Source>> 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;
};
}

View File

@@ -0,0 +1,136 @@
#ifndef LLMR_STYLE_TYPES
#define LLMR_STYLE_TYPES
#include <string>
namespace llmr {
enum class BucketType : uint8_t {
None,
Fill,
Line,
Icon,
Text,
Raster
};
enum class WindingType : uint8_t {
EvenOdd,
NonZero
};
enum class CapType : uint8_t {
None,
Round,
Butt,
Square
};
enum class JoinType : uint8_t {
None,
Miter,
Bevel,
Round
};
enum class TextPathType : uint8_t {
Horizontal,
Curve
};
enum class TranslateAnchorType : uint8_t {
Map,
Viewport
};
enum class RotateAnchorType : uint8_t {
Map,
Viewport
};
enum class SourceType : uint8_t {
Vector,
Raster,
GeoJSON,
Video
};
inline constexpr BucketType parseBucketType(const std::string &type = "") {
return
type.compare("fill") == 0 ? BucketType::Fill :
type.compare("line") == 0 ? BucketType::Line :
type.compare("icon") == 0 ? BucketType::Icon :
type.compare("text") == 0 ? BucketType::Text :
type.compare("raster") == 0 ? BucketType::Raster :
BucketType::None;
}
inline constexpr WindingType parseWindingType(const std::string &type = "") {
return
type.compare("even-odd") == 0 ? WindingType::EvenOdd :
WindingType::NonZero;
}
inline constexpr CapType parseCapType(const std::string &cap = "") {
return
cap.compare("round") == 0 ? CapType::Round :
cap.compare("butt") == 0 ? CapType::Butt :
cap.compare("square") == 0 ? CapType::Square :
CapType::None;
}
inline constexpr JoinType parseJoinType(const std::string &join = "") {
return
join.compare("miter") == 0 ? JoinType::Miter :
join.compare("bevel") == 0 ? JoinType::Bevel :
join.compare("round") == 0 ? JoinType::Round :
JoinType::None;
}
inline constexpr TextPathType parseTextPathType(const std::string &path = "") {
return
path.compare("horizontal") == 0 ? TextPathType::Horizontal :
path.compare("curve") == 0 ? TextPathType::Curve :
TextPathType::Horizontal;
}
inline constexpr TranslateAnchorType parseTranslateAnchorType(const std::string &anchor = "") {
return
anchor.compare("viewport") == 0 ? TranslateAnchorType::Viewport :
TranslateAnchorType::Map;
}
inline constexpr RotateAnchorType parseRotateAnchorType(const std::string &anchor = "") {
return
anchor.compare("map") == 0 ? RotateAnchorType::Map :
RotateAnchorType::Viewport;
}
inline constexpr float parseAlignmentType(const std::string &alignment = "") {
return
alignment.compare("right") == 0 ? 1.0f :
alignment.compare("left") == 0 ? 0.0f :
0.5f;
};
inline constexpr float parseVerticalAlignmentType(const std::string &alignment = "") {
return
alignment.compare("bottom") == 0 ? 1.0f :
alignment.compare("top") == 0 ? 0.0f :
0.5f;
};
inline constexpr SourceType parseSourceType(const std::string &source = "") {
return
source.compare("vector") == 0 ? SourceType::Vector :
source.compare("raster") == 0 ? SourceType::Raster :
source.compare("geojson") == 0 ? SourceType::GeoJSON :
source.compare("video") == 0 ? SourceType::Video :
SourceType::Vector;
}
}
#endif

View File

@@ -12,7 +12,7 @@ namespace llmr {
typedef std::pair<uint16_t, uint16_t> GlyphRange;
// Note: this only works for the BMP
GlyphRange getGlyphRange(uint32_t glyph);
GlyphRange getGlyphRange(char32_t glyph);
struct GlyphMetrics {
operator bool() const {

View File

@@ -10,14 +10,14 @@
namespace llmr {
class TextBucket;
class BucketTextDescription;
class StyleBucketText;
class Placement {
public:
Placement(int8_t zoom);
void addFeature(TextBucket &bucket, const std::vector<Coordinate> &line,
const BucketTextDescription &info,
const StyleBucketText &info,
const GlyphPositions &face,
const Shaping &shaping);

View File

@@ -7,7 +7,7 @@
{
'target_name': 'shaders',
'type': 'none',
'hard_dependency': 1,
# 'hard_dependency': 1,
'actions': [
{
'action_name': 'Build Shaders',

View File

@@ -36,6 +36,10 @@ Map::Map(View& view)
}
Map::~Map() {
// Clear the style first before the rest of the constructor deletes members of this object.
// This is required because members of the style reference the Map object in their destructors.
style.reset();
if (async) {
stop();
}
@@ -167,17 +171,6 @@ void Map::setup() {
painter.setup();
sources.emplace("outdoors",
std::unique_ptr<Source>(new Source(*this,
painter,
kVectorTileURL,
Source::Type::vector,
{{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }},
512,
0,
14,
true)));
setStyleJSON(styleJSON);
}
@@ -387,49 +380,44 @@ bool Map::getDebug() const {
return debug;
}
void Map::setAppliedClasses(std::set<std::string> appliedClasses) {
style->cancelTransitions();
style->appliedClasses.swap(appliedClasses);
update();
void Map::toggleClass(const std::string &name) {
style->toggleClass(name);
}
std::set<std::string> Map::getAppliedClasses() const {
return style->appliedClasses;
}
//void Map::setAppliedClasses(const std::vector<std::string> &appliedClasses) {
// style->cancelTransitions();
//
// style->appliedClasses = appliedClasses;
//
// update();
//}
//
//const std::vector<std::string> &Map::getAppliedClasses() const {
// return style->appliedClasses;
//}
void Map::setDefaultTransitionDuration(uint64_t duration_milliseconds) {
style->setDefaultTransitionDuration(duration_milliseconds);
}
void Map::updateTiles() {
for (auto &pair : sources) {
const std::unique_ptr<Source> &source = pair.second;
if (source->enabled) {
source->update();
}
for (const std::shared_ptr<Source> &source : style->getActiveSources()) {
source->update(*this);
}
}
void Map::updateRenderState() {
std::forward_list<Tile::ID> ids;
for (const auto &pair : sources) {
Source &source = *pair.second;
if (source.enabled) {
ids.splice_after(ids.before_begin(), source.getIDs());
source.updateMatrices(state);
}
for (const std::shared_ptr<Source> &source : style->getActiveSources()) {
ids.splice_after(ids.before_begin(), source->getIDs());
source->updateMatrices(painter.projMatrix, state);
}
const std::map<Tile::ID, ClipID> clipIDs = computeClipIDs(ids);
for (const auto &pair : sources) {
Source &source = *pair.second;
if (source.enabled) {
source.updateClipIDs(clipIDs);
}
for (const std::shared_ptr<Source> &source : style->getActiveSources()) {
source->updateClipIDs(clipIDs);
}
}
@@ -491,14 +479,13 @@ void Map::render() {
updateRenderState();
painter.drawClippingMasks(sources);
painter.drawClippingMasks(style->getActiveSources());
#if defined(DEBUG)
// Generate debug information
size_t source_id = 0;
for (const auto &pair : sources) {
const Source &source = *pair.second;
size_t count = source.getTileCount();
for (const std::shared_ptr<Source> &source : style->getActiveSources()) {
size_t count = source->getTileCount();
debug.emplace_back(util::sprintf<100>("source %d: %d\n", source_id, count));
source_id++;
}
@@ -512,11 +499,8 @@ void Map::render() {
// This guarantees that we have at least one function per tile called.
// When only rendering layers via the stylesheet, it's possible that we don't
// ever visit a tile during rendering.
for (const auto &pair : sources) {
Source &source = *pair.second;
const std::string &name = pair.first;
gl::group group(std::string("debug ") + name);
source.finishRender();
for (const std::shared_ptr<Source> &source : style->getActiveSources()) {
source->finishRender(painter);
}
painter.renderMatte();
@@ -533,9 +517,14 @@ void Map::render() {
glFlush();
}
void Map::renderLayers(const std::vector<LayerDescription>& layers) {
void Map::renderLayers(std::shared_ptr<StyleLayerGroup> layers) {
if (!layers) {
// Make sure that we actually do have a layer group.
return;
}
// TODO: Correctly compute the number of layers recursively beforehand.
float strata_thickness = 1.0f / (layers.size() + 1);
float strata_thickness = 1.0f / (layers->size() + 1);
// - FIRST PASS ------------------------------------------------------------
// Render everything top-to-bottom by using reverse iterators. Render opaque
@@ -544,9 +533,9 @@ void Map::renderLayers(const std::vector<LayerDescription>& layers) {
if (debug::renderTree) {
std::cout << std::string(indent++ * 4, ' ') << "OPAQUE {" << std::endl;
}
typedef std::vector<LayerDescription>::const_reverse_iterator riterator;
typedef std::vector<StyleLayer::Ptr>::reverse_iterator riterator;
int i = 0;
for (riterator it = layers.rbegin(), end = layers.rend(); it != end; ++it, ++i) {
for (riterator it = layers->rbegin(), end = layers->rend(); it != end; ++it, ++i) {
painter.setOpaque();
painter.setStrata(i * strata_thickness);
renderLayer(*it, Opaque);
@@ -561,9 +550,9 @@ void Map::renderLayers(const std::vector<LayerDescription>& layers) {
if (debug::renderTree) {
std::cout << std::string(indent++ * 4, ' ') << "TRANSLUCENT {" << std::endl;
}
typedef std::vector<LayerDescription>::const_iterator iterator;
typedef std::vector<StyleLayer::Ptr>::iterator iterator;
--i;
for (iterator it = layers.begin(), end = layers.end(); it != end; ++it, --i) {
for (iterator it = layers->begin(), end = layers->end(); it != end; ++it, --i) {
painter.setTranslucent();
painter.setStrata(i * strata_thickness);
renderLayer(*it, Translucent);
@@ -573,48 +562,22 @@ void Map::renderLayers(const std::vector<LayerDescription>& layers) {
}
}
template <typename Styles>
typename Styles::const_iterator find_style(const Styles &styles, const LayerDescription &layer_desc) {
auto it = styles.find(layer_desc.name);
#if defined(DEBUG)
if (it == styles.end()) {
if (debug::renderWarnings) {
fprintf(stderr, "[WARNING] can't find class named '%s' in style\n",
layer_desc.name.c_str());
}
}
#endif
return it;
}
template <typename Styles>
bool is_invisible(const Styles &styles, const LayerDescription &layer_desc) {
auto it = find_style(styles, layer_desc);
if (it == styles.end()) {
// We don't have a style, so we fall back to the default style which is
// always visible.
return false;
}
return !it->second.isVisible();
}
void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) {
if (layer_desc.child_layer.size()) {
void Map::renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass) {
if (layer_desc->layers) {
// This is a layer group. We render them during our translucent render pass.
if (pass == Translucent) {
auto it = find_style(style->computed.composites, layer_desc);
const CompositeProperties &properties = (it != style->computed.composites.end()) ? it->second : defaultCompositeProperties;
const CompositeProperties &properties = layer_desc->getProperties<CompositeProperties>();
if (properties.isVisible()) {
gl::group group(std::string("group: ") + layer_desc.name);
gl::group group(std::string("group: ") + layer_desc->id);
if (debug::renderTree) {
std::cout << std::string(indent++ * 4, ' ') << "+ " << layer_desc.name
std::cout << std::string(indent++ * 4, ' ') << "+ " << layer_desc->id
<< " (Composite) {" << std::endl;
}
painter.pushFramebuffer();
renderLayers(layer_desc.child_layer);
renderLayers(layer_desc->layers);
GLuint texture = painter.popFramebuffer();
@@ -626,63 +589,51 @@ void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) {
}
}
}
} else if (layer_desc.bucket_name == "background") {
} else if (layer_desc->id == "background") {
// This layer defines the background color.
} else {
// This is a singular layer. Try to find the bucket associated with
// this layer and render it.
auto bucket_it = style->buckets.find(layer_desc.bucket_name);
if (bucket_it != style->buckets.end()) {
const BucketDescription &bucket_desc = bucket_it->second;
// Abort early if we can already deduce from the bucket type that
// we're not going to render anything anyway during this pass.
switch (bucket_desc.type) {
case BucketType::Fill:
if (is_invisible(style->computed.fills, layer_desc)) return;
break;
case BucketType::Line:
if (pass == Opaque) return;
if (is_invisible(style->computed.lines, layer_desc)) return;
break;
case BucketType::Icon:
if (pass == Opaque) return;
if (is_invisible(style->computed.icons, layer_desc)) return;
break;
case BucketType::Text:
if (pass == Opaque) return;
if (is_invisible(style->computed.texts, layer_desc)) return;
break;
case BucketType::Raster:
if (pass == Translucent) return;
if (is_invisible(style->computed.rasters, layer_desc)) return;
break;
default:
break;
}
// Find the source and render all tiles in it.
auto source_it = sources.find(bucket_desc.source_name);
if (source_it != sources.end()) {
if (debug::renderTree) {
std::cout << std::string(indent * 4, ' ') << "- " << layer_desc.name << " ("
<< bucket_desc.type << ")" << std::endl;
}
const std::unique_ptr<Source> &source = source_it->second;
source->render(layer_desc, bucket_desc);
} else {
if (debug::renderWarnings) {
fprintf(stderr, "[WARNING] can't find source '%s' required for bucket '%s'\n",
bucket_desc.source_name.c_str(), layer_desc.bucket_name.c_str());
}
}
} else {
if (debug::renderWarnings) {
fprintf(stderr, "[WARNING] can't find bucket '%s' required for layer '%s'\n",
layer_desc.bucket_name.c_str(), layer_desc.name.c_str());
}
// This is a singular layer.
if (!layer_desc->bucket) {
fprintf(stderr, "[WARNING] layer '%s' is missing bucket\n", layer_desc->id.c_str());
return;
}
if (!layer_desc->bucket->source) {
fprintf(stderr, "[WARNING] can't find source for layer '%s'\n", layer_desc->id.c_str());
return;
}
// Abort early if we can already deduce from the bucket type that
// we're not going to render anything anyway during this pass.
switch (layer_desc->bucket->type) {
case BucketType::Fill:
if (!layer_desc->getProperties<FillProperties>().isVisible()) return;
break;
case BucketType::Line:
if (pass == Opaque) return;
if (!layer_desc->getProperties<LineProperties>().isVisible()) return;
break;
case BucketType::Icon:
if (pass == Opaque) return;
if (!layer_desc->getProperties<IconProperties>().isVisible()) return;
break;
case BucketType::Text:
if (pass == Opaque) return;
if (!layer_desc->getProperties<TextProperties>().isVisible()) return;
break;
case BucketType::Raster:
if (pass == Translucent) return;
if (!layer_desc->getProperties<RasterProperties>().isVisible()) return;
break;
default:
break;
}
if (debug::renderTree) {
std::cout << std::string(indent * 4, ' ') << "- " << layer_desc->id << " ("
<< layer_desc->bucket->type << ")" << std::endl;
}
layer_desc->bucket->source->render(painter, layer_desc);
}
}

View File

@@ -1,6 +1,6 @@
#include <llmr/map/map.hpp>
#include <llmr/map/raster_tile_data.hpp>
#include <llmr/style/layer_description.hpp>
#include <llmr/style/style.hpp>
using namespace llmr;
@@ -25,10 +25,10 @@ void RasterTileData::parse() {
}
}
void RasterTileData::render(Painter &painter, const LayerDescription& layer_desc) {
bucket.render(painter, layer_desc.name, id);
void RasterTileData::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc) {
bucket.render(painter, layer_desc, id);
}
bool RasterTileData::hasData(const LayerDescription& layer_desc) const {
bool RasterTileData::hasData(std::shared_ptr<StyleLayer> layer_desc) const {
return bucket.hasData();
}

View File

@@ -14,23 +14,33 @@
#include <llmr/map/vector_tile_data.hpp>
#include <llmr/map/raster_tile_data.hpp>
using namespace llmr;
namespace llmr {
Source::Source(Map &map, Painter &painter,
const char *url, Source::Type type, std::vector<uint32_t> zooms, uint32_t tile_size,
uint32_t min_zoom, uint32_t max_zoom, bool enabled)
: enabled(enabled),
map(map),
painter(painter),
type(type),
zooms(zooms),
url(url),
Source::Source(SourceType type, const std::string &url, const std::string &glyphs,
uint32_t tile_size, uint32_t min_zoom, uint32_t max_zoom)
: type(type),
url(normalizeSourceURL(url)),
glyphs(glyphs),
tile_size(tile_size),
min_zoom(min_zoom),
max_zoom(max_zoom) {}
bool Source::update() {
return updateTiles();
std::string Source::normalizeSourceURL(const std::string &url) {
const std::string t = "mapbox://";
if (url.compare(0, t.length(), t) == 0) {
return std::string("http://api.tiles.mapbox.com/v3/") + url.substr(t.length()) + "/%d/%d/%d.vector.pbf";
} else {
return url;
}
}
bool Source::update(Map &map) {
if (map.getTime() > updated) {
return updateTiles(map);
} else {
return false;
}
}
void Source::updateClipIDs(const std::map<Tile::ID, ClipID> &mapping) {
@@ -45,11 +55,11 @@ void Source::updateClipIDs(const std::map<Tile::ID, ClipID> &mapping) {
});
}
void Source::updateMatrices(const TransformState &transform) {
void Source::updateMatrices(const mat4 &projMatrix, const TransformState &transform) {
for (std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) {
Tile &tile = *pair.second;
transform.matrixFor(tile.matrix, tile.id);
matrix::multiply(tile.matrix, painter.projMatrix, tile.matrix);
matrix::multiply(tile.matrix, projMatrix, tile.matrix);
}
}
@@ -57,7 +67,7 @@ size_t Source::getTileCount() const {
return tiles.size();
}
void Source::drawClippingMasks() {
void Source::drawClippingMasks(Painter &painter) {
for (std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) {
Tile &tile = *pair.second;
gl::group group(util::sprintf<32>("mask %d/%d/%d", tile.id.z, tile.id.y, tile.id.z));
@@ -65,10 +75,8 @@ void Source::drawClippingMasks() {
}
}
void Source::render(const LayerDescription& layer_desc, const BucketDescription &bucket_desc) {
if (!enabled) return;
gl::group group(std::string("layer: ") + layer_desc.name);
void Source::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc) {
gl::group group(std::string("layer: ") + layer_desc->id);
for (const std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) {
Tile &tile = *pair.second;
if (tile.data && tile.data->state == TileData::State::parsed) {
@@ -77,9 +85,7 @@ void Source::render(const LayerDescription& layer_desc, const BucketDescription
}
}
void Source::finishRender() {
if (!enabled) return;
void Source::finishRender(Painter &painter) {
for (std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) {
Tile &tile = *pair.second;
painter.renderTileDebug(tile);
@@ -109,7 +115,7 @@ TileData::State Source::hasTile(const Tile::ID& id) {
return TileData::State::invalid;
}
TileData::State Source::addTile(const Tile::ID& id) {
TileData::State Source::addTile(Map &map, const Tile::ID& id) {
const TileData::State state = hasTile(id);
if (state != TileData::State::invalid) {
@@ -139,12 +145,14 @@ TileData::State Source::addTile(const Tile::ID& id) {
std::string formed_url;
if (type == Source::Type::vector) {
if (type == SourceType::Vector) {
formed_url = util::sprintf<256>(url, normalized_id.z, normalized_id.x, normalized_id.y);
new_tile.data = std::make_shared<VectorTileData>(normalized_id, map, formed_url);
} else {
} else if (type == SourceType::Raster) {
formed_url = util::sprintf<256>(url, normalized_id.z, normalized_id.x, normalized_id.y, (map.getState().getPixelRatio() > 1.0 ? "@2x" : ""));
new_tile.data = std::make_shared<RasterTileData>(normalized_id, map, formed_url);
} else {
throw std::runtime_error("source type not implemented");
}
new_tile.data->request();
@@ -205,27 +213,27 @@ bool Source::findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std::
return false;
}
bool Source::updateTiles() {
bool Source::updateTiles(Map &map) {
bool changed = false;
// Figure out what tiles we need to load
int32_t zoom = map.getState().getIntegerZoom();
if (zoom > max_zoom) zoom = max_zoom;
if (zoom < min_zoom) zoom = min_zoom;
int32_t clamped_zoom = map.getState().getIntegerZoom();
if (clamped_zoom > max_zoom) clamped_zoom = max_zoom;
if (clamped_zoom < min_zoom) clamped_zoom = min_zoom;
int32_t max_covering_zoom = zoom + 1;
int32_t max_covering_zoom = clamped_zoom + 1;
if (max_covering_zoom > max_zoom) max_covering_zoom = max_zoom;
int32_t min_covering_zoom = zoom - 10;
int32_t min_covering_zoom = clamped_zoom - 10;
if (min_covering_zoom < min_zoom) min_covering_zoom = min_zoom;
// Map four viewport corners to pixel coordinates
box box = map.getState().cornersToBox(zoom);
box box = map.getState().cornersToBox(clamped_zoom);
// Performs a scanline algorithm search that covers the rectangle of the box
// and sorts them by proximity to the center.
std::forward_list<Tile::ID> required = covering_tiles(zoom, box);
std::forward_list<Tile::ID> required = covering_tiles(map.getState(), clamped_zoom, box);
// Retain is a list of tiles that we shouldn't delete, even if they are not
// the most ideal tile for the current viewport. This may include tiles like
@@ -234,7 +242,7 @@ bool Source::updateTiles() {
// Add existing child/parent tiles if the actual tile is not yet loaded
for (const Tile::ID& id : required) {
const TileData::State state = addTile(id);
const TileData::State state = addTile(map, id);
if (state != TileData::State::parsed) {
// if (use_raster && (transform.rotating || transform.scaling || transform.panning))
@@ -289,6 +297,8 @@ bool Source::updateTiles() {
}
});
updated = map.getTime();
return changed;
}
@@ -354,30 +364,30 @@ void _scanTriangle(const llmr::vec2<double> a, const llmr::vec2<double> b, const
if (bc.dy) _scanSpans(ca, bc, ymin, ymax, scanLine);
}
double Source::getZoom() const {
double Source::getZoom(const TransformState &state) const {
double offset = log(util::tileSize / tile_size) / log(2);
offset += (map.getState().getPixelRatio() > 1.0 ? 1 :0);
return map.getState().getZoom() + offset;
offset += (state.getPixelRatio() > 1.0 ? 1 :0);
return state.getZoom() + offset;
}
std::forward_list<llmr::Tile::ID> Source::covering_tiles(int32_t zoom, const box& points) {
int32_t dim = std::pow(2, zoom);
std::forward_list<llmr::Tile::ID> Source::covering_tiles(const TransformState &state, int32_t clamped_zoom, const box& points) {
int32_t dim = std::pow(2, clamped_zoom);
std::forward_list<llmr::Tile::ID> tiles;
bool is_raster = (type == Type::raster);
double search_zoom = getZoom();
bool is_raster = (type == SourceType::Raster);
double search_zoom = getZoom(state);
auto scanLine = [&tiles, zoom, is_raster, search_zoom](int32_t x0, int32_t x1, int32_t y, int32_t ymax) {
auto scanLine = [&tiles, clamped_zoom, is_raster, search_zoom](int32_t x0, int32_t x1, int32_t y, int32_t ymax) {
int32_t x;
if (y >= 0 && y <= ymax) {
for (x = x0; x < x1; x++) {
if (is_raster) {
Tile::ID id = Tile::ID(zoom, x, y);
Tile::ID id = Tile::ID(clamped_zoom, x, y);
auto ids = id.children(search_zoom);
for (const Tile::ID& child_id : ids) {
tiles.emplace_front(child_id.z, child_id.x, child_id.y);
}
} else {
tiles.emplace_front(zoom, x, y);
tiles.emplace_front(clamped_zoom, x, y);
}
}
}
@@ -401,3 +411,5 @@ std::forward_list<llmr::Tile::ID> Source::covering_tiles(int32_t zoom, const box
return tiles;
}
}

View File

@@ -62,72 +62,74 @@ void TileParser::addGlyph(uint64_t tileid, const std::string stackname,
}
}
void TileParser::parseStyleLayers(const std::vector<LayerDescription> &layers) {
for (const LayerDescription &layer_desc : layers) {
void TileParser::parseStyleLayers(std::shared_ptr<StyleLayerGroup> layers) {
if (!layers) {
return;
}
for (const std::shared_ptr<StyleLayer> &layer_desc : *layers) {
// Cancel early when parsing.
if (obsolete()) {
return;
}
if (layer_desc.bucket_name == "background") {
if (layer_desc->id == "background") {
// background is a special, fake bucket
continue;
}
if (layer_desc.child_layer.size()) {
} else if (layer_desc->layers) {
// This is a layer group.
// TODO: create framebuffer
parseStyleLayers(layer_desc.child_layer);
// TODO: render framebuffer on previous framebuffer
} else {
parseStyleLayers(layer_desc->layers);
} else if (layer_desc->bucket) {
// This is a singular layer. Check if this bucket already exists. If not,
// parse this bucket.
auto bucket_it = tile.buckets.find(layer_desc.bucket_name);
auto bucket_it = tile.buckets.find(layer_desc->bucket->name);
if (bucket_it == tile.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::unique_ptr<Bucket> bucket = createBucket(bucket_it->second);
if (bucket) {
// Bucket creation might fail because the data tile may not
// contain any data that falls into this bucket.
tile.buckets[layer_desc.bucket_name] = std::move(bucket);
}
} else {
// There is no proper specification for this bucket, even though
// it is referenced in the stylesheet.
if (debug::tileParseWarnings) {
fprintf(stderr, "Stylesheet specifies bucket %s, but it is not defined\n",
layer_desc.bucket_name.c_str());
}
// We need to create this bucket since it doesn't exist yet.
std::unique_ptr<Bucket> bucket = createBucket(layer_desc->bucket);
if (bucket) {
// Bucket creation might fail because the data tile may not
// contain any data that falls into this bucket.
tile.buckets[layer_desc->bucket->name] = std::move(bucket);
}
}
} else {
fprintf(stderr, "[WARNING] layer does not have child layers or buckets\n");
}
}
}
std::unique_ptr<Bucket> TileParser::createBucket(const BucketDescription &bucket_desc) {
auto layer_it = vector_data.layers.find(bucket_desc.source_layer);
std::unique_ptr<Bucket> TileParser::createBucket(std::shared_ptr<StyleBucket> bucket_desc) {
if (!bucket_desc) {
fprintf(stderr, "missing bucket desc\n");
return nullptr;
}
auto layer_it = vector_data.layers.find(bucket_desc->source_layer);
if (layer_it != vector_data.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::Icon) {
return createIconBucket(layer, bucket_desc);
} else if (bucket_desc.type == BucketType::Text) {
return createTextBucket(layer, bucket_desc);
if (bucket_desc->render.is<StyleBucketFill>()) {
fprintf(stderr, "create fill bucket\n");
return createFillBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketFill>());
} else if (bucket_desc->render.is<StyleBucketLine>()) {
fprintf(stderr, "create line bucket\n");
return createLineBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketLine>());
} else if (bucket_desc->render.is<StyleBucketIcon>()) {
fprintf(stderr, "create icon bucket\n");
return createIconBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketIcon>());
} else if (bucket_desc->render.is<StyleBucketText>()) {
fprintf(stderr, "create text bucket\n");
return createTextBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketText>());
} else if (bucket_desc->render.is<StyleBucketRaster>()) {
fprintf(stderr, "create raster bucket\n");
return nullptr;
} else {
throw std::runtime_error("unknown bucket type");
fprintf(stderr, "[WARNING] unknown bucket render type for layer '%s'\n", bucket_desc->source_layer.c_str());
}
} else {
// The layer specified in the bucket does not exist. Do nothing.
if (debug::tileParseWarnings) {
fprintf(stderr, "[WARNING] layer '%s' does not exist in tile %d/%d/%d of source '%s'\n",
bucket_desc.source_layer.c_str(), tile.id.z, tile.id.x, tile.id.y,
bucket_desc.source_name.c_str());
fprintf(stderr, "[WARNING] layer '%s' does not exist in tile %d/%d/%d\n",
bucket_desc->source_layer.c_str(), tile.id.z, tile.id.x, tile.id.y);
}
}
@@ -135,9 +137,8 @@ std::unique_ptr<Bucket> TileParser::createBucket(const BucketDescription &bucket
}
template <class Bucket>
void TileParser::addBucketFeatures(Bucket &bucket, const VectorTileLayer &layer,
const BucketDescription &bucket_desc) {
FilteredVectorTileLayer filtered_layer(layer, bucket_desc);
void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter) {
FilteredVectorTileLayer filtered_layer(layer, filter);
for (pbf feature : filtered_layer) {
if (obsolete())
return;
@@ -154,64 +155,38 @@ void TileParser::addBucketFeatures(Bucket &bucket, const VectorTileLayer &layer,
}
template <class Bucket, typename... Args>
void TileParser::addBucketFeatures(Bucket &bucket, const VectorTileLayer &layer,
const BucketDescription &bucket_desc, Args &&... args) {
FilteredVectorTileLayer filtered_layer(layer, bucket_desc);
void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter, Args&& ...args) {
FilteredVectorTileLayer filtered_layer(layer, filter);
for (const pbf &feature_pbf : filtered_layer) {
if (obsolete())
if (obsolete()) {
return;
}
bucket->addFeature({feature_pbf, layer}, std::forward<Args>(args)...);
}
}
std::unique_ptr<Bucket> TileParser::createFillBucket(const VectorTileLayer &layer,
const BucketDescription &bucket_desc) {
if (!bucket_desc.render.valid() || !bucket_desc.render.is<BucketFillDescription>()) {
return nullptr;
}
std::unique_ptr<FillBucket> bucket = std::make_unique<FillBucket>(
tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer,
bucket_desc.render.get<BucketFillDescription>());
addBucketFeatures(bucket, layer, bucket_desc);
std::unique_ptr<Bucket> TileParser::createFillBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketFill &fill) {
std::unique_ptr<FillBucket> bucket = std::make_unique<FillBucket>(tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer, fill);
addBucketFeatures(bucket, layer, filter);
return obsolete() ? nullptr : std::move(bucket);
}
std::unique_ptr<Bucket> TileParser::createLineBucket(const VectorTileLayer &layer,
const BucketDescription &bucket_desc) {
if (!bucket_desc.render.valid() || !bucket_desc.render.is<BucketLineDescription>()) {
return nullptr;
}
std::unique_ptr<LineBucket> bucket = std::make_unique<LineBucket>(
tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer,
bucket_desc.render.get<BucketLineDescription>());
addBucketFeatures(bucket, layer, bucket_desc);
std::unique_ptr<Bucket> TileParser::createLineBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketLine &line) {
std::unique_ptr<LineBucket> bucket = std::make_unique<LineBucket>(tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer, line);
addBucketFeatures(bucket, layer, filter);
return obsolete() ? nullptr : std::move(bucket);
}
std::unique_ptr<Bucket> TileParser::createIconBucket(const VectorTileLayer &layer,
const BucketDescription &bucket_desc) {
if (!bucket_desc.render.valid() || !bucket_desc.render.is<BucketIconDescription>()) {
return nullptr;
}
std::unique_ptr<IconBucket> bucket = std::make_unique<IconBucket>(
tile.iconVertexBuffer, bucket_desc.render.get<BucketIconDescription>());
addBucketFeatures(bucket, layer, bucket_desc, *spriteAtlas);
std::unique_ptr<Bucket> TileParser::createIconBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketIcon &icon) {
std::unique_ptr<IconBucket> bucket = std::make_unique<IconBucket>(tile.iconVertexBuffer, icon);
addBucketFeatures(bucket, layer, filter, *spriteAtlas);
return obsolete() ? nullptr : std::move(bucket);
}
typedef std::pair<uint16_t, uint16_t> GlyphRange;
std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketText &text) {
std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer &layer,
const BucketDescription &bucket_desc) {
if (!bucket_desc.render.valid() || !bucket_desc.render.is<BucketTextDescription>()) {
return nullptr;
}
const BucketTextDescription &properties = bucket_desc.render.get<BucketTextDescription>();
const StyleBucketText &properties = text;
std::unique_ptr<TextBucket> bucket = std::make_unique<TextBucket>(
tile.textVertexBuffer, tile.triangleElementsBuffer, properties, placement);
@@ -224,7 +199,7 @@ std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer &laye
{
std::set<GlyphRange> ranges;
FilteredVectorTileLayer filtered_layer(layer, bucket_desc);
FilteredVectorTileLayer filtered_layer(layer, filter);
for (const pbf &feature_pbf : filtered_layer) {
if (obsolete())
return nullptr;
@@ -234,7 +209,7 @@ std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer &laye
util::replaceTokens(properties.field, feature.properties));
// Loop through all characters of this text and collect unique codepoints.
for (uint32_t chr : string) {
for (char32_t chr : string) {
ranges.insert(getGlyphRange(chr));
}
@@ -265,3 +240,9 @@ std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer &laye
return std::move(bucket);
}
//typedef std::pair<uint16_t, uint16_t> GlyphRange;
//

View File

@@ -102,9 +102,9 @@ VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) {
}
}
FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const BucketDescription& bucket_desc)
FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression)
: layer(layer),
bucket_desc(bucket_desc) {
filterExpression(filterExpression) {
}
FilteredVectorTileLayer::iterator FilteredVectorTileLayer::begin() const {
@@ -193,7 +193,7 @@ bool FilteredVectorTileLayer::iterator::matchesExpression(const PropertyExpressi
void FilteredVectorTileLayer::iterator::operator++() {
valid = false;
const PropertyFilterExpression &expression = parent.bucket_desc.filter;
const PropertyFilterExpression &expression = parent.filterExpression;
while (data.next(2)) { // feature
feature = data.message();
@@ -203,7 +203,7 @@ void FilteredVectorTileLayer::iterator::operator++() {
bool matched = false;
// Treat the absence of any expression filters as a match.
if (expression.is<std::true_type>()) {
if (!expression.valid() || expression.is<std::true_type>()) {
matched = true;
}
@@ -228,10 +228,11 @@ void FilteredVectorTileLayer::iterator::operator++() {
default: type = BucketType::None; break;
}
if (type != parent.bucket_desc.feature_type) {
matched = false;
break; // feature_pbf loop early
}
// TODO: Parse feature type
// if (type != parent.bucket_desc.feature_type) {
// matched = false;
// break; // feature_pbf loop early
// }
} else {
feature_pbf.skip();
}

View File

@@ -9,7 +9,10 @@ VectorTileData::VectorTileData(Tile::ID id, Map &map, const std::string url)
}
VectorTileData::~VectorTileData() {
map.getGlyphAtlas()->removeGlyphs(id.to_uint64());
std::shared_ptr<GlyphAtlas> glyphAtlas = map.getGlyphAtlas();
if (glyphAtlas) {
glyphAtlas->removeGlyphs(id.to_uint64());
}
}
void VectorTileData::beforeParse() {
@@ -43,22 +46,23 @@ void VectorTileData::afterParse() {
parser.reset();
}
void VectorTileData::render(Painter &painter, const LayerDescription& layer_desc) {
auto databucket_it = buckets.find(layer_desc.bucket_name);
if (databucket_it != buckets.end()) {
assert(databucket_it->second);
databucket_it->second->render(painter, layer_desc.name, id);
void VectorTileData::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc) {
if (state == State::parsed && layer_desc->bucket) {
auto databucket_it = buckets.find(layer_desc->bucket->name);
if (databucket_it != buckets.end()) {
assert(databucket_it->second);
databucket_it->second->render(painter, layer_desc, id);
}
}
}
bool VectorTileData::hasData(const LayerDescription& layer_desc) const {
if (state != State::parsed) return false;
auto databucket_it = buckets.find(layer_desc.bucket_name);
if (databucket_it != buckets.end()) {
assert(databucket_it->second);
return databucket_it->second->hasData();
} else {
return false;
bool VectorTileData::hasData(std::shared_ptr<StyleLayer> layer_desc) const {
if (state == State::parsed && layer_desc->bucket) {
auto databucket_it = buckets.find(layer_desc->bucket->name);
if (databucket_it != buckets.end()) {
assert(databucket_it->second);
return databucket_it->second->hasData();
}
}
return false;
}

View File

@@ -14,7 +14,7 @@ DebugBucket::DebugBucket(DebugFontBuffer& fontBuffer)
: fontBuffer(fontBuffer) {
}
void DebugBucket::render(Painter& painter, const std::string& /*layer_name*/, const Tile::ID& /*id*/) {
void DebugBucket::render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& /*id*/) {
painter.renderDebugText(*this);
}

View File

@@ -33,7 +33,7 @@ void FillBucket::free(void *, void *ptr) {
FillBucket::FillBucket(FillVertexBuffer &vertexBuffer,
TriangleElementsBuffer &triangleElementsBuffer,
LineElementsBuffer &lineElementsBuffer,
const BucketFillDescription &properties)
const StyleBucketFill &properties)
: properties(properties),
allocator(new TESSalloc{&alloc, &realloc, &free, nullptr, // userData
64, // meshEdgeBucketSize
@@ -204,8 +204,8 @@ void FillBucket::tessellate() {
lineGroup.vertex_length += total_vertex_count;
}
void FillBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) {
painter.renderFill(*this, layer_name, id);
void FillBucket::render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
painter.renderFill(*this, layer_desc, id);
}
bool FillBucket::hasData() const {

View File

@@ -19,7 +19,7 @@ struct geometry_too_long_exception : std::exception {};
using namespace llmr;
IconBucket::IconBucket(IconVertexBuffer& vertexBuffer,
const BucketIconDescription& properties)
const StyleBucketIcon& properties)
: properties(properties),
vertexBuffer(vertexBuffer),
vertex_start(vertexBuffer.index()) {
@@ -57,8 +57,8 @@ void IconBucket::addFeature(const VectorTileFeature &feature, SpriteAtlas &sprit
vertex_end = vertexBuffer.index();
}
void IconBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) {
painter.renderIcon(*this, layer_name, id);
void IconBucket::render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
painter.renderIcon(*this, layer_desc, id);
}
bool IconBucket::hasData() const {

View File

@@ -20,7 +20,7 @@ using namespace llmr;
LineBucket::LineBucket(LineVertexBuffer& vertexBuffer,
TriangleElementsBuffer& triangleElementsBuffer,
PointElementsBuffer& pointElementsBuffer,
const BucketLineDescription& properties)
const StyleBucketLine& properties)
: properties(properties),
vertexBuffer(vertexBuffer),
triangleElementsBuffer(triangleElementsBuffer),
@@ -341,8 +341,8 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
}
}
void LineBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) {
painter.renderLine(*this, layer_name, id);
void LineBucket::render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
painter.renderLine(*this, layer_desc, id);
}
bool LineBucket::hasData() const {

View File

@@ -172,10 +172,10 @@ void Painter::prepareTile(const Tile& tile) {
glStencilFunc(GL_EQUAL, id, mask);
}
void Painter::renderTileLayer(const Tile& tile, const LayerDescription &layer_desc) {
void Painter::renderTileLayer(const Tile& tile, std::shared_ptr<StyleLayer> layer_desc) {
assert(tile.data);
if (tile.data->hasData(layer_desc)) {
gl::group group(util::sprintf<32>("render %d/%d/%d", tile.id.z, tile.id.y, tile.id.z));
gl::group group(util::sprintf<32>("render %d/%d/%d\n", tile.id.z, tile.id.y, tile.id.z));
prepareTile(tile);
tile.data->render(*this, layer_desc);
frameHistory.record(map.getAnimationTime(), map.getState().getNormalizedZoom());
@@ -183,14 +183,14 @@ void Painter::renderTileLayer(const Tile& tile, const LayerDescription &layer_de
}
const mat4 &Painter::translatedMatrix(const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchor anchor) {
const mat4 &Painter::translatedMatrix(const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchorType anchor) {
if (translation[0] == 0 && translation[1] == 0) {
return matrix;
} else {
// TODO: Get rid of the 8 (scaling from 4096 to tile size)
const double factor = ((double)(1 << id.z)) / map.getState().getScale() * (4096.0 / util::tileSize);
if (anchor == TranslateAnchor::Viewport) {
if (anchor == TranslateAnchorType::Viewport) {
const double sin_a = std::sin(-map.getState().getAngle());
const double cos_a = std::cos(-map.getState().getAngle());
matrix::translate(vtxMatrix, matrix,

View File

@@ -6,7 +6,7 @@
using namespace llmr;
void Painter::drawClippingMasks(const Sources &sources) {
void Painter::drawClippingMasks(const std::set<std::shared_ptr<Source>> &sources) {
gl::group group("clipping masks");
useProgram(plainShader->program);
@@ -15,22 +15,15 @@ void Painter::drawClippingMasks(const Sources &sources) {
glDepthRange(1.0f, 1.0f);
glStencilMask(0xFF);
const BackgroundProperties &properties = map.getStyle()->computed.background;
Color background = properties.color;
const float opacity = properties.opacity;
background[0] *= opacity;
background[1] *= opacity;
background[2] *= opacity;
background[3] *= opacity;
plainShader->setColor(background);
// std::shared_ptr<StyleLayer> background_layer = map.getStyle()->background;
// const BackgroundProperties &properties = background_layer ? background_layer->getProperties<BackgroundProperties>() : defaultStyleProperties<BackgroundProperties>();
const BackgroundProperties &properties = defaultStyleProperties<BackgroundProperties>();
plainShader->setColor(properties.color);
coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0));
for (const auto &pair : sources) {
Source &source = *pair.second;
if (source.enabled) {
source.drawClippingMasks();
}
for (const std::shared_ptr<Source> &source : sources) {
source->drawClippingMasks(*this);
}
glEnable(GL_DEPTH_TEST);

View File

@@ -63,6 +63,10 @@ void Painter::renderDebugFrame() {
}
void Painter::renderDebugText(const std::vector<std::string> &strings) {
if (strings.empty()) {
return;
}
gl::group group("debug text");
glDisable(GL_DEPTH_TEST);
@@ -78,20 +82,21 @@ void Painter::renderDebugText(const std::vector<std::string> &strings) {
line += 20;
}
// draw debug info
VertexArrayObject debugFontArray;
debugFontArray.bind(*plainShader, debugFontBuffer, BUFFER_OFFSET(0));
plainShader->setColor(1.0f, 1.0f, 1.0f, 1.0f);
lineWidth(4.0f * map.getState().getPixelRatio());
glDrawArrays(GL_LINES, 0, (GLsizei)debugFontBuffer.index());
#ifndef GL_ES_VERSION_2_0
glPointSize(2);
glDrawArrays(GL_POINTS, 0, (GLsizei)debugFontBuffer.index());
#endif
plainShader->setColor(0.0f, 0.0f, 0.0f, 1.0f);
lineWidth(2.0f * map.getState().getPixelRatio());
glDrawArrays(GL_LINES, 0, (GLsizei)debugFontBuffer.index());
if (!debugFontBuffer.empty()) {
// draw debug info
VertexArrayObject debugFontArray;
debugFontArray.bind(*plainShader, debugFontBuffer, BUFFER_OFFSET(0));
plainShader->setColor(1.0f, 1.0f, 1.0f, 1.0f);
lineWidth(4.0f * map.getState().getPixelRatio());
glDrawArrays(GL_LINES, 0, (GLsizei)debugFontBuffer.index());
#ifndef GL_ES_VERSION_2_0
glPointSize(2);
glDrawArrays(GL_POINTS, 0, (GLsizei)debugFontBuffer.index());
#endif
plainShader->setColor(0.0f, 0.0f, 0.0f, 1.0f);
lineWidth(2.0f * map.getState().getPixelRatio());
glDrawArrays(GL_LINES, 0, (GLsizei)debugFontBuffer.index());
}
glEnable(GL_DEPTH_TEST);
}

View File

@@ -140,65 +140,60 @@ void Painter::renderFill(FillBucket& bucket, const FillProperties& properties, c
}
}
void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, const Tile::ID& id) {
void Painter::renderFill(FillBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
// Abort early.
if (!bucket.hasData()) return;
const std::unordered_map<std::string, FillProperties> &fill_properties = map.getStyle()->computed.fills;
const std::unordered_map<std::string, FillProperties>::const_iterator fill_properties_it = fill_properties.find(layer_name);
const FillProperties &properties = fill_properties_it != fill_properties.end()
? fill_properties_it->second
: defaultFillProperties;
const FillProperties &properties = layer_desc->getProperties<FillProperties>();
if (!properties.enabled) return;
if (properties.prerender && properties.getPrerender(id.z)) {
if (pass == Translucent) {
// Buffer value around the 0..4096 extent that will be drawn into the 256x256 pixel
// texture. We later scale the texture so that the actual bounds will align with this
// tile's bounds. The reason we do this is so that the
if (!bucket.prerendered) {
const PrerenderProperties prerender = properties.getPrerenderProperties(id.z);
bucket.prerendered = std::make_unique<PrerenderedTexture>(prerender);
bucket.prerendered->bindFramebuffer();
preparePrerender(*bucket.prerendered);
const FillProperties modifiedProperties = [&]{
FillProperties modifiedProperties = properties;
modifiedProperties.opacity = 1;
return modifiedProperties;
}();
// When drawing the fill, we want to draw a buffer around too, so we
// essentially downscale everyting, and then upscale it later when rendering.
const int buffer = prerender.buffer * 4096.0f;
const mat4 vtxMatrix = [&]{
mat4 vtxMatrix;
matrix::ortho(vtxMatrix, -buffer, 4096 + buffer, -4096 - buffer, buffer, 0, 1);
matrix::translate(vtxMatrix, vtxMatrix, 0, -4096, 0);
return vtxMatrix;
}();
setOpaque();
renderFill(bucket, modifiedProperties, id, vtxMatrix);
setTranslucent();
renderFill(bucket, modifiedProperties, id, vtxMatrix);
if (prerender.blur > 0) {
bucket.prerendered->blur(*this, prerender.blur);
}
// RESET STATE
bucket.prerendered->unbindFramebuffer();
finishPrerender(*bucket.prerendered);
}
renderPrerenderedTexture(*bucket.prerendered, properties);
}
} else {
// if (properties.prerender && properties.getPrerender(id.z)) {
// if (pass == Translucent) {
// // Buffer value around the 0..4096 extent that will be drawn into the 256x256 pixel
// // texture. We later scale the texture so that the actual bounds will align with this
// // tile's bounds. The reason we do this is so that the
// if (!bucket.prerendered) {
// const PrerenderProperties prerender = properties.getPrerenderProperties(id.z);
// bucket.prerendered = std::make_unique<PrerenderedTexture>(prerender);
// bucket.prerendered->bindFramebuffer();
//
// preparePrerender(*bucket.prerendered);
//
// const FillProperties modifiedProperties = [&]{
// FillProperties modifiedProperties = properties;
// modifiedProperties.opacity = 1;
// return modifiedProperties;
// }();
//
// // When drawing the fill, we want to draw a buffer around too, so we
// // essentially downscale everyting, and then upscale it later when rendering.
// const int buffer = prerender.buffer * 4096.0f;
// const mat4 vtxMatrix = [&]{
// mat4 vtxMatrix;
// matrix::ortho(vtxMatrix, -buffer, 4096 + buffer, -4096 - buffer, buffer, 0, 1);
// matrix::translate(vtxMatrix, vtxMatrix, 0, -4096, 0);
// return vtxMatrix;
// }();
//
// setOpaque();
// renderFill(bucket, modifiedProperties, id, vtxMatrix);
//
// setTranslucent();
// renderFill(bucket, modifiedProperties, id, vtxMatrix);
//
// if (prerender.blur > 0) {
// bucket.prerendered->blur(*this, prerender.blur);
// }
//
// // RESET STATE
// bucket.prerendered->unbindFramebuffer();
// finishPrerender(*bucket.prerendered);
// }
//
// renderPrerenderedTexture(*bucket.prerendered, properties);
// }
// } else {
const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
renderFill(bucket, properties, id, vtxMatrix);
}
// }
}

View File

@@ -116,7 +116,7 @@ void Painter::pushFramebuffer() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glColorMask(false, false, false, false);
drawClippingMasks(map.getSources());
drawClippingMasks(map.getStyle()->getActiveSources());
glColorMask(true, true, true, true);
fbo_depth_stencil_valid = true;

View File

@@ -6,32 +6,23 @@
using namespace llmr;
void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, const Tile::ID& id) {
void Painter::renderIcon(IconBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
// Abort early.
if (!bucket.hasData()) return;
if (pass == Opaque) return;
const std::unordered_map<std::string, IconProperties> &icon_properties = map.getStyle()->computed.icons;
const std::unordered_map<std::string, IconProperties>::const_iterator icon_properties_it = icon_properties.find(layer_name);
const IconProperties &properties = icon_properties_it != icon_properties.end()
? icon_properties_it->second
: defaultIconProperties;
const IconProperties &properties = layer_desc->getProperties<IconProperties>();
if (!properties.enabled) return;
Color color = properties.color;
color[0] *= properties.opacity;
color[1] *= properties.opacity;
color[2] *= properties.opacity;
color[3] *= properties.opacity;
const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
// TODO: when translating icon, are we doing this in the bucket already?
// const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
SpriteAtlas &spriteAtlas = *map.getSpriteAtlas();
useProgram(iconShader->program);
iconShader->setMatrix(vtxMatrix);
iconShader->setColor(color);
// TODO: update
// iconShader->setColor(color);
iconShader->setImage(0);
iconShader->setRatio(map.getState().getPixelRatio());
iconShader->setDimension({{

View File

@@ -4,17 +4,12 @@
using namespace llmr;
void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& id) {
void Painter::renderLine(LineBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
// Abort early.
if (pass == Opaque) return;
if (!bucket.hasData()) return;
const std::unordered_map<std::string, LineProperties> &line_properties = map.getStyle()->computed.lines;
const std::unordered_map<std::string, LineProperties>::const_iterator line_properties_it = line_properties.find(layer_name);
const LineProperties &properties = line_properties_it != line_properties.end()
? line_properties_it->second
: defaultLineProperties;
const LineProperties &properties = layer_desc->getProperties<LineProperties>();
if (!properties.enabled) return;
float width = properties.width;

View File

@@ -23,21 +23,21 @@ void Painter::finishPrerender(PrerenderedTexture &texture) {
glViewport(0, 0, gl_viewport[0], gl_viewport[1]);
}
void Painter::renderPrerenderedTexture(PrerenderedTexture &texture, const GenericProperties &properties) {
const int buffer = texture.properties.buffer * 4096.0f;
// draw the texture on a quad
useProgram(rasterShader->program);
rasterShader->setMatrix(matrix);
rasterShader->setOpacity(1);
glDepthRange(strata, 1.0f);
glActiveTexture(GL_TEXTURE0);
rasterShader->setImage(0);
rasterShader->setBuffer(buffer);
rasterShader->setOpacity(properties.opacity);
texture.bindTexture();
coveringRasterArray.bind(*rasterShader, tileStencilBuffer, BUFFER_OFFSET(0));
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index());
}
//void Painter::renderPrerenderedTexture(PrerenderedTexture &texture, const GenericProperties &properties) {
// const int buffer = texture.properties.buffer * 4096.0f;
//
// // draw the texture on a quad
// useProgram(rasterShader->program);
// rasterShader->setMatrix(matrix);
// rasterShader->setOpacity(1);
//
// glDepthRange(strata, 1.0f);
//
// glActiveTexture(GL_TEXTURE0);
// rasterShader->setImage(0);
// rasterShader->setBuffer(buffer);
// rasterShader->setOpacity(properties.opacity);
// texture.bindTexture();
// coveringRasterArray.bind(*rasterShader, tileStencilBuffer, BUFFER_OFFSET(0));
// glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index());
//}

View File

@@ -4,15 +4,10 @@
using namespace llmr;
void Painter::renderRaster(RasterBucket& bucket, const std::string& layer_name, const Tile::ID& /*id*/) {
void Painter::renderRaster(RasterBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& /*id*/) {
if (pass == Translucent) return;
const std::unordered_map<std::string, RasterProperties> &raster_properties = map.getStyle()->computed.rasters;
const std::unordered_map<std::string, RasterProperties>::const_iterator raster_properties_it = raster_properties.find(layer_name);
const RasterProperties &properties = raster_properties_it != raster_properties.end()
? raster_properties_it->second
: defaultRasterProperties;
const RasterProperties &properties = layer_desc->getProperties<RasterProperties>();
if (!properties.enabled) return;
depthMask(false);

View File

@@ -5,17 +5,12 @@
using namespace llmr;
void Painter::renderText(TextBucket& bucket, const std::string& layer_name, const Tile::ID& id) {
void Painter::renderText(TextBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
// Abort early.
if (pass == Opaque) return;
if (!bucket.hasData()) return;
const std::unordered_map<std::string, TextProperties> &text_properties = map.getStyle()->computed.texts;
const std::unordered_map<std::string, TextProperties>::const_iterator text_properties_it = text_properties.find(layer_name);
const TextProperties &properties = text_properties_it != text_properties.end()
? text_properties_it->second
: defaultTextProperties;
const TextProperties &properties = layer_desc->getProperties<TextProperties>();
if (!properties.enabled) return;
mat4 exMatrix;
@@ -24,16 +19,13 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
matrix::rotate_z(exMatrix, exMatrix, map.getState().getAngle());
}
const float rotate = properties.rotate;
if (rotate != 0.0f) {
matrix::rotate_z(exMatrix, exMatrix, rotate);
}
// If layerStyle.size > bucket.info.fontSize then labels may collide
float fontSize = std::fmin(properties.size, bucket.properties.max_size);
matrix::scale(exMatrix, exMatrix, fontSize / 24.0f, fontSize / 24.0f, 1.0f);
const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
// TODO: figure out whether we actually need to account for this while painting; we might already have
// done this during label placement.
// const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
useProgram(textShader->program);
textShader->setMatrix(vtxMatrix);
@@ -45,7 +37,7 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
static_cast<float>(glyphAtlas.height)}});
// Convert the -pi..pi to an int8 range.
float angle = std::round((map.getState().getAngle() + rotate) / M_PI * 128);
float angle = std::round((map.getState().getAngle()) / M_PI * 128);
// adjust min/max zooms for variable font sies
float zoomAdjust = log(fontSize / bucket.properties.max_size) / log(2);
@@ -98,12 +90,12 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
// We're drawing in the translucent pass which is bottom-to-top, so we need
// to draw the halo first.
if (properties.halo[3] > 0.0f) {
if (properties.halo_color[3] > 0.0f) {
// TODO: Get rid of the 2.4 magic value. It is currently 24 / 10, with 24 being the font size
// of the SDF glyphs.
textShader->setGamma(properties.halo_blur * 2.4f / fontSize / map.getState().getPixelRatio());
textShader->setColor(properties.halo);
textShader->setBuffer(properties.halo_radius);
textShader->setColor(properties.halo_color);
textShader->setBuffer(properties.halo_width);
glDepthRange(strata, 1.0f);
bucket.drawGlyphs(*textShader);
}

View File

@@ -7,8 +7,8 @@ RasterBucket::RasterBucket(const std::shared_ptr<Texturepool> &texturepool)
: raster(texturepool) {
}
void RasterBucket::render(Painter &painter, const std::string &layer_name, const Tile::ID &id) {
painter.renderRaster(*this, layer_name, id);
void RasterBucket::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID &id) {
painter.renderRaster(*this, layer_desc, id);
}
bool RasterBucket::setImage(const std::string &data) {

View File

@@ -22,7 +22,7 @@ using namespace llmr;
TextBucket::TextBucket(
TextVertexBuffer &vertexBuffer,
TriangleElementsBuffer &triangleElementsBuffer,
const BucketTextDescription &properties, Placement &placement)
const StyleBucketText &properties, Placement &placement)
: properties(properties),
vertexBuffer(vertexBuffer),
triangleElementsBuffer(triangleElementsBuffer),
@@ -124,9 +124,9 @@ void TextBucket::addFeature(const pbf &geom_pbf,
}
}
void TextBucket::render(Painter &painter, const std::string &layer_name,
void TextBucket::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc,
const Tile::ID &id) {
painter.renderText(*this, layer_name, id);
painter.renderText(*this, layer_desc, id);
}
bool TextBucket::hasData() const {

View File

@@ -3,20 +3,20 @@
#include <iostream>
using namespace llmr;
size_t LayerDescription::size() const {
size_t count = 1;
for (const LayerDescription &layer : child_layer) {
count += layer.size();
}
return count;
}
std::ostream& llmr::operator<<(std::ostream& os, const LayerDescription& layer) {
os << "Structure: " << layer.name << std::endl;
os << " - bucket_name: " << layer.bucket_name << std::endl;
for (const LayerDescription& value : layer.child_layer) {
os << " - child_layer: " << value << std::endl;
}
return os;
}
//
//size_t LayerDescription::size() const {
// size_t count = 1;
// for (const LayerDescription &layer : child_layer) {
// count += layer.size();
// }
// return count;
//}
//
//std::ostream& llmr::operator<<(std::ostream& os, const LayerDescription& layer) {
// os << "Structure: " << layer.name << std::endl;
// os << " - bucket_name: " << layer.bucket_name << std::endl;
// for (const LayerDescription& value : layer.child_layer) {
// os << " - child_layer: " << value << std::endl;
// }
// return os;
//}

View File

@@ -5,8 +5,7 @@
#include <cassert>
#include <cmath>
using namespace llmr;
namespace llmr {
float functions::null(float, const std::vector<float>&) {
return 0;
@@ -86,3 +85,13 @@ float functions::exponential(float z, const std::vector<float>& values) {
return std::fmin(std::fmax(min, val + std::pow(1.75, (z - z_base)) * slope), max);
}
template<> const FillProperties &defaultStyleProperties() { static const FillProperties p; return p; }
template<> const LineProperties &defaultStyleProperties() { static const LineProperties p; return p; }
template<> const IconProperties &defaultStyleProperties() { static const IconProperties p; return p; }
template<> const TextProperties &defaultStyleProperties() { static const TextProperties p; return p; }
template<> const CompositeProperties &defaultStyleProperties() { static const CompositeProperties p; return p; }
template<> const RasterProperties &defaultStyleProperties() { static const RasterProperties p; return p; }
template<> const BackgroundProperties &defaultStyleProperties() { static const BackgroundProperties p; return p; }
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ namespace llmr {
// Note: we could use a binary lookup table to get averaged constant time lookups, however,
// most of our lookups are going to be within the first 3 ranges listed here, so this is
// likely faster.
GlyphRange getGlyphRange(uint32_t glyph) {
GlyphRange getGlyphRange(char32_t glyph) {
unsigned start = (glyph/256) * 256;
unsigned end = (start + 255);
if (start > 65280) start = 65280;

View File

@@ -245,7 +245,7 @@ void getGlyphs(PlacedGlyphs &glyphs, GlyphBoxes &boxes,
}
void Placement::addFeature(TextBucket &bucket, const std::vector<Coordinate> &line,
const BucketTextDescription &info, const GlyphPositions &face,
const StyleBucketText &info, const GlyphPositions &face,
const Shaping &shaping) {
const bool horizontal = info.path == TextPathType::Horizontal;
const float fontScale = (tileExtent / util::tileSize) / (glyphSize / info.max_size);