Merge branch 'master' into fuzz-pipe
Conflicts: test/test.gyp
This commit is contained in:
2
Makefile
2
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
|
||||
|
||||
11
README.md
11
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`.
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
|
||||

|
||||
|
||||
|
||||
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
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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<std::shared_ptr<Source>> getActiveSources() const;
|
||||
const std::set<std::shared_ptr<StyleSource>> getActiveSources() const;
|
||||
void setAppliedClasses(const std::vector<std::string> &classes);
|
||||
void toggleClass(const std::string &name);
|
||||
const std::vector<std::string> &getAppliedClasses() const;
|
||||
@@ -178,7 +178,7 @@ private:
|
||||
|
||||
int indent = 0;
|
||||
|
||||
std::set<std::shared_ptr<Source>> activeSources;
|
||||
std::set<std::shared_ptr<StyleSource>> activeSources;
|
||||
|
||||
private:
|
||||
bool async = false;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#ifndef LLMR_PLATFORM_EVENT
|
||||
#define LLMR_PLATFORM_EVENT
|
||||
|
||||
#include <llmr/util/enum.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
|
||||
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;
|
||||
|
||||
@@ -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<std::shared_ptr<Source>> &sources);
|
||||
void drawClippingMasks(const std::set<std::shared_ptr<StyleSource>> &sources);
|
||||
void drawClippingMask(const mat4& matrix, const ClipID& clip);
|
||||
|
||||
void clearFramebuffers();
|
||||
|
||||
@@ -76,7 +76,6 @@ public:
|
||||
|
||||
std::string name;
|
||||
std::shared_ptr<StyleSource> style_source;
|
||||
std::shared_ptr<Source> source;
|
||||
std::string source_layer;
|
||||
FilterExpression filter;
|
||||
StyleBucketRender render = std::false_type();
|
||||
|
||||
@@ -3,25 +3,27 @@
|
||||
|
||||
#include <llmr/style/types.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
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,
|
||||
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) {}
|
||||
};
|
||||
class StyleSource {
|
||||
public:
|
||||
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> 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) {}
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef LLMR_STYLE_TYPES
|
||||
#define LLMR_STYLE_TYPES
|
||||
|
||||
#include <llmr/util/enum.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
55
include/llmr/util/enum.hpp
Normal file
55
include/llmr/util/enum.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef LLMR_UTIL_ENUM
|
||||
#define LLMR_UTIL_ENUM
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
template <typename Type>
|
||||
struct EnumValue {
|
||||
const Type value;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
template <typename EnumName, const EnumValue<EnumName> *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<Type> 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<Type> 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> type##_names[] = strings; \
|
||||
using name = ::llmr::Enum<type, type##_names, sizeof(type##_names) / sizeof(::llmr::EnumValue<type>)>; \
|
||||
inline std::ostream& operator<<(std::ostream& os, type t) { return os << name(t).str(); }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,6 +11,10 @@ template<typename T, typename ...Args>
|
||||
return ::std::unique_ptr<T>(new T(::std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace llmr {
|
||||
namespace util {
|
||||
|
||||
template <typename Container, typename ForwardIterator, typename Predicate>
|
||||
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
|
||||
|
||||
@@ -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"];
|
||||
|
||||
@@ -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<dimension> dst = atlas.getImage(name, sprite);
|
||||
const SpritePosition &src = sprite.getSpritePosition(name);
|
||||
if (!src) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <llmr/util/string.hpp>
|
||||
#include <llmr/util/constants.hpp>
|
||||
#include <llmr/util/uv.hpp>
|
||||
#include <llmr/util/std.hpp>
|
||||
#include <llmr/style/style_layer_group.hpp>
|
||||
#include <llmr/style/style_bucket.hpp>
|
||||
#include <llmr/geometry/sprite_atlas.hpp>
|
||||
@@ -410,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<StyleSource> &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<StyleSource> &source : activeSources) {
|
||||
if (source->enabled) {
|
||||
if (!source->source) {
|
||||
source->source = std::make_shared<Source>(*source, getAccessToken());
|
||||
}
|
||||
} else {
|
||||
source->source.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, remove all sources that are disabled.
|
||||
util::erase_if(activeSources, [](std::shared_ptr<StyleSource> source){
|
||||
return !source->enabled;
|
||||
});
|
||||
}
|
||||
|
||||
const std::set<std::shared_ptr<Source>> Map::getActiveSources() const {
|
||||
const std::set<std::shared_ptr<StyleSource>> Map::getActiveSources() const {
|
||||
return activeSources;
|
||||
}
|
||||
|
||||
@@ -426,8 +448,7 @@ void Map::updateSources(const std::shared_ptr<StyleLayerGroup> &group) {
|
||||
if (!layer) continue;
|
||||
if (layer->bucket) {
|
||||
if (layer->bucket->style_source) {
|
||||
auto ret = activeSources.emplace(std::make_shared<Source>(*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);
|
||||
@@ -436,23 +457,23 @@ void Map::updateSources(const std::shared_ptr<StyleLayerGroup> &group) {
|
||||
}
|
||||
|
||||
void Map::updateTiles() {
|
||||
for (const std::shared_ptr<Source> &source : getActiveSources()) {
|
||||
source->update(*this);
|
||||
for (const std::shared_ptr<StyleSource> &source : getActiveSources()) {
|
||||
source->source->update(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::updateRenderState() {
|
||||
std::forward_list<Tile::ID> ids;
|
||||
|
||||
for (const std::shared_ptr<Source> &source : getActiveSources()) {
|
||||
ids.splice_after(ids.before_begin(), source->getIDs());
|
||||
source->updateMatrices(painter.projMatrix, state);
|
||||
for (const std::shared_ptr<StyleSource> &source : getActiveSources()) {
|
||||
ids.splice_after(ids.before_begin(), source->source->getIDs());
|
||||
source->source->updateMatrices(painter.projMatrix, state);
|
||||
}
|
||||
|
||||
const std::map<Tile::ID, ClipID> clipIDs = computeClipIDs(ids);
|
||||
|
||||
for (const std::shared_ptr<Source> &source : getActiveSources()) {
|
||||
source->updateClipIDs(clipIDs);
|
||||
for (const std::shared_ptr<StyleSource> &source : getActiveSources()) {
|
||||
source->source->updateClipIDs(clipIDs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,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> &source : getActiveSources()) {
|
||||
source->finishRender(painter);
|
||||
for (const std::shared_ptr<StyleSource> &source : getActiveSources()) {
|
||||
source->source->finishRender(painter);
|
||||
}
|
||||
|
||||
painter.renderMatte();
|
||||
@@ -629,6 +650,8 @@ void Map::renderLayer(std::shared_ptr<StyleLayer> 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) {
|
||||
@@ -660,6 +683,8 @@ void Map::renderLayer(std::shared_ptr<StyleLayer> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Tile::ID> retain_data;
|
||||
std::erase_if(tiles, [&retain, &retain_data, &changed](std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair) {
|
||||
util::erase_if(tiles, [&retain, &retain_data, &changed](std::pair<const Tile::ID, std::unique_ptr<Tile>> &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<const Tile::ID, std::weak_ptr<TileData>> &pair) {
|
||||
util::erase_if(tile_data, [&retain_data](std::pair<const Tile::ID, std::weak_ptr<TileData>> &pair) {
|
||||
const std::shared_ptr<TileData> tile = pair.second.lock();
|
||||
if (!tile) {
|
||||
return true;
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
#include <llmr/platform/event.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
using namespace llmr;
|
||||
|
||||
void Painter::drawClippingMasks(const std::set<std::shared_ptr<Source>> &sources) {
|
||||
void Painter::drawClippingMasks(const std::set<std::shared_ptr<StyleSource>> &sources) {
|
||||
gl::group group("clipping masks");
|
||||
|
||||
useProgram(plainShader->program);
|
||||
@@ -18,8 +18,8 @@ void Painter::drawClippingMasks(const std::set<std::shared_ptr<Source>> &sources
|
||||
|
||||
coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0));
|
||||
|
||||
for (const std::shared_ptr<Source> &source : sources) {
|
||||
source->drawClippingMasks(*this);
|
||||
for (const std::shared_ptr<StyleSource> &source : sources) {
|
||||
source->source->drawClippingMasks(*this);
|
||||
}
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <llmr/renderer/text_bucket.hpp>
|
||||
#include <llmr/style/style_layer.hpp>
|
||||
#include <llmr/map/map.hpp>
|
||||
#include <llmr/util/math.hpp>
|
||||
#include <cmath>
|
||||
|
||||
using namespace llmr;
|
||||
@@ -88,12 +89,37 @@ void Painter::renderText(TextBucket& bucket, std::shared_ptr<StyleLayer> 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.
|
||||
textShader->setGamma(properties.halo_blur * 2.4f / fontSize / map.getState().getPixelRatio());
|
||||
const float haloWidth = util::clamp((sdfOffset - properties.halo_width / (fontSize / sdfFontSize)) / 8.0f, 0.0f, 1.0f);
|
||||
|
||||
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;
|
||||
@@ -104,16 +130,14 @@ void Painter::renderText(TextBucket& bucket, std::shared_ptr<StyleLayer> layer_d
|
||||
} else {
|
||||
textShader->setColor(properties.halo_color);
|
||||
}
|
||||
textShader->setBuffer(properties.halo_width);
|
||||
textShader->setBuffer(haloWidth);
|
||||
glDepthRange(strata, 1.0f);
|
||||
bucket.drawGlyphs(*textShader);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <llmr/platform/log.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace llmr;
|
||||
|
||||
|
||||
@@ -560,7 +560,7 @@ void StyleParser::parseLayer(std::pair<JSVal, std::shared_ptr<StyleLayer>> &pair
|
||||
if (!type.IsString()) {
|
||||
Log::Warning(Event::ParseStyle, "layer type of '%s' must be a string", layer->id.c_str());
|
||||
} else {
|
||||
layer->type = parseStyleLayerType({ type.GetString(), type.GetStringLength() });
|
||||
layer->type = StyleLayerTypeClass(std::string { type.GetString(), type.GetStringLength() });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#include <llmr/style/types.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
43
test/enums.cpp
Normal file
43
test/enums.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include <iostream>
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <llmr/style/types.hpp>
|
||||
|
||||
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("raster"));
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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": "style",
|
||||
"product_name": "test_style",
|
||||
@@ -185,6 +201,7 @@
|
||||
"dependencies": [
|
||||
"rotation_range",
|
||||
"clip_ids",
|
||||
"enums",
|
||||
"variant",
|
||||
"tile",
|
||||
"functions",
|
||||
|
||||
Reference in New Issue
Block a user