Merge branch 'master' of github.com:mapbox/llmr-native

This commit is contained in:
Justin R. Miller
2014-05-26 11:11:44 -07:00
36 changed files with 762 additions and 450 deletions

2
.gitignore vendored
View File

@@ -12,3 +12,5 @@
/include/llmr/shader/shaders.hpp
/include/llmr/style/resources.hpp
/src/style/resources.cpp
/src/shader/shaders_gl.cpp
/src/shader/shaders_gles2.cpp

View File

@@ -3,7 +3,7 @@
var fs = require('fs');
var path = require('path');
var lazy_update = require('./lazy-update');
var mkdirp = require('./mkdirp');
try { var glsl = require('glsl-optimizer'); } catch(err) {}
@@ -117,9 +117,13 @@ module.exports = function(shader_type, prefix, suffix) {
code += '\n};\n';
code += suffix + '\n';
var file_path = path.join(process.argv[2], 'include/llmr/shader/shaders.hpp');
mkdirp.sync(path.dirname(file_path));
fs.writeFileSync(file_path, header);
var header_path = path.join(process.argv[2], 'src/shader/shaders_' + shader_type + '.cpp');
mkdirp.sync(path.dirname(header_path));
fs.writeFileSync(header_path, code);
lazy_update('include/llmr/shader/shaders.hpp', header);
lazy_update('src/shader/shaders_' + shader_type + '.cpp', code);
};
module.exports('gl', '#ifndef GL_ES_VERSION_2_0', '#endif');

View File

@@ -2,9 +2,8 @@
'use strict';
var path = require('path');
var lazy_update = require('./lazy-update');
var fs = require('fs');
var mkdirp = require('./mkdirp');
var name = 'style';
var data = JSON.stringify(require(path.join(process.cwd(), process.argv[2])));
@@ -26,7 +25,9 @@ header += '}\n';
header += '\n';
header += '#endif\n';
lazy_update('include/llmr/style/resources.hpp', header);
var header_path = path.join(process.argv[3], 'include/llmr/style/resources.hpp');
mkdirp.sync(path.dirname(header_path));
fs.writeFileSync(header_path, header);
var code = '// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.\n';
code += '#include <llmr/style/resources.hpp>\n';
@@ -36,5 +37,6 @@ code += '\n';
code += 'const unsigned char resources::' + name + '[] = R"JSON(' + data + ')JSON";\n';
code += 'const unsigned long resources::' + name + '_size = sizeof(resources::' + name + ');\n';
lazy_update('src/style/resources.cpp', code);
var file_path = path.join(process.argv[3], 'src/style/resources.cpp');
mkdirp.sync(path.dirname(file_path));
fs.writeFileSync(file_path, code);

97
bin/mkdirp.js Normal file
View File

@@ -0,0 +1,97 @@
var path = require('path');
var fs = require('fs');
module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP;
function mkdirP (p, opts, f, made) {
if (typeof opts === 'function') {
f = opts;
opts = {};
}
else if (!opts || typeof opts !== 'object') {
opts = { mode: opts };
}
var mode = opts.mode;
var xfs = opts.fs || fs;
if (mode === undefined) {
mode = 0777 & (~process.umask());
}
if (!made) made = null;
var cb = f || function () {};
p = path.resolve(p);
xfs.mkdir(p, mode, function (er) {
if (!er) {
made = made || p;
return cb(null, made);
}
switch (er.code) {
case 'ENOENT':
mkdirP(path.dirname(p), opts, function (er, made) {
if (er) cb(er, made);
else mkdirP(p, opts, cb, made);
});
break;
// In the case of any other error, just see if there's a dir
// there already. If so, then hooray! If not, then something
// is borked.
default:
xfs.stat(p, function (er2, stat) {
// if the stat fails, then that's super weird.
// let the original error be the failure reason.
if (er2 || !stat.isDirectory()) cb(er, made)
else cb(null, made);
});
break;
}
});
}
mkdirP.sync = function sync (p, opts, made) {
if (!opts || typeof opts !== 'object') {
opts = { mode: opts };
}
var mode = opts.mode;
var xfs = opts.fs || fs;
if (mode === undefined) {
mode = 0777 & (~process.umask());
}
if (!made) made = null;
p = path.resolve(p);
try {
xfs.mkdirSync(p, mode);
made = made || p;
}
catch (err0) {
switch (err0.code) {
case 'ENOENT' :
made = sync(path.dirname(p), opts, made);
sync(p, opts, made);
break;
// In the case of any other error, just see if there's a dir
// there already. If so, then hooray! If not, then something
// is borked.
default:
var stat;
try {
stat = xfs.statSync(p);
}
catch (err1) {
throw err0;
}
if (!stat.isDirectory()) throw err0;
break;
}
}
return made;
};

View File

