diff --git a/include/mbgl/geometry/glyph_atlas.hpp b/include/mbgl/geometry/glyph_atlas.hpp index 07011d324..8df9fd0f7 100644 --- a/include/mbgl/geometry/glyph_atlas.hpp +++ b/include/mbgl/geometry/glyph_atlas.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -12,7 +13,7 @@ namespace mbgl { -class GlyphAtlas { +class GlyphAtlas : public util::noncopyable { public: private: diff --git a/include/mbgl/geometry/sprite_atlas.hpp b/include/mbgl/geometry/sprite_atlas.hpp index c30499a53..36f0f338e 100644 --- a/include/mbgl/geometry/sprite_atlas.hpp +++ b/include/mbgl/geometry/sprite_atlas.hpp @@ -2,6 +2,7 @@ #define MBGL_GEOMETRY_SPRITE_ATLAS #include +#include #include #include @@ -14,7 +15,7 @@ namespace mbgl { class Sprite; class SpritePosition; -class SpriteAtlas { +class SpriteAtlas : public util::noncopyable { public: typedef uint16_t dimension; diff --git a/include/mbgl/platform/event.hpp b/include/mbgl/platform/event.hpp index 1676f40d2..1befd0af3 100644 --- a/include/mbgl/platform/event.hpp +++ b/include/mbgl/platform/event.hpp @@ -59,6 +59,7 @@ constexpr EventSeverity disabledEventSeverities[] = { #if !DEBUG EventSeverity::Debug, #endif + EventSeverity(-1) // Avoid zero size array }; diff --git a/include/mbgl/renderer/painter.hpp b/include/mbgl/renderer/painter.hpp index fcbafc52d..a8fe62b55 100644 --- a/include/mbgl/renderer/painter.hpp +++ b/include/mbgl/renderer/painter.hpp @@ -81,11 +81,12 @@ public: void renderDebugText(DebugBucket& bucket, const mat4 &matrix); void renderDebugText(const std::vector &strings); - void renderFill(FillBucket& bucket, const FillProperties& properties, const Tile::ID& id, const mat4 &matrix); void renderFill(FillBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id, const mat4 &matrix); void renderLine(LineBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id, const mat4 &matrix); void renderSymbol(SymbolBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id, const mat4 &matrix); void renderRaster(RasterBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id, const mat4 &matrix); + void renderBackground(std::shared_ptr layer_desc); + std::array spinWeights(float spin_value); void preparePrerender(RasterBucket &bucket); @@ -118,7 +119,7 @@ public: bool needsAnimation() const; private: void setupShaders(); - const mat4 &translatedMatrix(const mat4& matrix, const std::array &translation, const Tile::ID &id, TranslateAnchorType anchor = TranslateAnchorType::Map); + mat4 translatedMatrix(const mat4& matrix, const std::array &translation, const Tile::ID &id, TranslateAnchorType anchor = TranslateAnchorType::Map); void prepareTile(const Tile& tile); @@ -129,7 +130,6 @@ public: void depthRange(float near, float far); public: - mat4 vtxMatrix; mat4 projMatrix; mat4 nativeMatrix; mat4 extrudeMatrix; @@ -142,11 +142,15 @@ public: return flipMatrix; }(); + const mat4 identityMatrix = []{ + mat4 identity; + matrix::identity(identity); + return identity; + }(); + private: Map& map; - FrameHistory frameHistory; - bool debug = false; uint32_t gl_program = 0; @@ -159,6 +163,8 @@ private: const float strata_epsilon = 1.0f / (1 << 16); public: + FrameHistory frameHistory; + std::unique_ptr plainShader; std::unique_ptr outlineShader; std::unique_ptr lineShader; @@ -170,6 +176,13 @@ public: std::unique_ptr dotShader; std::unique_ptr gaussianShader; + StaticVertexBuffer backgroundBuffer = { + { -1, -1 }, { 1, -1 }, + { -1, 1 }, { 1, 1 } + }; + + VertexArrayObject backgroundArray; + // Set up the stencil quad we're using to generate the stencil mask. StaticVertexBuffer tileStencilBuffer = { // top left triangle diff --git a/include/mbgl/style/property_key.hpp b/include/mbgl/style/property_key.hpp index ec68ea991..28aa80060 100644 --- a/include/mbgl/style/property_key.hpp +++ b/include/mbgl/style/property_key.hpp @@ -60,6 +60,7 @@ enum class PropertyKey { RasterContrast, RasterFade, + BackgroundOpacity, BackgroundColor }; diff --git a/include/mbgl/style/style.hpp b/include/mbgl/style/style.hpp index 6acb5d0cb..c09de6ebb 100644 --- a/include/mbgl/style/style.hpp +++ b/include/mbgl/style/style.hpp @@ -20,7 +20,6 @@ namespace mbgl { class Sprite; class StyleLayer; class StyleLayerGroup; -struct BackgroundProperties; class Style { public: @@ -47,8 +46,6 @@ public: bool hasTransitions() const; - const BackgroundProperties &getBackgroundProperties() const; - const std::string &getSpriteURL() const; public: diff --git a/include/mbgl/style/style_properties.hpp b/include/mbgl/style/style_properties.hpp index bbe8812bc..20200a0dd 100644 --- a/include/mbgl/style/style_properties.hpp +++ b/include/mbgl/style/style_properties.hpp @@ -61,7 +61,7 @@ struct SymbolProperties { struct { float opacity = 1.0f; - float size = 12.0f; + float size = 16.0f; Color color = {{ 0, 0, 0, 1 }}; Color halo_color = {{ 0, 0, 0, 0 }}; float halo_width = 0.0f; @@ -92,6 +92,7 @@ struct RasterProperties { struct BackgroundProperties { inline BackgroundProperties() {} + float opacity = 1.0f; Color color = {{ 0, 0, 0, 1 }}; }; diff --git a/include/mbgl/text/glyph.hpp b/include/mbgl/text/glyph.hpp index 38f9e116a..de7f55bdc 100644 --- a/include/mbgl/text/glyph.hpp +++ b/include/mbgl/text/glyph.hpp @@ -46,12 +46,12 @@ typedef std::map GlyphPositions; class PositionedGlyph { public: - inline explicit PositionedGlyph(uint32_t glyph, uint32_t x, uint32_t y) + inline explicit PositionedGlyph(uint32_t glyph, float x, float y) : glyph(glyph), x(x), y(y) {} uint32_t glyph = 0; - int32_t x = 0; - int32_t y = 0; + float x = 0; + float y = 0; }; typedef std::vector Shaping; diff --git a/src/map/map.cpp b/src/map/map.cpp index b657ab689..5c139f364 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -559,6 +559,8 @@ void Map::render() { painter.drawClippingMasks(getActiveSources()); + painter.frameHistory.record(getAnimationTime(), getState().getNormalizedZoom()); + // Actually render the layers if (debug::renderTree) { std::cout << "{" << std::endl; indent++; } renderLayers(style->layers); @@ -625,7 +627,14 @@ void Map::renderLayers(std::shared_ptr group) { void Map::renderLayer(std::shared_ptr layer_desc, RenderPass pass, const Tile::ID* id, const mat4* matrix) { if (layer_desc->type == StyleLayerType::Background) { - // This layer defines the background color. + // This layer defines a background color/image. + + if (debug::renderTree) { + std::cout << std::string(indent * 4, ' ') << "- " << layer_desc->id << " (" + << layer_desc->type << ")" << std::endl; + } + + painter.renderBackground(layer_desc); } else { // This is a singular layer. if (!layer_desc->bucket) { diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 240aff688..2a3d45c9e 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -143,8 +143,7 @@ void Painter::clear() { glStencilMask(0xFF); depthMask(true); - const BackgroundProperties &properties = map.getStyle()->getBackgroundProperties(); - glClearColor(properties.color[0], properties.color[1], properties.color[2], properties.color[3]); + glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } @@ -180,18 +179,39 @@ void Painter::renderTileLayer(const Tile& tile, std::shared_ptr laye gl::group group(util::sprintf<32>("render %d/%d/%d\n", tile.id.z, tile.id.y, tile.id.z)); prepareTile(tile); tile.data->render(*this, layer_desc, matrix); - frameHistory.record(map.getAnimationTime(), map.getState().getNormalizedZoom()); } } +void Painter::renderBackground(std::shared_ptr layer_desc) { + const BackgroundProperties& properties = layer_desc->getProperties(); -const mat4 &Painter::translatedMatrix(const mat4& matrix, const std::array &translation, const Tile::ID &id, TranslateAnchorType anchor) { + Color color = properties.color; + color[0] *= properties.opacity; + color[1] *= properties.opacity; + color[2] *= properties.opacity; + color[3] *= properties.opacity; + + if ((color[3] >= 1.0f) == (pass == RenderPass::Opaque)) { + useProgram(plainShader->program); + plainShader->setMatrix(identityMatrix); + plainShader->setColor(color); + backgroundArray.bind(*plainShader, backgroundBuffer, BUFFER_OFFSET(0)); + + glDisable(GL_STENCIL_TEST); + depthRange(strata + strata_epsilon, 1.0f); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glEnable(GL_STENCIL_TEST); + } +} + +mat4 Painter::translatedMatrix(const mat4& matrix, const std::array &translation, const Tile::ID &id, TranslateAnchorType anchor) { if (translation[0] == 0 && translation[1] == 0) { return matrix; } else { // TODO: Get rid of the 8 (scaling from 4096 to tile size) const double factor = ((double)(1 << id.z)) / map.getState().getScale() * (4096.0 / util::tileSize); + mat4 vtxMatrix; if (anchor == TranslateAnchorType::Viewport) { const double sin_a = std::sin(-map.getState().getAngle()); const double cos_a = std::cos(-map.getState().getAngle()); diff --git a/src/renderer/painter_fill.cpp b/src/renderer/painter_fill.cpp index fe08d4c2f..97ca1767f 100644 --- a/src/renderer/painter_fill.cpp +++ b/src/renderer/painter_fill.cpp @@ -10,9 +10,13 @@ using namespace mbgl; +void Painter::renderFill(FillBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id, const mat4 &matrix) { + // Abort early. + if (!bucket.hasData()) return; + const FillProperties &properties = layer_desc->getProperties(); + mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor); -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; @@ -136,11 +140,3 @@ void Painter::renderFill(FillBucket& bucket, const FillProperties& properties, c bucket.drawVertices(*outlineShader); } } - -void Painter::renderFill(FillBucket& bucket, std::shared_ptr layer_desc, const Tile::ID& id, const mat4 &matrix) { - // Abort early. - if (!bucket.hasData()) return; - const FillProperties &properties = layer_desc->getProperties(); - const mat4 &vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor); - renderFill(bucket, properties, id, vtxMatrix); -} diff --git a/src/renderer/painter_line.cpp b/src/renderer/painter_line.cpp index 24358c51d..ad0778fc0 100644 --- a/src/renderer/painter_line.cpp +++ b/src/renderer/painter_line.cpp @@ -31,7 +31,7 @@ void Painter::renderLine(LineBucket& bucket, std::shared_ptr layer_d float dash_length = properties.dash_array[0]; float dash_gap = properties.dash_array[1]; - const mat4 &vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor); + mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor); depthRange(strata, 1.0f); diff --git a/src/renderer/painter_symbol.cpp b/src/renderer/painter_symbol.cpp index c2d62bec7..e412bc49d 100644 --- a/src/renderer/painter_symbol.cpp +++ b/src/renderer/painter_symbol.cpp @@ -9,8 +9,7 @@ namespace mbgl { -void Painter::renderSymbol(SymbolBucket &bucket, std::shared_ptr layer_desc, - const Tile::ID &/*id*/, const mat4 &matrix) { +void Painter::renderSymbol(SymbolBucket &bucket, std::shared_ptr layer_desc, const Tile::ID &id, const mat4 &matrix) { // Abort early. if (pass == RenderPass::Opaque) { return; @@ -21,6 +20,8 @@ void Painter::renderSymbol(SymbolBucket &bucket, std::shared_ptr lay glDisable(GL_STENCIL_TEST); if (bucket.hasTextData()) { + mat4 vtxMatrix = translatedMatrix(matrix, properties.text.translate, id, properties.text.translate_anchor); + mat4 exMatrix; matrix::copy(exMatrix, projMatrix); if (bucket.properties.placement == PlacementType::Line) { @@ -32,7 +33,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, std::shared_ptr lay matrix::scale(exMatrix, exMatrix, fontSize / 24.0f, fontSize / 24.0f, 1.0f); useProgram(textShader->program); - textShader->setMatrix(matrix); + textShader->setMatrix(vtxMatrix); textShader->setExtrudeMatrix(exMatrix); GlyphAtlas &glyphAtlas = *map.getGlyphAtlas(); @@ -161,6 +162,8 @@ void Painter::renderSymbol(SymbolBucket &bucket, std::shared_ptr lay } if (bucket.hasIconData()) { + mat4 vtxMatrix = translatedMatrix(matrix, properties.icon.translate, id, properties.icon.translate_anchor); + mat4 exMatrix; matrix::copy(exMatrix, projMatrix); @@ -179,7 +182,7 @@ void Painter::renderSymbol(SymbolBucket &bucket, std::shared_ptr lay matrix::scale(exMatrix, exMatrix, fontScale, fontScale, 1.0f); useProgram(iconShader->program); - iconShader->setMatrix(matrix); + iconShader->setMatrix(vtxMatrix); iconShader->setExtrudeMatrix(exMatrix); SpriteAtlas &spriteAtlas = *map.getSpriteAtlas(); diff --git a/src/style/property_fallback.cpp b/src/style/property_fallback.cpp index 0f8335dd6..572c4b7a8 100644 --- a/src/style/property_fallback.cpp +++ b/src/style/property_fallback.cpp @@ -52,6 +52,7 @@ const std::map PropertyFallbackValue::properties = { { PropertyKey::RasterContrast, defaultStyleProperties().contrast }, { PropertyKey::RasterFade, defaultStyleProperties().fade }, + { PropertyKey::BackgroundOpacity, defaultStyleProperties().opacity }, { PropertyKey::BackgroundColor, defaultStyleProperties().color }, }; diff --git a/src/style/style.cpp b/src/style/style.cpp index ee930751e..6f0a0e3b2 100644 --- a/src/style/style.cpp +++ b/src/style/style.cpp @@ -103,15 +103,4 @@ void Style::loadJSON(const uint8_t *const data) { updateClasses(); } -const BackgroundProperties &Style::getBackgroundProperties() const { - if (layers && layers->layers.size()) { - const auto first = layers->layers.front(); - if (first && first->type == StyleLayerType::Background) { - return first->getProperties(); - } - } - - return defaultStyleProperties(); -} - } diff --git a/src/style/style_layer.cpp b/src/style/style_layer.cpp index 71916afe2..4f758fe72 100644 --- a/src/style/style_layer.cpp +++ b/src/style/style_layer.cpp @@ -233,6 +233,7 @@ template <> void StyleLayer::applyStyleProperties(const float z, const timestamp now) { properties.set(); BackgroundProperties &background = properties.get(); + applyTransitionedStyleProperty(PropertyKey::BackgroundOpacity, background.opacity, z, now); applyTransitionedStyleProperty(PropertyKey::BackgroundColor, background.color, z, now); } diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 2fccf1f40..3d51a2ebe 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -633,9 +633,10 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) { parseOptionalProperty("transition-raster-saturation", Key::RasterSaturation, klass, value); parseOptionalProperty>("raster-contrast", Key::RasterContrast, klass, value); parseOptionalProperty("transition-raster-contrast", Key::RasterContrast, klass, value); - parseOptionalProperty>("raster-fade", Key::RasterFade, klass, value); - parseOptionalProperty("transition-raster-fade", Key::RasterFade, klass, value); + parseOptionalProperty>("raster-fade-duration", Key::RasterFade, klass, value); + parseOptionalProperty("transition-raster-fade-duration", Key::RasterFade, klass, value); + parseOptionalProperty>("background-opacity", Key::BackgroundOpacity, klass, value); parseOptionalProperty>("background-color", Key::BackgroundColor, klass, value); } diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp index 65941e91f..783710d92 100644 --- a/src/text/glyph_store.cpp +++ b/src/text/glyph_store.cpp @@ -131,7 +131,7 @@ void FontStack::lineWrap(Shaping &shaping, const float lineHeight, const float m } } - maxLineLength = maxLineLength || shaping.back().x; + if (!maxLineLength) maxLineLength = shaping.back().x; justifyLine(shaping, metrics, lineStartIndex, uint32_t(shaping.size()) - 1, justify); align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line); diff --git a/test/headless.cpp b/test/headless.cpp index 2453f1bb3..4299fd79b 100644 --- a/test/headless.cpp +++ b/test/headless.cpp @@ -51,10 +51,6 @@ TEST_P(HeadlessTest, render) { Log::Set(); - // Setup OpenGL - HeadlessView view; - Map map(view); - for (auto it = infoDoc.MemberBegin(), end = infoDoc.MemberEnd(); it != end; it++) { const std::string name { it->name.GetString(), it->name.GetStringLength() }; const rapidjson::Value &value = it->value; @@ -80,6 +76,9 @@ TEST_P(HeadlessTest, render) { } } + HeadlessView view; + Map map(view); + map.setStyleJSON(style, base_directory); map.setAppliedClasses(classes); @@ -97,7 +96,6 @@ TEST_P(HeadlessTest, render) { const std::string image = util::compress_png(width, height, pixels.get(), true); util::write_file(actual_image, image); } - } INSTANTIATE_TEST_CASE_P(Headless, HeadlessTest, ::testing::ValuesIn([] {