From 7c03f89079a5db04d948c0f65551a310a3c34884 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Jul 2014 11:41:29 -0700 Subject: [PATCH 01/11] fix up access token docs for Xcode --- README.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e642468a3..b69166aed 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,12 @@ This will clear cached build data and update to the latest versions of dependenc The demo applications use Mapbox vector tiles, which **require a Mapbox account and API access token**. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/account/apps/). +For iOS and OS X use of the demo apps in Xcode, setup the access token by editing the scheme for the application target, then adding an environment variable with the name `MAPBOX_ACCESS_TOKEN`. + +![setting access token in Xcode scheme](https://cloud.githubusercontent.com/assets/52399/3543326/9e7cfbb8-0860-11e4-8def-3684a9028b61.png) + ## OS X -in the Xcode project, click on the Target icon next to the Run/Stop button, and then "Edit Scheme". In the screen, add an environment variable with the name `MAPBOX_ACCESS_TOKEN` to the targets you want to run. - -![Setting the access token](https://cloud.githubusercontent.com/assets/52399/3543326/9e7cfbb8-0860-11e4-8def-3684a9028b61.png) - - Run: make setup @@ -61,8 +60,6 @@ First, pull down the submodule(s): git submodule init git submodule update -Insert your access token into `MBXViewController.h`. - Then run: make setup From ab472ed8bb54d181989a1f07e639a9841cbe7145 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Jul 2014 12:16:46 -0700 Subject: [PATCH 02/11] simplify OS X access token use --- macosx/main.mm | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/macosx/main.mm b/macosx/main.mm index f72476cde..e12103f35 100644 --- a/macosx/main.mm +++ b/macosx/main.mm @@ -17,12 +17,9 @@ int main() { map.setDebug(settings.debug); // Set access token if present - const char *token = getenv("MAPBOX_ACCESS_TOKEN"); - if (token == nullptr) { - llmr::Log::Warning(llmr::Event::Setup, "no access token set. mapbox.com tiles won't work."); - } else { - map.setAccessToken(std::string(token)); - } + NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"]; + if ( ! accessToken) llmr::Log::Warning(llmr::Event::Setup, "No access token set. Mapbox vector tiles won't work."); + if (accessToken) map.setAccessToken([accessToken cStringUsingEncoding:[NSString defaultCStringEncoding]]); // Load style NSString *path = [[NSBundle mainBundle] pathForResource:@"style.min" ofType:@"js"]; From 8b775573c190740ffa46c70f18c105debb8158ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 14 Jul 2014 15:01:13 -0700 Subject: [PATCH 03/11] move std::erase_if => util::erase_if --- include/llmr/util/std.hpp | 5 +++++ src/geometry/sprite_atlas.cpp | 2 +- src/map/map.cpp | 1 + src/map/source.cpp | 4 ++-- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/llmr/util/std.hpp b/include/llmr/util/std.hpp index c09aa5ff6..fad3380bc 100644 --- a/include/llmr/util/std.hpp +++ b/include/llmr/util/std.hpp @@ -11,6 +11,10 @@ template return ::std::unique_ptr(new T(::std::forward(args)...)); } +} + +namespace llmr { +namespace util { template void erase_if(Container &container, ForwardIterator it, const ForwardIterator end, Predicate pred) { @@ -28,6 +32,7 @@ void erase_if(Container &container, Predicate pred) { erase_if(container, container.begin(), container.end(), pred); } +} } #endif diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp index d76f24ebd..8a055e5a6 100644 --- a/src/geometry/sprite_atlas.cpp +++ b/src/geometry/sprite_atlas.cpp @@ -228,7 +228,7 @@ void SpriteAtlas::update(const Sprite &sprite) { if (!sprite.isLoaded()) return; SpriteAtlas &atlas = *this; - std::erase_if(uninitialized, [&sprite, &atlas](const std::string &name) { + util::erase_if(uninitialized, [&sprite, &atlas](const std::string &name) { Rect dst = atlas.getImage(name, sprite); const SpritePosition &src = sprite.getSpritePosition(name); if (!src) { diff --git a/src/map/map.cpp b/src/map/map.cpp index 3443cf78e..899b9534f 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/src/map/source.cpp b/src/map/source.cpp index cf5a273b0..55a2bea4e 100644 --- a/src/map/source.cpp +++ b/src/map/source.cpp @@ -284,7 +284,7 @@ bool Source::updateTiles(Map &map) { // Remove tiles that we definitely don't need, i.e. tiles that are not on // the required list. std::set retain_data; - std::erase_if(tiles, [&retain, &retain_data, &changed](std::pair> &pair) { + util::erase_if(tiles, [&retain, &retain_data, &changed](std::pair> &pair) { Tile &tile = *pair.second; bool obsolete = std::find(retain.begin(), retain.end(), tile.id) == retain.end(); if (obsolete) { @@ -296,7 +296,7 @@ bool Source::updateTiles(Map &map) { }); // Remove all the expired pointers from the set. - std::erase_if(tile_data, [&retain_data](std::pair> &pair) { + util::erase_if(tile_data, [&retain_data](std::pair> &pair) { const std::shared_ptr tile = pair.second.lock(); if (!tile) { return true; From d91aa9c7e2d77290dba79c7d15157858f84b38af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 14 Jul 2014 15:01:32 -0700 Subject: [PATCH 04/11] don't initialize sources multiple times --- include/llmr/map/map.hpp | 4 +-- include/llmr/renderer/painter.hpp | 3 +- include/llmr/style/style_bucket.hpp | 1 - include/llmr/style/style_source.hpp | 19 +++++++---- src/map/map.cpp | 52 +++++++++++++++++++++-------- src/renderer/painter_clipping.cpp | 6 ++-- 6 files changed, 57 insertions(+), 28 deletions(-) diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index 649acfa69..af4250c35 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -52,7 +52,7 @@ public: void resize(uint16_t width, uint16_t height, float ratio, uint16_t fb_width, uint16_t fb_height); // Styling - const std::set> getActiveSources() const; + const std::set> getActiveSources() const; void setAppliedClasses(const std::vector &classes); void toggleClass(const std::string &name); const std::vector &getAppliedClasses() const; @@ -178,7 +178,7 @@ private: int indent = 0; - std::set> activeSources; + std::set> activeSources; private: bool async = false; diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index a465f657f..ef160eddd 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -34,6 +34,7 @@ class Style; class Tile; class GlyphAtlas; class Source; +class StyleSource; class FillBucket; class LineBucket; @@ -106,7 +107,7 @@ public: // Configures the painter strata that is used for early z-culling of fragments. void setStrata(float strata); - void drawClippingMasks(const std::set> &sources); + void drawClippingMasks(const std::set> &sources); void drawClippingMask(const mat4& matrix, const ClipID& clip); void clearFramebuffers(); diff --git a/include/llmr/style/style_bucket.hpp b/include/llmr/style/style_bucket.hpp index 0f3824211..5d8c9d6bb 100644 --- a/include/llmr/style/style_bucket.hpp +++ b/include/llmr/style/style_bucket.hpp @@ -76,7 +76,6 @@ public: std::string name; std::shared_ptr style_source; - std::shared_ptr source; std::string source_layer; FilterExpression filter; StyleBucketRender render = std::false_type(); diff --git a/include/llmr/style/style_source.hpp b/include/llmr/style/style_source.hpp index cf55e94be..e7b742abb 100644 --- a/include/llmr/style/style_source.hpp +++ b/include/llmr/style/style_source.hpp @@ -5,14 +5,19 @@ namespace llmr { -struct StyleSource { - const SourceType type; - const std::string url; - const uint32_t tile_size; - const int32_t min_zoom; - const int32_t max_zoom; +class Source; - StyleSource(SourceType type = SourceType::Vector, +struct StyleSource { + const SourceType type; + const std::string url; + const uint32_t tile_size; + const int32_t min_zoom; + const int32_t max_zoom; + + bool enabled = false; + std::shared_ptr source; + + StyleSource(SourceType type = SourceType::Vector, const std::string &url = "", uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 22) diff --git a/src/map/map.cpp b/src/map/map.cpp index 899b9534f..68db66370 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -411,11 +411,32 @@ void Map::setDefaultTransitionDuration(uint64_t duration_milliseconds) { } void Map::updateSources() { - activeSources.clear(); + // First, disable all existing sources. + for (const std::shared_ptr &source : activeSources) { + source->enabled = false; + } + + // Then, reenable all of those that we actually use when drawing this layer. updateSources(style->layers); + + // Then, construct or destroy the actual source object, depending on enabled state. + for (const std::shared_ptr &source : activeSources) { + if (source->enabled) { + if (!source->source) { + source->source = std::make_shared(*source, getAccessToken()); + } + } else { + source->source.reset(); + } + } + + // Finally, remove all sources that are disabled. + util::erase_if(activeSources, [](std::shared_ptr source){ + return !source->enabled; + }); } -const std::set> Map::getActiveSources() const { +const std::set> Map::getActiveSources() const { return activeSources; } @@ -427,8 +448,7 @@ void Map::updateSources(const std::shared_ptr &group) { if (!layer) continue; if (layer->bucket) { if (layer->bucket->style_source) { - auto ret = activeSources.emplace(std::make_shared(*layer->bucket->style_source, this->getAccessToken())); - layer->bucket->source = *ret.first; + (*activeSources.emplace(layer->bucket->style_source).first)->enabled = true; } } else if (layer->layers) { updateSources(layer->layers); @@ -437,23 +457,23 @@ void Map::updateSources(const std::shared_ptr &group) { } void Map::updateTiles() { - for (const std::shared_ptr &source : getActiveSources()) { - source->update(*this); + for (const std::shared_ptr &source : getActiveSources()) { + source->source->update(*this); } } void Map::updateRenderState() { std::forward_list ids; - for (const std::shared_ptr &source : getActiveSources()) { - ids.splice_after(ids.before_begin(), source->getIDs()); - source->updateMatrices(painter.projMatrix, state); + for (const std::shared_ptr &source : getActiveSources()) { + ids.splice_after(ids.before_begin(), source->source->getIDs()); + source->source->updateMatrices(painter.projMatrix, state); } const std::map clipIDs = computeClipIDs(ids); - for (const std::shared_ptr &source : getActiveSources()) { - source->updateClipIDs(clipIDs); + for (const std::shared_ptr &source : getActiveSources()) { + source->source->updateClipIDs(clipIDs); } } @@ -532,8 +552,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 std::shared_ptr &source : getActiveSources()) { - source->finishRender(painter); + for (const std::shared_ptr &source : getActiveSources()) { + source->source->finishRender(painter); } painter.renderMatte(); @@ -630,6 +650,8 @@ void Map::renderLayer(std::shared_ptr layer_desc, RenderPass pass) { return; } + StyleSource &style_source = *layer_desc->bucket->style_source; + // 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->type) { @@ -661,6 +683,8 @@ void Map::renderLayer(std::shared_ptr layer_desc, RenderPass pass) { << layer_desc->type << ")" << std::endl; } - layer_desc->bucket->source->render(painter, layer_desc); + if (style_source.source) { + style_source.source->render(painter, layer_desc); + } } } diff --git a/src/renderer/painter_clipping.cpp b/src/renderer/painter_clipping.cpp index 95e4b727f..25fe0658f 100644 --- a/src/renderer/painter_clipping.cpp +++ b/src/renderer/painter_clipping.cpp @@ -6,7 +6,7 @@ using namespace llmr; -void Painter::drawClippingMasks(const std::set> &sources) { +void Painter::drawClippingMasks(const std::set> &sources) { gl::group group("clipping masks"); useProgram(plainShader->program); @@ -18,8 +18,8 @@ void Painter::drawClippingMasks(const std::set> &sources coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0)); - for (const std::shared_ptr &source : sources) { - source->drawClippingMasks(*this); + for (const std::shared_ptr &source : sources) { + source->source->drawClippingMasks(*this); } glEnable(GL_DEPTH_TEST); From af9293a65b7d29ebe7eec9d4446bd90d283b65af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 14 Jul 2014 15:09:05 -0700 Subject: [PATCH 05/11] fix includes --- include/llmr/style/style_source.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/llmr/style/style_source.hpp b/include/llmr/style/style_source.hpp index e7b742abb..a368e4fd7 100644 --- a/include/llmr/style/style_source.hpp +++ b/include/llmr/style/style_source.hpp @@ -3,6 +3,8 @@ #include +#include + namespace llmr { class Source; From 37bb2ff0484bbac6bc23bd4be40d5006f74ed7c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 14 Jul 2014 15:31:39 -0700 Subject: [PATCH 06/11] don't force Testing build on linux [skip ci] --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 70d706afa..cbc00c8ea 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ xtest: config.gypi clear_xcode_cache node # Builds the linux app with make. This is also used by Travis CI linux: config.gypi linux/llmr-app.gyp node deps/run_gyp linux/llmr-app.gyp --depth=. -Goutput_dir=.. --generator-output=./build/linux -f make - $(MAKE) -C build/linux BUILDTYPE=Testing V=$(V) linuxapp + $(MAKE) -C build/linux BUILDTYPE=$(BUILDTYPE) V=$(V) linuxapp # Executes the Linux binary run-linux: linux From bdc97d55d28dc07da944fdde065b9e00edd6d6c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 14 Jul 2014 16:33:02 -0700 Subject: [PATCH 07/11] add enum class to unify parsing/stringification --- common/nslog_log.mm | 8 ++-- common/stderr_log.hpp | 8 ++-- include/llmr/platform/event.hpp | 28 ++++++++++---- include/llmr/style/style_source.hpp | 17 +++----- include/llmr/style/types.hpp | 16 ++++++-- include/llmr/util/enum.hpp | 55 ++++++++++++++++++++++++++ src/platform/event.cpp | 60 ----------------------------- src/shader/shader.cpp | 1 + src/style/style_parser.cpp | 2 +- src/style/types.cpp | 35 ----------------- test/enums.cpp | 43 +++++++++++++++++++++ test/headless.cpp | 16 ++++---- test/test.gyp | 17 ++++++++ 13 files changed, 173 insertions(+), 133 deletions(-) create mode 100644 include/llmr/util/enum.hpp delete mode 100644 src/platform/event.cpp create mode 100644 test/enums.cpp diff --git a/common/nslog_log.mm b/common/nslog_log.mm index 76f7ac42c..c6ca65d0b 100644 --- a/common/nslog_log.mm +++ b/common/nslog_log.mm @@ -7,7 +7,7 @@ namespace llmr { void NSLogBackend::record(EventSeverity severity, Event event, const std::string &msg) { - NSLog(@"[%s] %s: %@", stringifyEventSeverity(severity), stringifyEvent(event), + NSLog(@"[%s] %s: %@", EventSeverityClass(severity).c_str(), EventClass(event).c_str(), [[NSString alloc] initWithBytes:msg.data() length:msg.size() encoding:NSUTF8StringEncoding]); @@ -23,15 +23,15 @@ void NSLogBackend::record(EventSeverity severity, Event event, const char* forma va_start(args, format); vsnprintf(buffer.get(), len + 1, format, args); va_end(args); - NSLog(@"[%s] %s: %s", stringifyEventSeverity(severity), stringifyEvent(event), buffer.get()); + NSLog(@"[%s] %s: %s", EventSeverityClass(severity).c_str(), EventClass(event).c_str(), buffer.get()); } void NSLogBackend::record(EventSeverity severity, Event event, int64_t code) { - NSLog(@"[%s] %s: (%lld)", stringifyEventSeverity(severity), stringifyEvent(event), code); + NSLog(@"[%s] %s: (%lld)", EventSeverityClass(severity).c_str(), EventClass(event).c_str(), code); } void NSLogBackend::record(EventSeverity severity, Event event, int64_t code, const std::string &msg) { - NSLog(@"[%s] %s: (%lld) %@", stringifyEventSeverity(severity), stringifyEvent(event), code, + NSLog(@"[%s] %s: (%lld) %@", EventSeverityClass(severity).c_str(), EventClass(event).c_str(), code, [[NSString alloc] initWithBytes:msg.data() length:msg.size() encoding:NSUTF8StringEncoding]); diff --git a/common/stderr_log.hpp b/common/stderr_log.hpp index e2492d3af..43d1b41c2 100644 --- a/common/stderr_log.hpp +++ b/common/stderr_log.hpp @@ -9,10 +9,10 @@ class StderrLogBackend : public LogBackend { public: inline ~StderrLogBackend() = default; - void record(EventSeverity severity, Event event, const std::string &msg); - void record(EventSeverity severity, Event event, const char* format, ...); - void record(EventSeverity severity, Event event, int64_t code); - void record(EventSeverity severity, Event event, int64_t code, const std::string &msg); + void record(EventSeverityClass severity, EventClass event, const std::string &msg); + void record(EventSeverityClass severity, EventClass event, const char* format, ...); + void record(EventSeverityClass severity, EventClass event, int64_t code); + void record(EventSeverityClass severity, EventClass event, int64_t code, const std::string &msg); }; diff --git a/include/llmr/platform/event.hpp b/include/llmr/platform/event.hpp index c1552b1c6..133cfc3c5 100644 --- a/include/llmr/platform/event.hpp +++ b/include/llmr/platform/event.hpp @@ -1,8 +1,9 @@ #ifndef LLMR_PLATFORM_EVENT #define LLMR_PLATFORM_EVENT +#include + #include -#include namespace llmr { @@ -14,9 +15,14 @@ enum class EventSeverity : uint8_t { Error, }; -EventSeverity parseEventSeverity(const char *name); -const char *stringifyEventSeverity(EventSeverity eventSeverity); -::std::ostream& operator<<(::std::ostream& os, EventSeverity eventSeverity); +LLMR_DEFINE_ENUM_CLASS(EventSeverityClass, EventSeverity, { + { EventSeverity::Debug, "DEBUG" }, + { EventSeverity::Info, "INFO" }, + { EventSeverity::Test, "TEST" }, + { EventSeverity::Warning, "WARNING" }, + { EventSeverity::Error, "ERROR" }, + { EventSeverity(-1), "UNKNOWN" }, +}); enum class Event : uint8_t { General, @@ -28,9 +34,17 @@ enum class Event : uint8_t { HttpRequest, }; -Event parseEvent(const char *name); -const char *stringifyEvent(Event event); -::std::ostream& operator<<(::std::ostream& os, Event event); +LLMR_DEFINE_ENUM_CLASS(EventClass, Event, { + { Event::General, "General" }, + { Event::Setup, "Setup" }, + { Event::Shader, "Shader" }, + { Event::ParseStyle, "ParseStyle" }, + { Event::ParseTile, "ParseTile" }, + { Event::Render, "Render" }, + { Event::HttpRequest, "HttpRequest" }, + { Event(-1), "Unknown" }, +}); + struct EventPermutation { const EventSeverity severity; diff --git a/include/llmr/style/style_source.hpp b/include/llmr/style/style_source.hpp index a368e4fd7..25a8218df 100644 --- a/include/llmr/style/style_source.hpp +++ b/include/llmr/style/style_source.hpp @@ -9,7 +9,8 @@ namespace llmr { class Source; -struct StyleSource { +class StyleSource { +public: const SourceType type; const std::string url; const uint32_t tile_size; @@ -19,16 +20,10 @@ struct StyleSource { bool enabled = false; std::shared_ptr source; - StyleSource(SourceType type = SourceType::Vector, - const std::string &url = "", - uint32_t tile_size = 512, uint32_t min_zoom = 0, - uint32_t max_zoom = 22) - : type(type), - url(url), - tile_size(tile_size), - min_zoom(min_zoom), - max_zoom(max_zoom) {} - }; + StyleSource(SourceType type = SourceType::Vector, const std::string &url = "", + uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 22) + : type(type), url(url), tile_size(tile_size), min_zoom(min_zoom), max_zoom(max_zoom) {} +}; }; #endif diff --git a/include/llmr/style/types.hpp b/include/llmr/style/types.hpp index fc0cc99ab..82632849a 100644 --- a/include/llmr/style/types.hpp +++ b/include/llmr/style/types.hpp @@ -1,6 +1,8 @@ #ifndef LLMR_STYLE_TYPES #define LLMR_STYLE_TYPES +#include + #include #include @@ -20,9 +22,17 @@ enum class StyleLayerType : uint8_t { Background }; -StyleLayerType parseStyleLayerType(const std::string &type); -const char *stringifyStyleLayerType(StyleLayerType type); -std::ostream& operator<<(std::ostream&, StyleLayerType type); +LLMR_DEFINE_ENUM_CLASS(StyleLayerTypeClass, StyleLayerType, { + { StyleLayerType::Unknown, "unknown" }, + { StyleLayerType::Fill, "fill" }, + { StyleLayerType::Line, "line" }, + { StyleLayerType::Icon, "icon" }, + { StyleLayerType::Text, "text" }, + { StyleLayerType::Raster, "raster" }, + { StyleLayerType::Composite, "composite" }, + { StyleLayerType::Background, "background" }, + { StyleLayerType(-1), "unknown" }, +}); enum class WindingType : uint8_t { diff --git a/include/llmr/util/enum.hpp b/include/llmr/util/enum.hpp new file mode 100644 index 000000000..9f3643b4f --- /dev/null +++ b/include/llmr/util/enum.hpp @@ -0,0 +1,55 @@ +#ifndef LLMR_UTIL_ENUM +#define LLMR_UTIL_ENUM + +#include +#include + +namespace llmr { + +template +struct EnumValue { + const Type value; + const char *name; +}; + +template *names, const size_t length> +struct Enum { + using Type = EnumName; + Type value; + static const constexpr size_t l = length; +private: + static constexpr inline bool compare(const char *a, const char *b) { + return *a == *b && (*a == '\0' || compare(a + 1, b + 1)); + } + static constexpr inline const char *lookup_type(Type e, EnumValue const * const l, size_t r) { + return r == 0 ? "" : l->value == e ? l->name : lookup_type(e, l + 1, r - 1); + } + static constexpr inline Type lookup_name(const char *n, EnumValue const * const l, size_t r) { + return r == 0 ? Type(-1) : compare(l->name, n) ? l->value : lookup_name(n, l + 1, r - 1); + } +public: + inline constexpr Enum(const char *n) : value(lookup_name(n, names, length)) {} + inline constexpr Enum(const std::string &n) : value(lookup_name(n.c_str(), names, length)) {} + inline constexpr Enum(Type t) : value(t) {} + + inline void operator=(const char *n) { value = lookup_name(n, names, length); } + inline void operator=(const std::string &n) { *this = n.c_str(); } + inline void operator=(Type t) { value = t; } + + inline constexpr bool valid() const { return value != Type(-1); } + + inline constexpr const char *c_str() const { return lookup_type(value, names, length); } + inline std::string str() const { return c_str(); } + + inline constexpr operator Type() const { return value; } +}; + +#define LLMR_DEFINE_ENUM_CLASS(name, type, strings...) \ + const constexpr ::llmr::EnumValue type##_names[] = strings; \ + using name = ::llmr::Enum)>; \ + inline std::ostream& operator<<(std::ostream& os, type t) { return os << name(t).str(); } + +} + +#endif + diff --git a/src/platform/event.cpp b/src/platform/event.cpp deleted file mode 100644 index c60faaeba..000000000 --- a/src/platform/event.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include - -#include - -namespace llmr { - -EventSeverity parseEventSeverity(const char *name) { - if (strcmp(name, "DEBUG") == 0) return EventSeverity::Debug; - if (strcmp(name, "INFO") == 0) return EventSeverity::Info; - if (strcmp(name, "TEST") == 0) return EventSeverity::Test; - if (strcmp(name, "WARNING") == 0) return EventSeverity::Warning; - if (strcmp(name, "ERROR") == 0) return EventSeverity::Error; - return EventSeverity(-1); -} - -const char *stringifyEventSeverity(EventSeverity eventSeverity) { - switch (eventSeverity) { - case EventSeverity::Debug: return "DEBUG"; - case EventSeverity::Info: return "INFO"; - case EventSeverity::Test: return "TEST"; - case EventSeverity::Warning: return "WARNING"; - case EventSeverity::Error: return "ERROR"; - default: return "UNKNOWN"; - } -} - -::std::ostream& operator<<(::std::ostream& os, EventSeverity eventSeverity) { - return os << stringifyEventSeverity(eventSeverity); -} - -Event parseEvent(const char *name) { - if (strcmp(name, "General") == 0) return Event::General; - if (strcmp(name, "Setup") == 0) return Event::Setup; - if (strcmp(name, "Shader") == 0) return Event::Shader; - if (strcmp(name, "ParseStyle") == 0) return Event::ParseStyle; - if (strcmp(name, "ParseTile") == 0) return Event::ParseTile; - if (strcmp(name, "Render") == 0) return Event::Render; - if (strcmp(name, "HttpRequest") == 0) return Event::HttpRequest; - return Event(-1); -} - -const char *stringifyEvent(Event event) { - switch (event) { - case Event::General: return "General"; - case Event::Setup: return "Setup"; - case Event::Shader: return "Shader"; - case Event::ParseStyle: return "ParseStyle"; - case Event::ParseTile: return "ParseTile"; - case Event::Render: return "Render"; - case Event::HttpRequest: return "HttpRequest"; - default: return "Unknown"; - } -} - -::std::ostream& operator<<(::std::ostream& os, Event event) { - return os << stringifyEvent(event); -} - - -} diff --git a/src/shader/shader.cpp b/src/shader/shader.cpp index aaf4c2792..aa3e76825 100644 --- a/src/shader/shader.cpp +++ b/src/shader/shader.cpp @@ -4,6 +4,7 @@ #include #include +#include using namespace llmr; diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 434f07a72..50a078983 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -559,7 +559,7 @@ void StyleParser::parseLayer(std::pair> &pair if (!type.IsString()) { fprintf(stderr, "[WARNING] layer type of '%s' must be a string\n", layer->id.c_str()); } else { - layer->type = parseStyleLayerType({ type.GetString(), type.GetStringLength() }); + layer->type = StyleLayerTypeClass(std::string { type.GetString(), type.GetStringLength() }); } } diff --git a/src/style/types.cpp b/src/style/types.cpp index 41a17d0b1..e69de29bb 100644 --- a/src/style/types.cpp +++ b/src/style/types.cpp @@ -1,35 +0,0 @@ -#include - -#include - -namespace llmr { - -StyleLayerType parseStyleLayerType(const std::string &type) { - if (type == "fill") return StyleLayerType::Fill; - if (type == "line") return StyleLayerType::Line; - if (type == "icon") return StyleLayerType::Icon; - if (type == "text") return StyleLayerType::Text; - if (type == "raster") return StyleLayerType::Raster; - if (type == "composite") return StyleLayerType::Composite; - if (type == "background") return StyleLayerType::Background; - return StyleLayerType::Unknown; -} - -const char *stringifyStyleLayerType(StyleLayerType type) { - switch (type) { - case StyleLayerType::Fill: return "fill"; - case StyleLayerType::Line: return "line"; - case StyleLayerType::Icon: return "icon"; - case StyleLayerType::Text: return "text"; - case StyleLayerType::Raster: return "raster"; - case StyleLayerType::Composite: return "composite"; - case StyleLayerType::Background: return "background"; - default: return "unknown"; - } -} - -std::ostream& operator<<(std::ostream& os, StyleLayerType type) { - return os << stringifyStyleLayerType(type); -} - -} diff --git a/test/enums.cpp b/test/enums.cpp new file mode 100644 index 000000000..3df711dd8 --- /dev/null +++ b/test/enums.cpp @@ -0,0 +1,43 @@ +#include +#include "gtest/gtest.h" + +#include + +#include + +using namespace llmr; + +TEST(Enums, StyleLayerType) { + std::cerr << StyleLayerType::Raster; + + ASSERT_EQ(StyleLayerType::Unknown, StyleLayerTypeClass("unknown")); + ASSERT_EQ(StyleLayerType::Fill, StyleLayerTypeClass("fill")); + ASSERT_EQ(StyleLayerType::Line, StyleLayerTypeClass("line")); + ASSERT_EQ(StyleLayerType::Icon, StyleLayerTypeClass("icon")); + ASSERT_EQ(StyleLayerType::Text, StyleLayerTypeClass("text")); + ASSERT_EQ(StyleLayerType::Raster, StyleLayerTypeClass("rastr")); + ASSERT_EQ(StyleLayerType::Composite, StyleLayerTypeClass("composite")); + ASSERT_EQ(StyleLayerType::Background, StyleLayerTypeClass("background")); + + ASSERT_EQ(StyleLayerType::Unknown, StyleLayerTypeClass(StyleLayerType::Unknown)); + ASSERT_EQ(StyleLayerType::Fill, StyleLayerTypeClass(StyleLayerType::Fill)); + ASSERT_EQ(StyleLayerType::Line, StyleLayerTypeClass(StyleLayerType::Line)); + ASSERT_EQ(StyleLayerType::Icon, StyleLayerTypeClass(StyleLayerType::Icon)); + ASSERT_EQ(StyleLayerType::Text, StyleLayerTypeClass(StyleLayerType::Text)); + ASSERT_EQ(StyleLayerType::Raster, StyleLayerTypeClass(StyleLayerType::Raster)); + ASSERT_EQ(StyleLayerType::Composite, StyleLayerTypeClass(StyleLayerType::Composite)); + ASSERT_EQ(StyleLayerType::Background, StyleLayerTypeClass(StyleLayerType::Background)); + + ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Unknown), StyleLayerTypeClass(StyleLayerType::Unknown)); + ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Fill), StyleLayerTypeClass(StyleLayerType::Fill)); + ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Line), StyleLayerTypeClass(StyleLayerType::Line)); + ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Icon), StyleLayerTypeClass(StyleLayerType::Icon)); + ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Text), StyleLayerTypeClass(StyleLayerType::Text)); + ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Raster), StyleLayerTypeClass(StyleLayerType::Raster)); + ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Composite), StyleLayerTypeClass(StyleLayerType::Composite)); + ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Background), StyleLayerTypeClass(StyleLayerType::Background)); + + ASSERT_EQ(false, StyleLayerTypeClass("").valid()); + ASSERT_EQ(false, StyleLayerTypeClass("Backgrund").valid()); +} + diff --git a/test/headless.cpp b/test/headless.cpp index 523f66d0d..a7f34b9d4 100644 --- a/test/headless.cpp +++ b/test/headless.cpp @@ -94,8 +94,8 @@ TEST_P(HeadlessTest, render) { if (js_entry.Size() == 5) { const uint32_t count = js_entry[rapidjson::SizeType(0)].GetUint(); const FixtureLogBackend::LogMessage message { - parseEventSeverity(js_entry[rapidjson::SizeType(1)].GetString()), - parseEvent(js_entry[rapidjson::SizeType(2)].GetString()), + EventSeverityClass(js_entry[rapidjson::SizeType(1)].GetString()), + EventClass(js_entry[rapidjson::SizeType(2)].GetString()), js_entry[rapidjson::SizeType(3)].GetInt64(), js_entry[rapidjson::SizeType(4)].GetString() }; @@ -104,15 +104,15 @@ TEST_P(HeadlessTest, render) { const uint32_t count = js_entry[rapidjson::SizeType(0)].GetUint(); if (js_entry[rapidjson::SizeType(3)].IsString()) { const FixtureLogBackend::LogMessage message { - parseEventSeverity(js_entry[rapidjson::SizeType(1)].GetString()), - parseEvent(js_entry[rapidjson::SizeType(2)].GetString()), + EventSeverityClass(js_entry[rapidjson::SizeType(1)].GetString()), + EventClass(js_entry[rapidjson::SizeType(2)].GetString()), js_entry[rapidjson::SizeType(3)].GetString() }; ASSERT_EQ(count, log.count(message)) << "Message: " << message << "Full Log: " << std::endl << log.messages; } else { const FixtureLogBackend::LogMessage message { - parseEventSeverity(js_entry[rapidjson::SizeType(1)].GetString()), - parseEvent(js_entry[rapidjson::SizeType(2)].GetString()), + EventSeverityClass(js_entry[rapidjson::SizeType(1)].GetString()), + EventClass(js_entry[rapidjson::SizeType(2)].GetString()), js_entry[rapidjson::SizeType(3)].GetInt64() }; ASSERT_EQ(count, log.count(message)) << "Message: " << message << "Full Log: " << std::endl << log.messages; @@ -120,8 +120,8 @@ TEST_P(HeadlessTest, render) { } else if (js_entry.Size() == 3) { const uint32_t count = js_entry[rapidjson::SizeType(0)].GetUint(); const FixtureLogBackend::LogMessage message { - parseEventSeverity(js_entry[rapidjson::SizeType(1)].GetString()), - parseEvent(js_entry[rapidjson::SizeType(2)].GetString()) + EventSeverityClass(js_entry[rapidjson::SizeType(1)].GetString()), + EventClass(js_entry[rapidjson::SizeType(2)].GetString()) }; ASSERT_EQ(count, log.count(message)) << "Message: " << message << "Full Log: " << std::endl << log.messages; } else { diff --git a/test/test.gyp b/test/test.gyp index c6869fd47..95f22c257 100644 --- a/test/test.gyp +++ b/test/test.gyp @@ -90,6 +90,22 @@ "../llmr.gyp:llmr-x86" ] }, + { + "target_name": "enums", + "product_name": "test_enums", + "type": "executable", + "libraries": [ + "-lpthread", + ], + "sources": [ + "./main.cpp", + "./enums.cpp", + ], + "dependencies": [ + "../deps/gtest/gtest.gyp:gtest", + "../llmr.gyp:llmr-x86" + ] + }, { "target_name": "variant", "product_name": "test_variant", @@ -167,6 +183,7 @@ "dependencies": [ "rotation_range", "clip_ids", + "enums", "variant", "tile", "functions", From ba7d8c7731983d12658fe26a3395879948e31f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 14 Jul 2014 16:38:34 -0700 Subject: [PATCH 08/11] fix errors --- common/stderr_log.hpp | 8 ++++---- test/enums.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/stderr_log.hpp b/common/stderr_log.hpp index 43d1b41c2..e2492d3af 100644 --- a/common/stderr_log.hpp +++ b/common/stderr_log.hpp @@ -9,10 +9,10 @@ class StderrLogBackend : public LogBackend { public: inline ~StderrLogBackend() = default; - void record(EventSeverityClass severity, EventClass event, const std::string &msg); - void record(EventSeverityClass severity, EventClass event, const char* format, ...); - void record(EventSeverityClass severity, EventClass event, int64_t code); - void record(EventSeverityClass severity, EventClass event, int64_t code, const std::string &msg); + void record(EventSeverity severity, Event event, const std::string &msg); + void record(EventSeverity severity, Event event, const char* format, ...); + void record(EventSeverity severity, Event event, int64_t code); + void record(EventSeverity severity, Event event, int64_t code, const std::string &msg); }; diff --git a/test/enums.cpp b/test/enums.cpp index 3df711dd8..3a5ddc9b0 100644 --- a/test/enums.cpp +++ b/test/enums.cpp @@ -15,7 +15,7 @@ TEST(Enums, StyleLayerType) { ASSERT_EQ(StyleLayerType::Line, StyleLayerTypeClass("line")); ASSERT_EQ(StyleLayerType::Icon, StyleLayerTypeClass("icon")); ASSERT_EQ(StyleLayerType::Text, StyleLayerTypeClass("text")); - ASSERT_EQ(StyleLayerType::Raster, StyleLayerTypeClass("rastr")); + ASSERT_EQ(StyleLayerType::Raster, StyleLayerTypeClass("raster")); ASSERT_EQ(StyleLayerType::Composite, StyleLayerTypeClass("composite")); ASSERT_EQ(StyleLayerType::Background, StyleLayerTypeClass("background")); From 22ed777a82e92532cdd0844557aa56c7744dcc57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 14 Jul 2014 16:44:40 -0700 Subject: [PATCH 09/11] make gcc happy --- include/llmr/util/enum.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/llmr/util/enum.hpp b/include/llmr/util/enum.hpp index 9f3643b4f..85a2d7c89 100644 --- a/include/llmr/util/enum.hpp +++ b/include/llmr/util/enum.hpp @@ -12,7 +12,7 @@ struct EnumValue { const char *name; }; -template *names, const size_t length> +template *names, const size_t length> struct Enum { using Type = EnumName; Type value; From 9213f8d8e01c265ede1ca742886fb6e5df1b6677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 14 Jul 2014 17:35:47 -0700 Subject: [PATCH 10/11] fix font halo units --- src/renderer/painter_text.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp index 1f6d76397..233ba25b1 100644 --- a/src/renderer/painter_text.cpp +++ b/src/renderer/painter_text.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include using namespace llmr; @@ -93,6 +94,17 @@ void Painter::renderText(TextBucket& bucket, std::shared_ptr layer_d 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. + + // Our signed distance fields are scaled so that 1 pixel is scaled to 32 pixels. + // Our cutoff between positive and negative values is hard coded to 64 (== 2 pixels). + // This means that our 6/8 of the value range lies outside the glyph outline. + const float sdfOffset = (256.0f - 64.0f) / 32.0f; + + // Currently, all of our fonts are rendered with a font size of 24px. + const float sdfFontSize = 24.0f; + + const float haloWidth = util::clamp((sdfOffset - properties.halo_width / (fontSize / sdfFontSize)) / 8.0f, 0.0f, 1.0f); + textShader->setGamma(properties.halo_blur * 2.4f / fontSize / map.getState().getPixelRatio()); if (properties.opacity < 1.0f) { Color color = properties.halo_color; @@ -104,7 +116,7 @@ void Painter::renderText(TextBucket& bucket, std::shared_ptr layer_d } else { textShader->setColor(properties.halo_color); } - textShader->setBuffer(properties.halo_width); + textShader->setBuffer(haloWidth); glDepthRange(strata, 1.0f); bucket.drawGlyphs(*textShader); } From 471dafc1d1e453efa09f6d0e213ee5f8601cd754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Mon, 14 Jul 2014 18:25:07 -0700 Subject: [PATCH 11/11] change halo-width/blur units refs mapbox/mapbox-gl-style-spec#66 --- src/renderer/painter_text.cpp | 42 ++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp index 233ba25b1..3d064d9ee 100644 --- a/src/renderer/painter_text.cpp +++ b/src/renderer/painter_text.cpp @@ -89,23 +89,37 @@ void Painter::renderText(TextBucket& bucket, std::shared_ptr layer_d textShader->setMaxFadeZoom(std::floor(highZ * 10)); textShader->setFadeZoom((map.getState().getNormalizedZoom() + bump) * 10); + // This defines the gamma around the SDF cutoff value. + const float sdfGamma = 0.75f / 10.0f; + + // Our signed distance fields are scaled so that 1 pixel is scaled to 32 pixels. + // Our cutoff between positive and negative values is hard coded to 64 (== 2 pixels). + // This means that our 6/8 of the value range lies outside the glyph outline. + const float sdfOffset = (256.0f - 64.0f) / 32.0f; + + // Currently, all of our fonts are rendered with a font size of 24px. + const float sdfFontSize = 24.0f; + + // The default gamma value has to be adjust for the current pixelratio so that we're not drawing + // blurry font on retina screens. + const float gamma = sdfGamma * sdfFontSize / fontSize / map.getState().getPixelRatio(); + // We're drawing in the translucent pass which is bottom-to-top, so we need // to draw the halo first. 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. - - // Our signed distance fields are scaled so that 1 pixel is scaled to 32 pixels. - // Our cutoff between positive and negative values is hard coded to 64 (== 2 pixels). - // This means that our 6/8 of the value range lies outside the glyph outline. - const float sdfOffset = (256.0f - 64.0f) / 32.0f; - - // Currently, all of our fonts are rendered with a font size of 24px. - const float sdfFontSize = 24.0f; - const float haloWidth = util::clamp((sdfOffset - properties.halo_width / (fontSize / sdfFontSize)) / 8.0f, 0.0f, 1.0f); - textShader->setGamma(properties.halo_blur * 2.4f / fontSize / map.getState().getPixelRatio()); + if (properties.halo_blur != 0.0f) { + // We are converting the halo_blur value to current screen pixels. + // Then we're dividing it by two because the gamma value is added/subtracted into both + // directions in the shader, but the halo_blur describes the entire width of the blur. + // Note that this does *not* have to be adjusted for retina screens, because we want the + // same blur width when we explicitly specify one. + textShader->setGamma((properties.halo_blur / (fontSize / sdfFontSize)) / 8.0f / 2.0f); + } else { + textShader->setGamma(sdfGamma); + } + if (properties.opacity < 1.0f) { Color color = properties.halo_color; color[0] *= properties.opacity; @@ -123,9 +137,7 @@ void Painter::renderText(TextBucket& bucket, std::shared_ptr layer_d if (properties.color[3] > 0.0f) { // Then, we draw the text over the halo - // 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(2.4f / fontSize / map.getState().getPixelRatio()); + textShader->setGamma(gamma); if (properties.opacity < 1.0f) { Color color = properties.color; color[0] *= properties.opacity;