@@ -1732,6 +1732,8 @@ module.exports = {
"hillshade_full_shadow": {
"color": "#103",
"antialias": false,
"prerender": true,
"prerender-blur": 1,
"opacity": [
"stops",
{"z": 15, "val": 0.075},
@@ -1742,6 +1744,8 @@ module.exports = {
"hillshade_medium_shadow": {
"color": "#206",
"antialias": false,
"prerender": true,
"prerender-blur": 1,
"opacity": [
"stops",
{"z": 15, "val": 0.075},
@@ -1752,6 +1756,8 @@ module.exports = {
"hillshade_full_highlight": {
"color": "#fffff3",
"antialias": false,
"prerender": true,
"prerender-blur": 1,
"opacity": [
"stops",
{"z": 15, "val": 0.3},
@@ -1762,6 +1768,8 @@ module.exports = {
"hillshade_medium_highlight": {
"color": "#ffd",
"antialias": false,
"prerender": true,
"prerender-blur": 1,
"opacity": [
"stops",
{"z": 15, "val": 0.3},
@@ -2433,6 +2441,8 @@ module.exports = {
"hillshade_full_shadow": {
"color": "#103",
"antialias": false,
"prerender": true,
"prerender-blur": 1,
"opacity": [
"stops",
{"z": 0, "val": 0.3},
@@ -2443,6 +2453,8 @@ module.exports = {
"hillshade_medium_shadow": {
"color": "#206",
"antialias": false,
"prerender": true,
"prerender-blur": 1,
"opacity": [
"stops",
{"z": 0, "val": 0.3},
@@ -2453,6 +2465,8 @@ module.exports = {
"hillshade_full_highlight": {
"color": "#fdfdad",
"antialias": false,
"prerender": true,
"prerender-blur": 1,
"opacity": [
"stops",
{"z": 14, "val": 0.4},
@@ -2464,6 +2478,8 @@ module.exports = {
"hillshade_medium_highlight": {
"color": "#ffe1b7",
"antialias": false,
"prerender": true,
"prerender-blur": 1,
"opacity": [
"stops",
{"z": 15, "val": 0.3},

View File

@@ -24,7 +24,7 @@ std::atomic<int> active_tasks;
void request_initialize_cb() {
NSURLSessionConfiguration *sessionConfig =
[NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.timeoutIntervalForResource = 6;
sessionConfig.timeoutIntervalForResource = 30;
sessionConfig.HTTPMaximumConnectionsPerHost = 8;
sessionConfig.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;

View File

@@ -4,6 +4,7 @@
#include <string>
#include <llmr/map/tile.hpp>
#include <llmr/util/noncopyable.hpp>
#include <llmr/renderer/prerendered_texture.hpp>
namespace llmr {
@@ -14,6 +15,8 @@ public:
virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id) = 0;
virtual bool hasData() const = 0;
virtual ~Bucket() {}
std::unique_ptr<PrerenderedTexture> prerendered;
};
}

View File

@@ -19,6 +19,7 @@
#include <llmr/shader/text_shader.hpp>
#include <llmr/shader/dot_shader.hpp>
#include <llmr/shader/composite_shader.hpp>
#include <llmr/shader/gaussian_shader.hpp>
#include <llmr/map/transform_state.hpp>
@@ -77,12 +78,17 @@ 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 preparePrerender(const GenericProperties &properties);
void finishPrerender(const GenericProperties &properties);
void renderPrerenderedTexture(Bucket &bucket, const GenericProperties &properties);
void resize();
// Changes whether debug information is drawn onto the map
@@ -112,6 +118,8 @@ private:
const mat4 &translatedMatrix(const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchor anchor = TranslateAnchor::Map);
void prepareTile(const Tile& tile);
public:
void useProgram(uint32_t program);
void lineWidth(float lineWidth);
void depthMask(bool value);
@@ -123,6 +131,14 @@ public:
mat4 nativeMatrix;
mat4 extrudeMatrix;
// used to composite images and flips the geometry upside down
const mat4 flipMatrix = []{
mat4 flipMatrix;
matrix::ortho(flipMatrix, 0, 4096, -4096, 0, 0, 1);
matrix::translate(flipMatrix, flipMatrix, 0, -4096, 0);
return flipMatrix;
}();
private:
Map& map;
@@ -138,6 +154,7 @@ private:
enum { Opaque, Translucent } pass = Opaque;
const float strata_epsilon = 1.0f / (1 << 16);
public:
std::unique_ptr<PlainShader> plainShader;
std::unique_ptr<OutlineShader> outlineShader;
std::unique_ptr<LineShader> lineShader;
@@ -148,6 +165,7 @@ private:
std::unique_ptr<TextShader> textShader;
std::unique_ptr<DotShader> dotShader;
std::unique_ptr<CompositeShader> compositeShader;
std::unique_ptr<GaussianShader> gaussianShader;
// Set up the stencil quad we're using to generate the stencil mask.
VertexBuffer tileStencilBuffer = {
@@ -165,6 +183,7 @@ private:
VertexArrayObject coveringPlainArray;
VertexArrayObject coveringPatternArray;
VertexArrayObject coveringRasterArray;
VertexArrayObject coveringGaussianArray;
VertexArrayObject compositeArray;
VertexArrayObject matteArray;

View File

@@ -0,0 +1,34 @@
#ifndef LLMR_RENDERER_PRERENDERED_TEXTURE
#define LLMR_RENDERER_PRERENDERED_TEXTURE
#include <llmr/util/noncopyable.hpp>
#include <llmr/platform/gl.hpp>
namespace llmr {
class Painter;
class PrerenderedTexture : private util::noncopyable {
public:
PrerenderedTexture(uint16_t size);
~PrerenderedTexture();
void bindTexture();
void bindFramebuffer();
void unbindFramebuffer();
inline GLuint getTexture() const { return texture; }
void blur(Painter& painter, uint16_t passes);
private:
const uint16_t size;
GLint previous_fbo = 0;
GLuint fbo = 0;
GLuint texture = 0;
bool mipmapped = false;
};
}
#endif

View File

@@ -0,0 +1,29 @@
#ifndef LLMR_RENDERER_SHADER_GAUSSIAN
#define LLMR_RENDERER_SHADER_GAUSSIAN
#include <llmr/shader/shader.hpp>
namespace llmr {
class GaussianShader : public Shader {
public:
GaussianShader();
void bind(char *offset);
void setImage(int32_t image);
void setOffset(const std::array<float, 2>& offset);
private:
int32_t a_pos = -1;
int32_t image = 0;
int32_t u_image = -1;
std::array<float, 2> offset = {{}};
int32_t u_offset = -1;
};
}
#endif

View File

@@ -13,6 +13,7 @@ public:
void setImage(int32_t image);
void setOpacity(float opacity);
void setBuffer(float buffer);
private:
int32_t a_pos = -1;
@@ -22,6 +23,9 @@ private:
float opacity = 0;
int32_t u_opacity = -1;
float buffer = 0;
int32_t u_buffer = -1;
};
}

View File

@@ -84,16 +84,40 @@ struct FunctionProperty {
template <typename T> inline T evaluate(float z) const { return function(z, values); }
};
struct IconClass {
struct GenericClass {
boost::optional<FunctionProperty> enabled;
boost::optional<std::array<FunctionProperty, 2>> translate;
boost::optional<PropertyTransition> translate_transition;
boost::optional<TranslateAnchor> translateAnchor;
boost::optional<FunctionProperty> opacity;
boost::optional<PropertyTransition> opacity_transition;
boost::optional<bool> prerender;
boost::optional<float> prerenderBuffer;
boost::optional<uint16_t> prerenderSize;
boost::optional<uint16_t> prerenderBlur;
};
struct GenericProperties {
bool enabled = true;
std::array<float, 2> translate = {{ 0, 0 }};
TranslateAnchor translateAnchor = TranslateAnchor::Map;
float opacity = 1.0;
bool prerender = false;
float prerenderBuffer = 1.0f / 32.0f;
uint16_t prerenderSize = 256;
uint16_t prerenderBlur = 0;
virtual bool isVisible() const {
if (!enabled) { return false; }
if (opacity <= 0) { return false; }
return true;
}
};
struct IconClass : public GenericClass {
boost::optional<FunctionProperty> size;
boost::optional<Color> color;
boost::optional<PropertyTransition> color_transition;
boost::optional<FunctionProperty> opacity;
boost::optional<PropertyTransition> opacity_transition;
boost::optional<std::string> image;
boost::optional<FunctionProperty> radius;
boost::optional<PropertyTransition> radius_transition;
@@ -101,23 +125,15 @@ struct IconClass {
boost::optional<PropertyTransition> blur_transition;
};
struct IconProperties {
bool enabled = true;
std::array<float, 2> translate = {{ 0, 0 }};
TranslateAnchor translateAnchor = TranslateAnchor::Map;
struct IconProperties : public GenericProperties {
float size = 0;
Color color = {{ 1, 1, 1, 1 }};
float opacity = 1.0;
std::string image;
float radius = 0;
float blur = 0;
};
struct LineClass {
boost::optional<FunctionProperty> enabled;
boost::optional<std::array<FunctionProperty, 2>> translate;
boost::optional<PropertyTransition> translate_transition;
boost::optional<TranslateAnchor> translateAnchor;
struct LineClass : public GenericClass {
boost::optional<FunctionProperty> width;
boost::optional<PropertyTransition> width_transition;
boost::optional<FunctionProperty> offset;
@@ -126,54 +142,35 @@ struct LineClass {
boost::optional<PropertyTransition> color_transition;
boost::optional<std::array<FunctionProperty, 2>> dash_array;
boost::optional<PropertyTransition> dash_array_transition;
boost::optional<FunctionProperty> opacity;
boost::optional<PropertyTransition> opacity_transition;
};
struct LineProperties {
bool enabled = true;
std::array<float, 2> translate = {{ 0, 0 }};
TranslateAnchor translateAnchor = TranslateAnchor::Map;
struct LineProperties : public GenericProperties {
float width = 0;
float offset = 0;
Color color = {{ 0, 0, 0, 1 }};
std::array<float, 2> dash_array = {{ 1, -1 }};
float opacity = 1.0;
};
struct FillClass {
boost::optional<FunctionProperty> enabled;
boost::optional<std::array<FunctionProperty, 2>> translate;
boost::optional<PropertyTransition> translate_transition;
boost::optional<TranslateAnchor> translateAnchor;
struct FillClass : public GenericClass {
boost::optional<Winding> winding;
boost::optional<FunctionProperty> antialias;
boost::optional<Color> fill_color;
boost::optional<PropertyTransition> fill_color_transition;
boost::optional<Color> stroke_color;
boost::optional<PropertyTransition> stroke_color_transition;
boost::optional<FunctionProperty> opacity;
boost::optional<PropertyTransition> opacity_transition;
boost::optional<std::string> image;
};
struct FillProperties {
bool enabled = true;
std::array<float, 2> translate = {{ 0, 0 }};
TranslateAnchor translateAnchor = TranslateAnchor::Map;
struct FillProperties : public GenericProperties {
Winding winding = Winding::NonZero;
bool antialias = true;
Color fill_color = {{ 0, 0, 0, 1 }};
Color stroke_color = {{ 0, 0, 0, 1 }};
float opacity = 1.0;
float blur = 0.0f;
std::string image;
};
struct TextClass {
boost::optional<FunctionProperty> enabled;
boost::optional<std::array<FunctionProperty, 2>> translate;
boost::optional<PropertyTransition> translate_transition;
boost::optional<TranslateAnchor> translateAnchor;
struct TextClass : public GenericClass {
boost::optional<Color> color;
boost::optional<PropertyTransition> color_transition;
boost::optional<Color> halo;
@@ -185,14 +182,9 @@ struct TextClass {
boost::optional<FunctionProperty> size;
boost::optional<FunctionProperty> rotate;
boost::optional<FunctionProperty> always_visible;
boost::optional<FunctionProperty> opacity;
boost::optional<PropertyTransition> opacity_transition;
};
struct TextProperties {
bool enabled = true;
std::array<float, 2> translate = {{ 0, 0 }};
TranslateAnchor translateAnchor = TranslateAnchor::Map;
struct TextProperties : public GenericProperties {
Color color = {{ 0, 0, 0, 1 }};
Color halo = {{ 1, 1, 1, 0.75 }};
float halo_radius = 0.25f;
@@ -200,45 +192,28 @@ struct TextProperties {
float size = 12.0f;
float rotate = 0.0f;
bool always_visible = false;
float opacity = 1.0;
};
struct BackgroundClass {
struct BackgroundClass : public GenericClass {
boost::optional<Color> color;
boost::optional<PropertyTransition> color_transition;
boost::optional<FunctionProperty> opacity;
boost::optional<PropertyTransition> opacity_transition;
};
struct BackgroundProperties {
struct BackgroundProperties : public GenericProperties {
Color color = {{ 1, 1, 1, 1 }};
float opacity = 1.0;
};
struct RasterClass {
boost::optional<FunctionProperty> enabled;
boost::optional<std::array<FunctionProperty, 2>> translate;
boost::optional<PropertyTransition> translate_transition;
boost::optional<FunctionProperty> opacity;
boost::optional<PropertyTransition> opacity_transition;
struct RasterClass : public GenericClass {
};
struct RasterProperties {
bool enabled = true;
std::array<float, 2> translate = {{ 0, 0 }};
float opacity = 1.0;
struct RasterProperties : public GenericProperties {
};
struct CompositeClass {
boost::optional<FunctionProperty> enabled;
boost::optional<FunctionProperty> opacity;
boost::optional<PropertyTransition> opacity_transition;
struct CompositeClass : public GenericClass {
};
struct CompositeProperties {
inline CompositeProperties() {}
bool enabled = true;
float opacity = 1.0;
struct CompositeProperties : public GenericProperties {
inline CompositeProperties() : GenericProperties() {}
};

View File

@@ -12,6 +12,7 @@
#include <llmr/util/uv.hpp>
#include <map>
#include <unordered_map>
#include <vector>
#include <set>
#include <memory>
@@ -52,12 +53,12 @@ public:
std::set<std::string> appliedClasses;
struct {
BackgroundProperties background;
std::map<std::string, FillProperties> fills;
std::map<std::string, LineProperties> lines;
std::map<std::string, IconProperties> icons;
std::map<std::string, TextProperties> texts;
std::map<std::string, RasterProperties> rasters;
std::map<std::string, CompositeProperties> composites;
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::map<std::string, std::map<TransitionablePropertyKey, std::string>> effective_classes;
} computed;
@@ -68,28 +69,30 @@ private:
uint64_t transitionDuration(std::string layer_name, TransitionablePropertyKey key);
uint64_t transitionDelay(std::string layer_name, TransitionablePropertyKey key);
void cascadeProperties(GenericProperties &properties, const GenericClass& klass, const std::string& layer_name, const std::string& class_name, float z);
private:
// Last applied settings.
struct {
BackgroundProperties background;
std::map<std::string, FillProperties> fills;
std::map<std::string, LineProperties> lines;
std::map<std::string, IconProperties> icons;
std::map<std::string, TextProperties> texts;
std::map<std::string, RasterProperties> rasters;
std::map<std::string, CompositeProperties> composites;
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::map<std::string, std::map<TransitionablePropertyKey, std::string>> effective_classes;
} previous;
// Settings values currently being transitioned.
struct {
BackgroundProperties background;
std::map<std::string, FillProperties> fills;
std::map<std::string, LineProperties> lines;
std::map<std::string, IconProperties> icons;
std::map<std::string, TextProperties> texts;
std::map<std::string, RasterProperties> rasters;
std::map<std::string, CompositeProperties> composites;
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::map<std::string, std::map<TransitionablePropertyKey, PropertyTransition>> properties_to_transition;

View File

@@ -30,6 +30,7 @@ private:
const std::map<std::string, BucketDescription> &buckets,
const std::map<std::string, std::string> &layerBuckets);
void parseGenericClass(GenericClass &klass, JSVal value);
FillClass parseFillClass(JSVal value);
LineClass parseLineClass(JSVal value);
IconClass parseIconClass(JSVal value);

View File

@@ -85,6 +85,18 @@ struct relaxed_equal {
Value const &lhs;
};
}
template <typename T>
T toNumber(const Value &value) {
if (value.is<std::string>()) return util::string_to_number<T>()(value.get<std::string>());
else if (value.is<bool>()) return value.get<bool>();
else if (value.is<int64_t>()) return value.get<int64_t>();
else if (value.is<uint64_t>()) return value.get<uint64_t>();
else if (value.is<double>()) return value.get<double>();
else return 0;
}
}
#endif

View File

@@ -19,14 +19,17 @@
'src/shader/shaders_gl.cpp',
'src/shader/shaders_gles2.cpp',
],
'action': ['<@(node)', 'bin/build-shaders.js'],
'action': ['<@(node)', 'bin/build-shaders.js', '<(SHARED_INTERMEDIATE_DIR)'],
}
],
'direct_dependent_settings': {
'sources': [
'include/llmr/shader/shaders.hpp',
'src/shader/shaders_gl.cpp',
'src/shader/shaders_gles2.cpp'
'<(SHARED_INTERMEDIATE_DIR)/include/llmr/shader/shaders.hpp',
'<(SHARED_INTERMEDIATE_DIR)/src/shader/shaders_gl.cpp',
'<(SHARED_INTERMEDIATE_DIR)/src/shader/shaders_gles2.cpp'
],
'include_dirs':[
'<(SHARED_INTERMEDIATE_DIR)/include/',
]
}
},
@@ -41,15 +44,19 @@
'bin/style.js',
],
'outputs': [
'include/llmr/style/resources.hpp',
'src/style/resources.cpp'
'<(SHARED_INTERMEDIATE_DIR)/include/llmr/style/resources.hpp',
'<(SHARED_INTERMEDIATE_DIR)/src/style/resources.cpp'
],
'action': ['<@(node)', 'bin/build-style.js', '<@(_inputs)']
'action': ['<@(node)', 'bin/build-style.js', '<@(_inputs)', '<(SHARED_INTERMEDIATE_DIR)']
}
],
'direct_dependent_settings': {
'sources': [
'src/style/resources.cpp'
'<(SHARED_INTERMEDIATE_DIR)/include/llmr/style/resources.hpp',
'<(SHARED_INTERMEDIATE_DIR)/src/style/resources.cpp'
],
'include_dirs':[
'<(SHARED_INTERMEDIATE_DIR)/include/',
]
}
},

View File

@@ -132,10 +132,10 @@ void Map::cleanup(uv_async_t *async) {
void Map::render(uv_async_t *async) {
Map *map = static_cast<Map *>(async->data);
map->prepare();
if (map->state.hasSize()) {
if (map->is_rendered.test_and_set() == false) {
map->prepare();
if (map->is_clean.test_and_set() == false) {
map->render();
map->is_swapped.clear();
@@ -584,18 +584,11 @@ typename Styles::const_iterator find_style(const Styles &styles, const LayerDesc
return it;
}
template <typename Properties>
bool is_invisible(const Properties &properties) {
if (!properties.enabled) { return true; }
if (properties.opacity <= 0) { return true; }
return false;
}
template <typename Styles>
bool is_invisible(const Styles &styles, const LayerDescription &layer_desc) {
auto it = find_style(styles, layer_desc);
if (it == styles.end()) { return true; }
return is_invisible(it->second);
return !it->second.isVisible();
}
void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) {
@@ -604,7 +597,7 @@ void Map::renderLayer(const LayerDescription& layer_desc, RenderPass pass) {
if (pass == Translucent) {
auto it = find_style(style.computed.composites, layer_desc);
const CompositeProperties &properties = (it != style.computed.composites.end()) ? it->second : defaultCompositeProperties;
if (!is_invisible(properties)) {
if (properties.isVisible()) {
gl::group group(std::string("group: ") + layer_desc.name);
if (debug::renderTree) {

View File

@@ -43,6 +43,7 @@ void Painter::setup() {
assert(textShader);
assert(dotShader);
assert(compositeShader);
assert(gaussianShader);
// Blending
@@ -73,6 +74,7 @@ void Painter::setupShaders() {
textShader = std::make_unique<TextShader>();
dotShader = std::make_unique<DotShader>();
compositeShader = std::make_unique<CompositeShader>();
gaussianShader = std::make_unique<GaussianShader>();
}
void Painter::cleanup() {

View File

@@ -3,20 +3,13 @@
#include <llmr/map/map.hpp>
#include <llmr/style/sprite.hpp>
#include <llmr/geometry/sprite_atlas.hpp>
#include <llmr/util/std.hpp>
using namespace llmr;
void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, const Tile::ID& id) {
// Abort early.
if (!bucket.hasData()) return;
auto fill_properties = map.getStyle().computed.fills;
auto fill_properties_it = fill_properties.find(layer_name);
if (fill_properties_it == fill_properties.end()) return;
const FillProperties& properties = fill_properties_it->second;
if (!properties.enabled) return;
void Painter::renderFill(FillBucket& bucket, const FillProperties& properties, const Tile::ID& id, const mat4 &vtxMatrix) {
Color fill_color = properties.fill_color;
fill_color[0] *= properties.opacity;
fill_color[1] *= properties.opacity;
@@ -36,7 +29,6 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
stroke_color = fill_color;
}
const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
// Because we're drawing top-to-bottom, and we update the stencil mask
// below, we have to draw the outline first (!)
@@ -147,3 +139,67 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
bucket.drawVertices(*outlineShader);
}
}
void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, 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);
if (fill_properties_it == fill_properties.end()) return;
const FillProperties& properties = fill_properties_it->second;
if (!properties.enabled) return;
if (properties.prerender) {
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) {
bucket.prerendered = std::make_unique<PrerenderedTexture>(properties.prerenderSize);
bucket.prerendered->bindFramebuffer();
preparePrerender(properties);
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 = 4096 * properties.prerenderBuffer;
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;
}();
pass = Opaque;
renderFill(bucket, modifiedProperties, id, vtxMatrix);
pass = Translucent;
renderFill(bucket, modifiedProperties, id, vtxMatrix);
if (properties.prerenderBlur > 0) {
bucket.prerendered->blur(*this, properties.prerenderBlur);
}
// RESET STATE
bucket.prerendered->unbindFramebuffer();
finishPrerender(properties);
}
renderPrerenderedTexture(bucket, properties);
}
} else {
const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
renderFill(bucket, properties, id, vtxMatrix);
}
}

View File

@@ -11,8 +11,8 @@ void Painter::renderIcon(IconBucket& bucket, const std::string& layer_name, cons
if (!bucket.hasData()) return;
if (pass == Opaque) return;
auto icon_properties = map.getStyle().computed.icons;
auto icon_properties_it = icon_properties.find(layer_name);
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);
if (icon_properties_it == icon_properties.end()) return;
const IconProperties& properties = icon_properties_it->second;

View File

@@ -9,8 +9,8 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons
if (pass == Opaque) return;
if (!bucket.hasData()) return;
auto line_properties = map.getStyle().computed.lines;
auto line_properties_it = line_properties.find(layer_name);
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);
if (line_properties_it == line_properties.end()) return;
const LineProperties& properties = line_properties_it->second;

View File

@@ -0,0 +1,47 @@
#include <llmr/renderer/painter.hpp>
using namespace llmr;
void Painter::preparePrerender(const GenericProperties &properties) {
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
// Render the actual tile.
#if GL_EXT_discard_framebuffer
const GLenum discards[] = {GL_COLOR_ATTACHMENT0};
glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards);
#endif
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, properties.prerenderSize, properties.prerenderSize);
}
void Painter::finishPrerender(const GenericProperties &properties) {
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glViewport(0, 0, gl_viewport[0], gl_viewport[1]);
}
void Painter::renderPrerenderedTexture(Bucket &bucket, const GenericProperties &properties) {
const int buffer = 4096 * properties.prerenderBuffer;
// draw the texture on a quad
depthMask(false);
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);
bucket.prerendered->bindTexture();
coveringRasterArray.bind(*rasterShader, tileStencilBuffer, BUFFER_OFFSET(0));
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index());
depthMask(true);
}

View File

@@ -7,8 +7,8 @@ using namespace llmr;
void Painter::renderRaster(RasterBucket& bucket, const std::string& layer_name, const Tile::ID& /*id*/) {
if (pass == Translucent) return;
auto raster_properties = map.getStyle().computed.rasters;
auto raster_properties_it = raster_properties.find(layer_name);
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);
if (raster_properties_it == raster_properties.end()) return;
const RasterProperties& properties = raster_properties_it->second;
@@ -18,6 +18,7 @@ void Painter::renderRaster(RasterBucket& bucket, const std::string& layer_name,
useProgram(rasterShader->program);
rasterShader->setMatrix(matrix);
rasterShader->setBuffer(0);
rasterShader->setOpacity(1);
// rasterShader->setOpacity(properties.opacity * tile_data->raster->opacity);

View File

@@ -9,8 +9,8 @@ void Painter::renderText(TextBucket& bucket, const std::string& layer_name, cons
if (pass == Opaque) return;
if (!bucket.hasData()) return;
auto text_properties = map.getStyle().computed.texts;
auto text_properties_it = text_properties.find(layer_name);
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);
if (text_properties_it == text_properties.end()) return;
const TextProperties& properties = text_properties_it->second;

View File

@@ -0,0 +1,137 @@
#include <llmr/renderer/prerendered_texture.hpp>
#include <llmr/renderer/painter.hpp>
using namespace llmr;
PrerenderedTexture::PrerenderedTexture(uint16_t size)
: size(size) {
}
PrerenderedTexture::~PrerenderedTexture() {
if (texture != 0) {
glDeleteTextures(1, &texture);
texture = 0;
}
if (fbo != 0) {
glDeleteFramebuffers(1, &fbo);
fbo = 0;
}
}
void PrerenderedTexture::bindTexture() {
if (texture == 0) {
bindFramebuffer();
unbindFramebuffer();
}
glBindTexture(GL_TEXTURE_2D, texture);
// if (!mipmapped) {
// glGenerateMipmap(GL_TEXTURE_2D);
// mipmapped = true;
// }
}
void PrerenderedTexture::bindFramebuffer() {
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previous_fbo);
if (texture == 0) {
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}
if (fbo == 0) {
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "Couldn't create framebuffer: ");
switch (status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: fprintf(stderr, "incomplete attachment\n"); break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: fprintf(stderr, "incomplete missing attachment\n"); break;
#ifdef GL_ES_VERSION_2_0
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: fprintf(stderr, "incomplete dimensions\n"); break;
#else
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: fprintf(stderr, "incomplete draw buffer\n"); break;
#endif
case GL_FRAMEBUFFER_UNSUPPORTED: fprintf(stderr, "unsupported\n"); break;
default: fprintf(stderr, "other\n"); break;
}
return;
}
} else {
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
}
}
void PrerenderedTexture::unbindFramebuffer() {
glBindFramebuffer(GL_FRAMEBUFFER, previous_fbo);
if (fbo != 0) {
glDeleteFramebuffers(1, &fbo);
fbo = 0;
}
}
void PrerenderedTexture::blur(Painter& painter, uint16_t passes) {
const GLuint original_texture = texture;
// Create a secondary texture
GLuint secondary_texture;
glGenTextures(1, &secondary_texture);
glBindTexture(GL_TEXTURE_2D, secondary_texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
painter.useProgram(painter.gaussianShader->program);
painter.gaussianShader->setMatrix(painter.flipMatrix);
painter.gaussianShader->setImage(0);
glActiveTexture(GL_TEXTURE0);
for (int i = 0; i < passes; i++) {
// Render horizontal
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, secondary_texture, 0);
#if GL_EXT_discard_framebuffer
const GLenum discards[] = { GL_COLOR_ATTACHMENT0 };
glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards);
#endif
glClear(GL_COLOR_BUFFER_BIT);
painter.gaussianShader->setOffset({{ 1.0f / float(size), 0 }});
glBindTexture(GL_TEXTURE_2D, original_texture);
painter.coveringGaussianArray.bind(*painter.gaussianShader, painter.tileStencilBuffer, BUFFER_OFFSET(0));
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)painter.tileStencilBuffer.index());
// Render vertical
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, original_texture, 0);
#if GL_EXT_discard_framebuffer
glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards);
#endif
glClear(GL_COLOR_BUFFER_BIT);
painter.gaussianShader->setOffset({{ 0, 1.0f / float(size) }});
glBindTexture(GL_TEXTURE_2D, secondary_texture);
painter.coveringGaussianArray.bind(*painter.gaussianShader, painter.tileStencilBuffer, BUFFER_OFFSET(0));
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)painter.tileStencilBuffer.index());
}
glDeleteTextures(1, &secondary_texture);
}

View File

@@ -0,0 +1,12 @@
uniform sampler2D u_image;
varying vec2 v_coords[3];
void main()
{
vec4 sum = vec4(0.0);
sum += texture2D(u_image, v_coords[0]) * 0.40261994689424746;
sum += texture2D(u_image, v_coords[1]) * 0.2986900265528763;
sum += texture2D(u_image, v_coords[2]) * 0.2986900265528763;
gl_FragColor = sum;
}

View File

@@ -0,0 +1,15 @@
attribute vec2 a_pos;
uniform mat4 u_matrix;
uniform vec2 u_offset;
varying vec2 v_coords[3];
void main() {
gl_Position = u_matrix * vec4(a_pos, 0, 1);
vec2 tex = (gl_Position.xy + 1.0) / 2.0;
v_coords[0] = tex;
v_coords[1] = tex + u_offset * 1.1824255238063563;
v_coords[2] = tex - u_offset * 1.1824255238063563;
}

View File

@@ -0,0 +1,48 @@
#include <llmr/shader/gaussian_shader.hpp>
#include <llmr/shader/shaders.hpp>
#include <llmr/platform/gl.hpp>
#include <cstdio>
using namespace llmr;
GaussianShader::GaussianShader()
: Shader(
shaders[GAUSSIAN_SHADER].vertex,
shaders[GAUSSIAN_SHADER].fragment
) {
if (!valid) {
fprintf(stderr, "invalid raster shader\n");
return;
}
a_pos = glGetAttribLocation(program, "a_pos");
u_matrix = glGetUniformLocation(program, "u_matrix");
u_image = glGetUniformLocation(program, "u_image");
u_offset = glGetUniformLocation(program, "u_offset");
// fprintf(stderr, "GaussianShader:\n");
// fprintf(stderr, " - u_matrix: %d\n", u_matrix);
// fprintf(stderr, " - u_image: %d\n", u_image);
// fprintf(stderr, " - u_gaussian: %f\n", u_gaussian);
}
void GaussianShader::bind(char *offset) {
glEnableVertexAttribArray(a_pos);
glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset);
}
void GaussianShader::setImage(int32_t new_image) {
if (image != new_image) {
glUniform1i(u_image, new_image);
image = new_image;
}
}
void GaussianShader::setOffset(const std::array<float, 2>& new_offset) {
if (offset != new_offset) {
glUniform2fv(u_offset, 1, new_offset.data());
offset = new_offset;
}
}

View File

@@ -4,5 +4,5 @@ uniform float u_opacity;
varying vec2 v_pos;
void main() {
gl_FragColor = texture2D(u_image, v_pos) * u_opacity;
gl_FragColor = texture2D(u_image, v_pos, 2) * u_opacity;
}

View File

@@ -1,10 +1,13 @@
uniform mat4 u_matrix;
uniform float u_buffer;
attribute vec2 a_pos;
varying vec2 v_pos;
void main() {
gl_Position = u_matrix * vec4(a_pos, 0, 1);
v_pos = a_pos / 4096.0;
float dimension = (4096.0 + 2.0 * u_buffer);
v_pos = (a_pos / dimension) + (u_buffer / dimension);
}

View File

@@ -21,11 +21,13 @@ RasterShader::RasterShader()
u_matrix = glGetUniformLocation(program, "u_matrix");
u_image = glGetUniformLocation(program, "u_image");
u_opacity = glGetUniformLocation(program, "u_opacity");
u_buffer = glGetUniformLocation(program, "u_buffer");
// fprintf(stderr, "RasterShader:\n");
// fprintf(stderr, " - u_matrix: %d\n", u_matrix);
// fprintf(stderr, " - u_image: %d\n", u_image);
// fprintf(stderr, " - u_opacity: %f\n", u_opacity);
// fprintf(stderr, " - u_buffer: %f\n", u_buffer);
}
void RasterShader::bind(char *offset) {
@@ -46,3 +48,10 @@ void RasterShader::setOpacity(float new_opacity) {
opacity = new_opacity;
}
}
void RasterShader::setBuffer(float new_buffer) {
if (buffer != new_buffer) {
glUniform1f(u_buffer, new_buffer);
buffer = new_buffer;
}
}

View File

@@ -1,50 +0,0 @@
// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
#include <llmr/platform/gl.hpp>
#ifndef GL_ES_VERSION_2_0
#include <llmr/shader/shaders.hpp>
using namespace llmr;
const shader_source llmr::shaders[SHADER_COUNT] = {
{
"#version 120\nattribute vec2 a_pos;\n\nuniform mat4 u_matrix;\nvarying vec2 v_pos;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n v_pos = (gl_Position.xy + 1.0) / 2.0;\n}\n",
"#version 120\nuniform sampler2D u_image;\nuniform float u_opacity;\n\nvarying vec2 v_pos;\n\nvoid main() {\n vec4 color = texture2D(u_image, v_pos);\n gl_FragColor = color * u_opacity;\n}\n",
},
{
"#version 120\nattribute vec2 a_pos;\n\nuniform mat4 u_matrix;\nuniform float u_size;\n\nvoid main(void) {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n gl_PointSize = u_size;\n}\n",
"#version 120\nuniform vec4 u_color;\nuniform float u_blur;\n\nvoid main() {\n\tfloat dist = length(gl_PointCoord - 0.5);\n\tfloat t = smoothstep(0.5, 0.5 - u_blur, dist);\n\n gl_FragColor = u_color * t;\n}\n",
},
{
"#version 120\nattribute vec2 a_pos;\nattribute vec2 a_tex;\n\nuniform mat4 u_matrix;\nuniform float u_size;\nuniform float u_ratio;\n\nvarying vec2 v_tex;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n gl_PointSize = u_size;\n v_tex = a_tex * u_ratio;\n}\n",
"#version 120\nuniform sampler2D u_image;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\n\nvarying vec2 v_tex;\n\nvoid main() {\n vec2 pos = (v_tex + (gl_PointCoord - 0.5) * u_size) / u_dimension;\n gl_FragColor = u_color * texture2D(u_image, pos);\n}\n",
},
{
"#version 120\n// floor(127 / 2) == 63.0\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\n// there are also \"special\" normals that have a bigger length (of up to 126 in\n// this case).\n// #define scale 63.0\n#define scale 0.015873016\n\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\n\n// posmatrix is for the vertex position, exmatrix is for rotating and projecting\n// the extrusion vector.\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\n\n// shared\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\n\nvoid main() {\n // We store the texture normals in the most insignificant bit\n // transform y so that 0 => -1 and 1 => 1\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\n // y is 1 if the normal points up, and -1 if it points down\n vec2 normal = mod(a_pos, 2.0);\n normal.y = sign(normal.y - 0.5);\n v_normal = normal;\n\n // Scale the extrusion vector down to a normal and then up by the line width\n // of this vertex.\n vec4 dist = vec4(u_linewidth.s * a_extrude * scale, 0.0, 0.0);\n\n // Remove the texture normal bit of the position before scaling it with the\n // model/view matrix. Add the extrusion vector *after* the model/view matrix\n // because we're extruding the line in pixel space, regardless of the current\n // tile's zoom level.\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0.0, 1.0) + u_exmatrix * dist;\n v_linesofar = a_linesofar * u_ratio;\n}",
"#version 120\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\n\nuniform vec2 u_dasharray;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\n\nvoid main() {\n // Calculate the distance of the pixel from the line in pixels.\n float dist = length(v_normal) * u_linewidth.s;\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float alpha = clamp(min(dist - (u_linewidth.t - 1.0), u_linewidth.s - dist), 0.0, 1.0);\n\n // Calculate the antialiasing fade factor based on distance to the dash.\n // Only affects alpha when line is dashed\n float pos = mod(v_linesofar, u_dasharray.x + u_dasharray.y);\n alpha *= max(step(0.0, -u_dasharray.y), clamp(min(pos, u_dasharray.x - pos), 0.0, 1.0));\n\n gl_FragColor = u_color * alpha;\n}",
},
{
"#version 120\nattribute vec2 a_pos;\n\nuniform mat4 u_matrix;\nuniform vec2 u_world;\nuniform float u_size;\n\nvarying vec2 v_pos;\n\nvoid main() {\n gl_Position = u_matrix * vec4(floor(a_pos / 2.0), 0.0, 1.0);\n v_pos = (gl_Position.xy + 1.0) * u_world;\n gl_PointSize = u_size;\n}\n",
"#version 120\nuniform vec4 u_color;\nuniform vec2 u_linewidth;\n\nvarying vec2 v_pos;\n\nvoid main() {\n float dist = length(v_pos - gl_FragCoord.xy);\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float alpha = clamp(min(dist - (u_linewidth.t - 1.0), u_linewidth.s - dist), 0.0, 1.0);\n gl_FragColor = u_color * alpha;\n}\n",
},
{
"#version 120\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform vec2 u_world;\n\nvarying vec2 v_pos;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n v_pos = (gl_Position.xy + 1.0) / 2.0 * u_world;\n}\n",
"#version 120\nuniform vec4 u_color;\n\nvarying vec2 v_pos;\n\nvoid main() {\n float dist = length(v_pos - gl_FragCoord.xy);\n float alpha = smoothstep(1.0, 0.0, dist);\n gl_FragColor = u_color * alpha;\n}\n",
},
{
"#version 120\nuniform mat4 u_matrix;\n\nattribute vec2 a_pos;\n\nvarying vec2 v_pos;\n\nvoid main() {\n v_pos = a_pos;\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n}\n",
"#version 120\nuniform vec4 u_color;\n\nuniform vec2 u_offset;\nuniform vec2 u_pattern_size;\nuniform vec2 u_pattern_tl;\nuniform vec2 u_pattern_br;\nuniform float u_mix;\n\n\nuniform sampler2D u_image;\n\nvarying vec2 v_pos;\n\nvoid main() {\n\n vec2 imagecoord = mod((v_pos + u_offset) / u_pattern_size, 1.0);\n vec2 pos = mix(u_pattern_tl, u_pattern_br, imagecoord);\n vec4 color1 = texture2D(u_image, pos);\n\n vec2 imagecoord2 = mod(imagecoord * 2.0, 1.0);\n vec2 pos2 = mix(u_pattern_tl, u_pattern_br, imagecoord2);\n vec4 color2 = texture2D(u_image, pos2);\n\n vec4 color = mix(color1, color2, u_mix);\n gl_FragColor = color + u_color * (1.0 - color.a);\n}\n",
},
{
"#version 120\nattribute vec2 a_pos;\n\nuniform mat4 u_matrix;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n}\n",
"#version 120\nuniform vec4 u_color;\n\nvoid main() {\n gl_FragColor = u_color;\n}\n",
},
{
"#version 120\nuniform mat4 u_matrix;\n\nattribute vec2 a_pos;\n\nvarying vec2 v_pos;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n v_pos = a_pos / 4096.0;\n}\n",
"#version 120\nuniform sampler2D u_image;\nuniform float u_opacity;\n\nvarying vec2 v_pos;\n\nvoid main() {\n gl_FragColor = texture2D(u_image, v_pos) * u_opacity;\n}\n",
},
{
"#version 120\nattribute vec2 a_pos;\nattribute vec2 a_offset;\nattribute vec4 a_data1;\nattribute vec4 a_data2;\n\n\n// posmatrix is for the vertex position, exmatrix is for rotating and projecting\n// the extrusion vector.\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_angle;\nuniform float u_zoom;\nuniform float u_flip;\nuniform float u_fadedist;\nuniform float u_minfadezoom;\nuniform float u_maxfadezoom;\nuniform float u_fadezoom;\n\nuniform vec2 u_texsize;\n\nvarying vec2 v_tex;\nvarying float v_alpha;\n\nvoid main() {\n vec2 a_tex = a_data1.xy;\n float a_labelminzoom = a_data1[2];\n float a_angle = a_data1[3];\n vec2 a_zoom = a_data2.st;\n vec2 a_range = a_data2.pq;\n\n float rev = 0.0;\n\n // u_angle is angle of the map, -128..128 representing 0..2PI\n // a_angle is angle of the label, 0..256 representing 0..2PI, where 0 is horizontal text\n float rotated = mod(a_angle + u_angle, 256.0);\n // if the label rotates with the map, and if the rotated label is upside down, hide it\n if (u_flip > 0.0 && rotated >= 64.0 && rotated < 192.0) rev = 1.0;\n\n // If the label should be invisible, we move the vertex outside\n // of the view plane so that the triangle gets clipped. This makes it easier\n // for us to create degenerate triangle strips.\n // u_zoom is the current zoom level adjusted for the change in font size\n float z = 2.0 - step(a_zoom[0], u_zoom) - (1.0 - step(a_zoom[1], u_zoom)) + rev;\n\n // fade out labels\n float alpha = clamp((u_fadezoom - a_labelminzoom) / u_fadedist, 0.0, 1.0);\n\n if (u_fadedist >= 0.0) {\n v_alpha = alpha;\n } else {\n v_alpha = 1.0 - alpha;\n }\n if (u_maxfadezoom < a_labelminzoom) {\n v_alpha = 0.0;\n }\n if (u_minfadezoom >= a_labelminzoom) {\n v_alpha = 1.0;\n }\n\n // if label has been faded out, clip it\n z += step(v_alpha, 0.0);\n\n // all the angles are 0..256 representing 0..2PI\n // hide if (angle >= a_rangeend && angle < rangestart)\n z += step(a_range[0], u_angle) * (1.0 - step(a_range[1], u_angle));\n\n gl_Position = u_matrix * vec4(a_pos, 0, 1) + u_exmatrix * vec4(a_offset / 64.0, z, 0);\n v_tex = a_tex * 4.0 / u_texsize;\n}\n",
"#version 120\nuniform sampler2D u_texture;\nuniform vec4 u_color;\nuniform float u_buffer;\nuniform float u_gamma;\n\nvarying vec2 v_tex;\nvarying float v_alpha;\n\nvoid main() {\n float dist = texture2D(u_texture, v_tex).a;\n float alpha = smoothstep(u_buffer - u_gamma, u_buffer + u_gamma, dist) * v_alpha;\n gl_FragColor = u_color * alpha;\n}\n",
}
};
#endif

View File

@@ -1,50 +0,0 @@
// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
#include <llmr/platform/gl.hpp>
#ifdef GL_ES_VERSION_2_0
#include <llmr/shader/shaders.hpp>
using namespace llmr;
const shader_source llmr::shaders[SHADER_COUNT] = {
{
"precision highp float;\nattribute vec2 a_pos;\n\nuniform mat4 u_matrix;\nvarying vec2 v_pos;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n v_pos = (gl_Position.xy + 1.0) / 2.0;\n}\n",
"precision highp float;\nuniform sampler2D u_image;\nuniform float u_opacity;\n\nvarying vec2 v_pos;\n\nvoid main() {\n vec4 color = texture2D(u_image, v_pos);\n gl_FragColor = color * u_opacity;\n}\n",
},
{
"precision highp float;\nattribute vec2 a_pos;\n\nuniform mat4 u_matrix;\nuniform float u_size;\n\nvoid main(void) {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n gl_PointSize = u_size;\n}\n",
"precision highp float;\nuniform vec4 u_color;\nuniform float u_blur;\n\nvoid main() {\n\tfloat dist = length(gl_PointCoord - 0.5);\n\tfloat t = smoothstep(0.5, 0.5 - u_blur, dist);\n\n gl_FragColor = u_color * t;\n}\n",
},
{
"precision highp float;\nattribute vec2 a_pos;\nattribute vec2 a_tex;\n\nuniform mat4 u_matrix;\nuniform float u_size;\nuniform float u_ratio;\n\nvarying vec2 v_tex;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n gl_PointSize = u_size;\n v_tex = a_tex * u_ratio;\n}\n",
"precision highp float;\nuniform sampler2D u_image;\nuniform vec2 u_dimension;\nuniform vec4 u_color;\nuniform float u_size;\n\nvarying vec2 v_tex;\n\nvoid main() {\n vec2 pos = (v_tex + (gl_PointCoord - 0.5) * u_size) / u_dimension;\n gl_FragColor = u_color * texture2D(u_image, pos);\n}\n",
},
{
"precision highp float;\n// floor(127 / 2) == 63.0\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\n// there are also \"special\" normals that have a bigger length (of up to 126 in\n// this case).\n// #define scale 63.0\n#define scale 0.015873016\n\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\n\n// posmatrix is for the vertex position, exmatrix is for rotating and projecting\n// the extrusion vector.\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\n\n// shared\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\n\nvoid main() {\n // We store the texture normals in the most insignificant bit\n // transform y so that 0 => -1 and 1 => 1\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\n // y is 1 if the normal points up, and -1 if it points down\n vec2 normal = mod(a_pos, 2.0);\n normal.y = sign(normal.y - 0.5);\n v_normal = normal;\n\n // Scale the extrusion vector down to a normal and then up by the line width\n // of this vertex.\n vec4 dist = vec4(u_linewidth.s * a_extrude * scale, 0.0, 0.0);\n\n // Remove the texture normal bit of the position before scaling it with the\n // model/view matrix. Add the extrusion vector *after* the model/view matrix\n // because we're extruding the line in pixel space, regardless of the current\n // tile's zoom level.\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0.0, 1.0) + u_exmatrix * dist;\n v_linesofar = a_linesofar * u_ratio;\n}",
"precision highp float;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\n\nuniform vec2 u_dasharray;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\n\nvoid main() {\n // Calculate the distance of the pixel from the line in pixels.\n float dist = length(v_normal) * u_linewidth.s;\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float alpha = clamp(min(dist - (u_linewidth.t - 1.0), u_linewidth.s - dist), 0.0, 1.0);\n\n // Calculate the antialiasing fade factor based on distance to the dash.\n // Only affects alpha when line is dashed\n float pos = mod(v_linesofar, u_dasharray.x + u_dasharray.y);\n alpha *= max(step(0.0, -u_dasharray.y), clamp(min(pos, u_dasharray.x - pos), 0.0, 1.0));\n\n gl_FragColor = u_color * alpha;\n}",
},
{
"precision highp float;\nattribute vec2 a_pos;\n\nuniform mat4 u_matrix;\nuniform vec2 u_world;\nuniform float u_size;\n\nvarying vec2 v_pos;\n\nvoid main() {\n gl_Position = u_matrix * vec4(floor(a_pos / 2.0), 0.0, 1.0);\n v_pos = (gl_Position.xy + 1.0) * u_world;\n gl_PointSize = u_size;\n}\n",
"precision highp float;\nuniform vec4 u_color;\nuniform vec2 u_linewidth;\n\nvarying vec2 v_pos;\n\nvoid main() {\n float dist = length(v_pos - gl_FragCoord.xy);\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float alpha = clamp(min(dist - (u_linewidth.t - 1.0), u_linewidth.s - dist), 0.0, 1.0);\n gl_FragColor = u_color * alpha;\n}\n",
},
{
"precision highp float;\nattribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform vec2 u_world;\n\nvarying vec2 v_pos;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n v_pos = (gl_Position.xy + 1.0) / 2.0 * u_world;\n}\n",
"precision highp float;\nuniform vec4 u_color;\n\nvarying vec2 v_pos;\n\nvoid main() {\n float dist = length(v_pos - gl_FragCoord.xy);\n float alpha = smoothstep(1.0, 0.0, dist);\n gl_FragColor = u_color * alpha;\n}\n",
},
{
"precision highp float;\nuniform mat4 u_matrix;\n\nattribute vec2 a_pos;\n\nvarying vec2 v_pos;\n\nvoid main() {\n v_pos = a_pos;\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n}\n",
"precision highp float;\nuniform vec4 u_color;\n\nuniform vec2 u_offset;\nuniform vec2 u_pattern_size;\nuniform vec2 u_pattern_tl;\nuniform vec2 u_pattern_br;\nuniform float u_mix;\n\n\nuniform sampler2D u_image;\n\nvarying vec2 v_pos;\n\nvoid main() {\n\n vec2 imagecoord = mod((v_pos + u_offset) / u_pattern_size, 1.0);\n vec2 pos = mix(u_pattern_tl, u_pattern_br, imagecoord);\n vec4 color1 = texture2D(u_image, pos);\n\n vec2 imagecoord2 = mod(imagecoord * 2.0, 1.0);\n vec2 pos2 = mix(u_pattern_tl, u_pattern_br, imagecoord2);\n vec4 color2 = texture2D(u_image, pos2);\n\n vec4 color = mix(color1, color2, u_mix);\n gl_FragColor = color + u_color * (1.0 - color.a);\n}\n",
},
{
"precision highp float;\nattribute vec2 a_pos;\n\nuniform mat4 u_matrix;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n}\n",
"precision highp float;\nuniform vec4 u_color;\n\nvoid main() {\n gl_FragColor = u_color;\n}\n",
},
{
"precision highp float;\nuniform mat4 u_matrix;\n\nattribute vec2 a_pos;\n\nvarying vec2 v_pos;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n v_pos = a_pos / 4096.0;\n}\n",
"precision highp float;\nuniform sampler2D u_image;\nuniform float u_opacity;\n\nvarying vec2 v_pos;\n\nvoid main() {\n gl_FragColor = texture2D(u_image, v_pos) * u_opacity;\n}\n",
},
{
"precision highp float;\nattribute vec2 a_pos;\nattribute vec2 a_offset;\nattribute vec4 a_data1;\nattribute vec4 a_data2;\n\n\n// posmatrix is for the vertex position, exmatrix is for rotating and projecting\n// the extrusion vector.\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\nuniform float u_angle;\nuniform float u_zoom;\nuniform float u_flip;\nuniform float u_fadedist;\nuniform float u_minfadezoom;\nuniform float u_maxfadezoom;\nuniform float u_fadezoom;\n\nuniform vec2 u_texsize;\n\nvarying vec2 v_tex;\nvarying float v_alpha;\n\nvoid main() {\n vec2 a_tex = a_data1.xy;\n float a_labelminzoom = a_data1[2];\n float a_angle = a_data1[3];\n vec2 a_zoom = a_data2.st;\n vec2 a_range = a_data2.pq;\n\n float rev = 0.0;\n\n // u_angle is angle of the map, -128..128 representing 0..2PI\n // a_angle is angle of the label, 0..256 representing 0..2PI, where 0 is horizontal text\n float rotated = mod(a_angle + u_angle, 256.0);\n // if the label rotates with the map, and if the rotated label is upside down, hide it\n if (u_flip > 0.0 && rotated >= 64.0 && rotated < 192.0) rev = 1.0;\n\n // If the label should be invisible, we move the vertex outside\n // of the view plane so that the triangle gets clipped. This makes it easier\n // for us to create degenerate triangle strips.\n // u_zoom is the current zoom level adjusted for the change in font size\n float z = 2.0 - step(a_zoom[0], u_zoom) - (1.0 - step(a_zoom[1], u_zoom)) + rev;\n\n // fade out labels\n float alpha = clamp((u_fadezoom - a_labelminzoom) / u_fadedist, 0.0, 1.0);\n\n if (u_fadedist >= 0.0) {\n v_alpha = alpha;\n } else {\n v_alpha = 1.0 - alpha;\n }\n if (u_maxfadezoom < a_labelminzoom) {\n v_alpha = 0.0;\n }\n if (u_minfadezoom >= a_labelminzoom) {\n v_alpha = 1.0;\n }\n\n // if label has been faded out, clip it\n z += step(v_alpha, 0.0);\n\n // all the angles are 0..256 representing 0..2PI\n // hide if (angle >= a_rangeend && angle < rangestart)\n z += step(a_range[0], u_angle) * (1.0 - step(a_range[1], u_angle));\n\n gl_Position = u_matrix * vec4(a_pos, 0, 1) + u_exmatrix * vec4(a_offset / 64.0, z, 0);\n v_tex = a_tex * 4.0 / u_texsize;\n}\n",
"precision highp float;\nuniform sampler2D u_texture;\nuniform vec4 u_color;\nuniform float u_buffer;\nuniform float u_gamma;\n\nvarying vec2 v_tex;\nvarying float v_alpha;\n\nvoid main() {\n float dist = texture2D(u_texture, v_tex).a;\n float alpha = smoothstep(u_buffer - u_gamma, u_buffer + u_gamma, dist) * v_alpha;\n gl_FragColor = u_color * alpha;\n}\n",
}
};
#endif

View File

@@ -25,20 +25,64 @@ void Style::reset() {
properties_to_transition.clear();
}
void Style::cascadeProperties(GenericProperties &properties, const GenericClass& klass, const std::string& layer_name, const std::string& class_name, float z) {
if (klass.enabled) {
properties.enabled = klass.enabled.get().evaluate<bool>(z);
}
if (klass.translate) {
properties.translate = {{ klass.translate.get()[0].evaluate<float>(z),
klass.translate.get()[1].evaluate<float>(z) }};
computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name;
if (klass.translate_transition && klass.translate_transition.get().duration) {
properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = klass.translate_transition.get();
}
}
if (klass.translateAnchor) {
properties.translateAnchor = klass.translateAnchor.get();
}
if (klass.opacity) {
properties.opacity = klass.opacity.get().evaluate<float>(z);
computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name;
if (klass.opacity_transition && klass.opacity_transition.get().duration) {
properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = klass.opacity_transition.get();
}
}
if (klass.prerender) {
properties.prerender = klass.prerender.get();
}
if (klass.prerenderBuffer) {
properties.prerenderBuffer = klass.prerenderBuffer.get();
}
if (klass.prerenderSize) {
properties.prerenderSize = klass.prerenderSize.get();
}
if (klass.prerenderBlur) {
properties.prerenderBlur = klass.prerenderBlur.get();
}
}
void Style::cascade(float z) {
uv::writelock lock(mtx);
time start = util::now();
previous.fills = computed.fills;
previous.lines = computed.lines;
previous.icons = computed.icons;
previous.texts = computed.texts;
previous.rasters = computed.rasters;
previous.composites = computed.composites;
previous.fills.swap(computed.fills);
previous.lines.swap(computed.lines);
previous.icons.swap(computed.icons);
previous.texts.swap(computed.texts);
previous.rasters.swap(computed.rasters);
previous.composites.swap(computed.composites);
previous.background = computed.background;
previous.effective_classes = computed.effective_classes;
previous.effective_classes.swap(computed.effective_classes);
reset();
@@ -62,22 +106,7 @@ void Style::cascade(float z) {
llmr::FillProperties& fill = computed.fills[layer_name];
if (layer.enabled) {
fill.enabled = layer.enabled.get().evaluate<bool>(z);
}
if (layer.translate) {
fill.translate = {{ layer.translate.get()[0].evaluate<float>(z),
layer.translate.get()[1].evaluate<float>(z) }};
computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name;
if (layer.translate_transition && layer.translate_transition.get().duration) {
properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition.get();
}
}
if (layer.translateAnchor) {
fill.translateAnchor = layer.translateAnchor.get();
}
cascadeProperties(fill, layer, layer_name, class_name, z);
if (layer.winding) {
fill.winding = layer.winding.get();
@@ -103,14 +132,6 @@ void Style::cascade(float z) {
}
}
if (layer.opacity) {
fill.opacity = layer.opacity.get().evaluate<float>(z);
computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name;
if (layer.opacity_transition && layer.opacity_transition.get().duration) {
properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition.get();
}
}
if (layer.image) {
fill.image = layer.image.get();
}
@@ -123,22 +144,7 @@ void Style::cascade(float z) {
llmr::LineProperties& stroke = computed.lines[layer_name];
if (layer.enabled) {
stroke.enabled = layer.enabled.get().evaluate<bool>(z);
}
if (layer.translate) {
stroke.translate = {{ layer.translate.get()[0].evaluate<float>(z),
layer.translate.get()[1].evaluate<float>(z) }};
computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name;
if (layer.translate_transition && layer.translate_transition.get().duration) {
properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition.get();
}
}
if (layer.translateAnchor) {
stroke.translateAnchor = layer.translateAnchor.get();
}
cascadeProperties(stroke, layer, layer_name, class_name, z);
if (layer.width) {
stroke.width = layer.width.get().evaluate<float>(z);
@@ -173,14 +179,6 @@ void Style::cascade(float z) {
properties_to_transition[layer_name][TransitionablePropertyKey::DashArray] = layer.dash_array_transition.get();
}
}
if (layer.opacity) {
stroke.opacity = layer.opacity.get().evaluate<float>(z);
computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name;
if (layer.opacity_transition && layer.opacity_transition.get().duration) {
properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition.get();
}
}
}
// Cascade icon classes.
@@ -190,22 +188,7 @@ void Style::cascade(float z) {
llmr::IconProperties& icon = computed.icons[layer_name];
if (layer.enabled) {
icon.enabled = layer.enabled.get().evaluate<bool>(z);
}
if (layer.translate) {
icon.translate = {{ layer.translate.get()[0].evaluate<float>(z),
layer.translate.get()[1].evaluate<float>(z) }};
computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name;
if (layer.translate_transition && layer.translate_transition.get().duration) {
properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition.get();
}
}
if (layer.translateAnchor) {
icon.translateAnchor = layer.translateAnchor.get();
}
cascadeProperties(icon, layer, layer_name, class_name, z);
if (layer.color) {
icon.color = layer.color.get();
@@ -219,14 +202,6 @@ void Style::cascade(float z) {
icon.size = layer.size.get().evaluate<float>(z);
}
if (layer.opacity) {
icon.opacity = layer.opacity.get().evaluate<float>(z);
computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name;
if (layer.opacity_transition && layer.opacity_transition.get().duration) {
properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition.get();
}
}
if (layer.image) {
icon.image = layer.image.get();
}
@@ -255,22 +230,7 @@ void Style::cascade(float z) {
llmr::TextProperties& text = computed.texts[layer_name];
if (layer.enabled) {
text.enabled = layer.enabled.get().evaluate<bool>(z);
}
if (layer.translate) {
text.translate = {{ layer.translate.get()[0].evaluate<float>(z),
layer.translate.get()[1].evaluate<float>(z) }};
computed.effective_classes[layer_name][TransitionablePropertyKey::Translate] = class_name;
if (layer.translate_transition && layer.translate_transition.get().duration) {
properties_to_transition[layer_name][TransitionablePropertyKey::Translate] = layer.translate_transition.get();
}
}
if (layer.translateAnchor) {
text.translateAnchor = layer.translateAnchor.get();
}
cascadeProperties(text, layer, layer_name, class_name, z);
if (layer.color) {
text.color = layer.color.get();
@@ -315,14 +275,6 @@ void Style::cascade(float z) {
if (layer.always_visible) {
text.always_visible = layer.always_visible.get().evaluate<bool>(z);
}
if (layer.opacity) {
text.opacity = layer.opacity.get().evaluate<float>(z);
computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name;
if (layer.opacity_transition && layer.opacity_transition.get().duration) {
properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition.get();
}
}
}
// Cascade raster classes.
@@ -332,17 +284,7 @@ void Style::cascade(float z) {
llmr::RasterProperties& raster = computed.rasters[layer_name];
if (layer.enabled) {
raster.enabled = layer.enabled.get().evaluate<bool>(z);
}
if (layer.opacity) {
raster.opacity = layer.opacity.get().evaluate<float>(z);
computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name;
if (layer.opacity_transition && layer.opacity_transition.get().duration) {
properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition.get();
}
}
cascadeProperties(raster, layer, layer_name, class_name, z);
}
// Cascade composite classes.
@@ -352,21 +294,13 @@ void Style::cascade(float z) {
llmr::CompositeProperties& composite = computed.composites[layer_name];
if (layer.enabled) {
composite.enabled = layer.enabled.get().evaluate<bool>(z);
}
if (layer.opacity) {
composite.opacity = layer.opacity.get().evaluate<float>(z);
computed.effective_classes[layer_name][TransitionablePropertyKey::Opacity] = class_name;
if (layer.opacity_transition && layer.opacity_transition.get().duration) {
properties_to_transition[layer_name][TransitionablePropertyKey::Opacity] = layer.opacity_transition.get();
}
}
cascadeProperties(composite, layer, layer_name, class_name, z);
}
// Cascade background.
{
cascadeProperties(computed.background, sheetClass.background, "background", class_name, z);
if (sheetClass.background.color) {
computed.background.color = sheetClass.background.color.get();
computed.effective_classes["background"][TransitionablePropertyKey::Color] = class_name;
@@ -374,13 +308,6 @@ void Style::cascade(float z) {
properties_to_transition["background"][TransitionablePropertyKey::Color] = sheetClass.background.color_transition.get();
}
}
if (sheetClass.background.opacity) {
computed.background.opacity = sheetClass.background.opacity.get().evaluate<float>(z);
computed.effective_classes["background"][TransitionablePropertyKey::Opacity] = class_name;
if (sheetClass.background.opacity_transition && sheetClass.background.opacity_transition.get().duration) {
properties_to_transition["background"][TransitionablePropertyKey::Opacity] = sheetClass.background.opacity_transition.get();
}
}
}
}

View File

@@ -500,10 +500,8 @@ PropertyTransition StyleParser::parseTransition(JSVal value, std::string propert
return transition;
}
FillClass StyleParser::parseFillClass(JSVal value) {
FillClass klass;
if (value.HasMember("enabled")) {
void StyleParser::parseGenericClass(GenericClass &klass, JSVal value) {
if (value.HasMember("enabled")) {
klass.enabled = parseFunction(value["enabled"]);
}
@@ -517,6 +515,33 @@ FillClass StyleParser::parseFillClass(JSVal value) {
klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]);
}
if (value.HasMember("opacity")) {
klass.opacity = parseFunction(value["opacity"]);
klass.opacity_transition = parseTransition(value, "opacity");
}
if (value.HasMember("prerender")) {
klass.prerender = parseBoolean(value["prerender"]);
}
if (value.HasMember("prerender-buffer")) {
klass.prerenderBuffer = toNumber<double>(parseValue(value["prerender-buffer"]));
}
if (value.HasMember("prerender-size")) {
klass.prerenderBuffer = toNumber<uint64_t>(parseValue(value["prerender-size"]));
}
if (value.HasMember("prerender-blur")) {
klass.prerenderBlur = toNumber<uint64_t>(parseValue(value["prerender-blur"]));
}
}
FillClass StyleParser::parseFillClass(JSVal value) {
FillClass klass;
parseGenericClass(klass, value);
if (value.HasMember("winding")) {
throw std::runtime_error("winding in stylesheets not yet supported");
}
@@ -541,30 +566,13 @@ FillClass StyleParser::parseFillClass(JSVal value) {
klass.image = parseString(value["image"]);
}
if (value.HasMember("opacity")) {
klass.opacity = parseFunction(value["opacity"]);
klass.opacity_transition = parseTransition(value, "opacity");
}
return klass;
}
LineClass StyleParser::parseLineClass(JSVal value) {
LineClass klass;
if (value.HasMember("enabled")) {
klass.enabled = parseFunction(value["enabled"]);
}
if (value.HasMember("translate")) {
std::vector<FunctionProperty> values = parseArray(value["translate"], 2);
klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
klass.translate_transition = parseTransition(value, "translate");
}
if (value.HasMember("translate-anchor")) {
klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]);
}
parseGenericClass(klass, value);
if (value.HasMember("color")) {
klass.color = parseColor(value["color"]);
@@ -576,11 +584,6 @@ LineClass StyleParser::parseLineClass(JSVal value) {
klass.width_transition = parseTransition(value, "width");
}
if (value.HasMember("opacity")) {
klass.opacity = parseFunction(value["opacity"]);
klass.opacity_transition = parseTransition(value, "opacity");
}
if (value.HasMember("dasharray")) {
std::vector<FunctionProperty> values = parseArray(value["dasharray"], 2);
klass.dash_array = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
@@ -593,30 +596,13 @@ LineClass StyleParser::parseLineClass(JSVal value) {
IconClass StyleParser::parseIconClass(JSVal value) {
IconClass klass;
if (value.HasMember("enabled")) {
klass.enabled = parseFunction(value["enabled"]);
}
if (value.HasMember("translate")) {
std::vector<FunctionProperty> values = parseArray(value["translate"], 2);
klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
klass.translate_transition = parseTransition(value, "translate");
}
if (value.HasMember("translate-anchor")) {
klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]);
}
parseGenericClass(klass, value);
if (value.HasMember("color")) {
klass.color = parseColor(value["color"]);
klass.color_transition = parseTransition(value, "color");
}
if (value.HasMember("opacity")) {
klass.opacity = parseFunction(value["opacity"]);
klass.opacity_transition = parseTransition(value, "opacity");
}
if (value.HasMember("image")) {
klass.image = parseString(value["image"]);
}
@@ -641,19 +627,7 @@ IconClass StyleParser::parseIconClass(JSVal value) {
TextClass StyleParser::parseTextClass(JSVal value) {
TextClass klass;
if (value.HasMember("enabled")) {
klass.enabled = parseFunction(value["enabled"]);
}
if (value.HasMember("translate")) {
std::vector<FunctionProperty> values = parseArray(value["translate"], 2);
klass.translate = std::array<FunctionProperty, 2> {{ values[0], values[1] }};
klass.translate_transition = parseTransition(value, "translate");
}
if (value.HasMember("translate-anchor")) {
klass.translateAnchor = parseTranslateAnchor(value["translate-anchor"]);
}
parseGenericClass(klass, value);
if (value.HasMember("color")) {
klass.color = parseColor(value["color"]);
@@ -687,25 +661,13 @@ TextClass StyleParser::parseTextClass(JSVal value) {
klass.always_visible = parseFunction(value["alwaysVisible"]);
}
if (value.HasMember("opacity")) {
klass.opacity = parseFunction(value["opacity"]);
klass.opacity_transition = parseTransition(value, "opacity");
}
return klass;
}
RasterClass StyleParser::parseRasterClass(JSVal value) {
RasterClass klass;
if (value.HasMember("enabled")) {
klass.enabled = parseFunction(value["enabled"]);
}
if (value.HasMember("opacity")) {
klass.opacity = parseFunction(value["opacity"]);
klass.opacity_transition = parseTransition(value, "opacity");
}
parseGenericClass(klass, value);
return klass;
}
@@ -713,14 +675,7 @@ RasterClass StyleParser::parseRasterClass(JSVal value) {
CompositeClass StyleParser::parseCompositeClass(JSVal value) {
CompositeClass klass;
if (value.HasMember("enabled")) {
klass.enabled = parseFunction(value["enabled"]);
}
if (value.HasMember("opacity")) {
klass.opacity = parseFunction(value["opacity"]);
klass.opacity_transition = parseTransition(value, "opacity");
}
parseGenericClass(klass, value);
return klass;
}
@@ -728,16 +683,13 @@ CompositeClass StyleParser::parseCompositeClass(JSVal value) {
BackgroundClass StyleParser::parseBackgroundClass(JSVal value) {
BackgroundClass klass;
parseGenericClass(klass, value);
if (value.HasMember("color")) {
klass.color = parseColor(value["color"]);
klass.color_transition = parseTransition(value, "color");
}
if (value.HasMember("opacity")) {
klass.opacity = parseFunction(value["opacity"]);
klass.opacity_transition = parseTransition(value, "opacity");
}
return klass;
}

View File

@@ -2,7 +2,7 @@
#include <llmr/util/unitbezier.hpp>
#include <llmr/platform/platform.hpp>
using namespace llmr::util;
namespace llmr { namespace util {
UnitBezier ease(0.25, 0.1, 0.25, 1);
@@ -74,3 +74,5 @@ transition::state ease_transition<std::array<float, 2>>::update(llmr::time now)
return running;
}
}
}}