Merge branch 'master' of github.com:mapbox/llmr-native
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
|
||||
@@ -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');
|
||||
|
||||
@@ -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
97
bin/mkdirp.js
Normal 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;
|
||||
};
|
||||
16
bin/style.js
16
bin/style.js
@@ -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},
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
34
include/llmr/renderer/prerendered_texture.hpp
Normal file
34
include/llmr/renderer/prerendered_texture.hpp
Normal 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
|
||||
29
include/llmr/shader/gaussian_shader.hpp
Normal file
29
include/llmr/shader/gaussian_shader.hpp
Normal 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
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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() {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
23
llmr.gyp
23
llmr.gyp
@@ -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/',
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
47
src/renderer/painter_prerender.cpp
Normal file
47
src/renderer/painter_prerender.cpp
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
137
src/renderer/prerendered_texture.cpp
Normal file
137
src/renderer/prerendered_texture.cpp
Normal 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);
|
||||
}
|
||||
12
src/shader/gaussian.fragment.glsl
Normal file
12
src/shader/gaussian.fragment.glsl
Normal 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;
|
||||
}
|
||||
15
src/shader/gaussian.vertex.glsl
Normal file
15
src/shader/gaussian.vertex.glsl
Normal 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;
|
||||
}
|
||||
48
src/shader/gaussian_shader.cpp
Normal file
48
src/shader/gaussian_shader.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user