diff options
author | Lauren Budorick <lauren@mapbox.com> | 2017-04-27 15:56:55 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-27 15:56:55 -0700 |
commit | f6e79d70735361438655f279c8699a786d25458c (patch) | |
tree | cc01ae7aba097bae4aa84beb12ac6b8f34f4d51a /src | |
parent | 839ad87f37a4880804fb4c79157d998ac59954b5 (diff) | |
download | qtlocation-mapboxgl-f6e79d70735361438655f279c8699a786d25458c.tar.gz |
[core] Render fill-extrusion layers (#8431)
Diffstat (limited to 'src')
52 files changed, 1346 insertions, 235 deletions
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 565fe33771..1a5a6a2289 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -250,6 +250,7 @@ UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type, cons bindRenderbuffer = renderbuffer; MBGL_CHECK_ERROR( glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), size.width, size.height)); + bindRenderbuffer = 0; return renderbuffer; } @@ -384,6 +385,17 @@ Framebuffer Context::createFramebuffer(const Texture& color) { return { color.size, std::move(fbo) }; } +Framebuffer +Context::createFramebuffer(const Texture& color, + const Renderbuffer<RenderbufferType::DepthComponent>& depthTarget) { + auto fbo = createFramebuffer(); + bindFramebuffer = fbo; + MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color.texture, 0)); + MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthTarget.renderbuffer)); + checkFramebuffer(); + return { depthTarget.size, std::move(fbo) }; +} + UniqueTexture Context::createTexture(const Size size, const void* data, TextureFormat format, TextureUnit unit) { auto obj = createTexture(); diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 14af299baa..56c0618989 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -81,7 +81,9 @@ public: template <RenderbufferType type> Renderbuffer<type> createRenderbuffer(const Size size) { - static_assert(type == RenderbufferType::RGBA || type == RenderbufferType::DepthStencil, + static_assert(type == RenderbufferType::RGBA || + type == RenderbufferType::DepthStencil || + type == RenderbufferType::DepthComponent, "invalid renderbuffer type"); return { size, createRenderbuffer(type, size) }; } @@ -92,6 +94,8 @@ public: Framebuffer createFramebuffer(const Texture&, const Renderbuffer<RenderbufferType::DepthStencil>&); Framebuffer createFramebuffer(const Texture&); + Framebuffer createFramebuffer(const Texture&, + const Renderbuffer<RenderbufferType::DepthComponent>&); template <typename Image, TextureFormat format = Image::channels == 4 ? TextureFormat::RGBA diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index 7d436693c9..0595419674 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -37,6 +37,11 @@ enum class DataType : uint32_t { enum class RenderbufferType : uint32_t { RGBA = 0x8058, DepthStencil = 0x88F0, +#if not MBGL_USE_GLES2 + DepthComponent = 0x1902, // GL_DEPTH_COMPONENT +#else + DepthComponent = 0x81A5, // GL_DEPTH_COMPONENT16 +#endif // MBGL_USE_GLES2 }; enum class TextureMipMap : bool { No = false, Yes = true }; diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index dd33d0b170..b5a1af172a 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -9,6 +9,7 @@ #include <mbgl/style/style.hpp> #include <mbgl/style/source.hpp> #include <mbgl/style/layer.hpp> +#include <mbgl/style/light.hpp> #include <mbgl/style/observer.hpp> #include <mbgl/style/transition_options.hpp> #include <mbgl/style/update_parameters.hpp> @@ -978,6 +979,22 @@ const style::Image* Map::getImage(const std::string& id) { return nullptr; } +void Map::setLight(std::unique_ptr<style::Light> light) { + if (!impl->style) { + return; + } + + impl->style->light = std::move(light); +} + +style::Light* Map::getLight() { + if (!impl->style) { + return nullptr; + } + + return impl->style->light.get(); +} + #pragma mark - Defaults std::string Map::getStyleName() const { diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index fe90d4b2e4..8c3c70feec 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -2,6 +2,7 @@ #include <mbgl/tile/tile_id.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/interpolate.hpp> +#include <mbgl/util/projection.hpp> #include <mbgl/math/log2.hpp> #include <mbgl/math/clamp.hpp> @@ -26,7 +27,7 @@ void TransformState::matrixFor(mat4& matrix, const UnwrappedTileID& tileID) cons matrix::scale(matrix, matrix, s / util::EXTENT, s / util::EXTENT, 1); } -void TransformState::getProjMatrix(mat4& projMatrix) const { +void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ) const { if (size.isEmpty()) { return; } @@ -45,7 +46,7 @@ void TransformState::getProjMatrix(mat4& projMatrix) const { // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance` const double farZ = furthestDistance * 1.01; - matrix::perspective(projMatrix, getFieldOfView(), double(size.width) / size.height, 1, farZ); + matrix::perspective(projMatrix, getFieldOfView(), double(size.width) / size.height, nearZ, farZ); const bool flippedY = viewportMode == ViewportMode::FlippedY; matrix::scale(projMatrix, projMatrix, 1, flippedY ? 1 : -1, 1); @@ -64,6 +65,9 @@ void TransformState::getProjMatrix(mat4& projMatrix) const { matrix::translate(projMatrix, projMatrix, pixel_x() - size.width / 2.0f, pixel_y() - size.height / 2.0f, 0); + + matrix::scale(projMatrix, projMatrix, 1, 1, + 1.0 / Projection::getMetersPerPixelAtLatitude(getLatLng(LatLng::Unwrapped).latitude(), getZoom())); } #pragma mark - Dimensions @@ -233,7 +237,6 @@ bool TransformState::isGestureInProgress() const { return gestureInProgress; } - #pragma mark - Projection double TransformState::zoomScale(double zoom) const { diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index 85d5d96700..d0bf455ead 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -24,7 +24,7 @@ public: // Matrix void matrixFor(mat4&, const UnwrappedTileID&) const; - void getProjMatrix(mat4& matrix) const; + void getProjMatrix(mat4& matrix, uint16_t nearZ = 1) const; // Dimensions Size getSize() const; diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp index e9ca18927e..cfd6a629de 100644 --- a/src/mbgl/programs/attributes.hpp +++ b/src/mbgl/programs/attributes.hpp @@ -24,6 +24,8 @@ MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos); MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude); MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_offset); MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos); +MBGL_DEFINE_ATTRIBUTE(int16_t, 3, a_normal); +MBGL_DEFINE_ATTRIBUTE(uint16_t, 1, a_edgedistance); template <typename T, std::size_t N> struct a_data { diff --git a/src/mbgl/programs/extrusion_texture_program.cpp b/src/mbgl/programs/extrusion_texture_program.cpp new file mode 100644 index 0000000000..afda4384b7 --- /dev/null +++ b/src/mbgl/programs/extrusion_texture_program.cpp @@ -0,0 +1,7 @@ +#include <mbgl/programs/extrusion_texture_program.hpp> + +namespace mbgl { + +static_assert(sizeof(ExtrusionTextureLayoutVertex) == 4, "expected ExtrusionTextureLayoutVertex size"); + +} // namespace mbgl diff --git a/src/mbgl/programs/extrusion_texture_program.hpp b/src/mbgl/programs/extrusion_texture_program.hpp new file mode 100644 index 0000000000..1519aa095d --- /dev/null +++ b/src/mbgl/programs/extrusion_texture_program.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include <mbgl/programs/program.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> +#include <mbgl/shaders/extrusion_texture.hpp> +#include <mbgl/util/geometry.hpp> + +namespace mbgl { + +class ExtrusionTextureProgram : public Program< + shaders::extrusion_texture, + gl::Triangle, + gl::Attributes<attributes::a_pos>, + gl::Uniforms< + uniforms::u_matrix, + uniforms::u_world, + uniforms::u_image, + uniforms::u_opacity>, + style::PaintProperties<>> { +public: + using Program::Program; + + static LayoutVertex layoutVertex(Point<int16_t> p) { + return LayoutVertex{ + {{ + p.x, + p.y + }} + }; + } +}; + +using ExtrusionTextureLayoutVertex = ExtrusionTextureProgram::LayoutVertex; +using ExtrusionTextureAttributes = ExtrusionTextureProgram::Attributes; + +} // namespace mbgl diff --git a/src/mbgl/programs/fill_extrusion_program.cpp b/src/mbgl/programs/fill_extrusion_program.cpp new file mode 100644 index 0000000000..67426c8d9d --- /dev/null +++ b/src/mbgl/programs/fill_extrusion_program.cpp @@ -0,0 +1,81 @@ +#include <mbgl/programs/fill_extrusion_program.hpp> +#include <mbgl/sprite/sprite_atlas.hpp> +#include <mbgl/style/cross_faded_property_evaluator.hpp> +#include <mbgl/tile/tile_id.hpp> +#include <mbgl/map/transform_state.hpp> +#include <mbgl/util/mat3.hpp> + +namespace mbgl { + +using namespace style; + +static_assert(sizeof(FillExtrusionLayoutVertex) == 12, "expected FillExtrusionLayoutVertex size"); + +std::array<float, 3> lightColor(const EvaluatedLight& light) { + const auto color = light.get<LightColor>(); + return {{ color.r, color.g, color.b }}; +} + +std::array<float, 3> lightPosition(const EvaluatedLight& light, const TransformState& state) { + auto lightPos = light.get<LightPosition>().getCartesian(); + mat3 lightMat; + matrix::identity(lightMat); + if (light.get<LightAnchor>() == LightAnchorType::Viewport) { + matrix::rotate(lightMat, lightMat, -state.getAngle()); + } + matrix::transformMat3f(lightPos, lightPos, lightMat); + return lightPos; +} + +float lightIntensity(const EvaluatedLight& light) { + return light.get<LightIntensity>(); +} + +FillExtrusionUniforms::Values +FillExtrusionUniforms::values(mat4 matrix, + const TransformState& state, + const EvaluatedLight& light) { + return FillExtrusionUniforms::Values{ + uniforms::u_matrix::Value{ matrix }, + uniforms::u_lightcolor::Value{ lightColor(light) }, + uniforms::u_lightpos::Value{ lightPosition(light, state) }, + uniforms::u_lightintensity::Value{ lightIntensity(light) } + }; +} + +FillExtrusionPatternUniforms::Values +FillExtrusionPatternUniforms::values(mat4 matrix, + const SpriteAtlasElement& a, + const SpriteAtlasElement& b, + const Faded<std::string>& fading, + const UnwrappedTileID& tileID, + const TransformState& state, + const float heightFactor, + const EvaluatedLight& light) { + int32_t tileSizeAtNearestZoom = util::tileSize * state.zoomScale(state.getIntegerZoom() - tileID.canonical.z); + int32_t pixelX = tileSizeAtNearestZoom * (tileID.canonical.x + tileID.wrap * state.zoomScale(tileID.canonical.z)); + int32_t pixelY = tileSizeAtNearestZoom * tileID.canonical.y; + + return FillExtrusionPatternUniforms::Values{ + uniforms::u_matrix::Value{ matrix }, + uniforms::u_pattern_tl_a::Value{ a.tl }, + uniforms::u_pattern_br_a::Value{ a.br }, + uniforms::u_pattern_tl_b::Value{ b.tl }, + uniforms::u_pattern_br_b::Value{ b.br }, + uniforms::u_pattern_size_a::Value{ a.size }, + uniforms::u_pattern_size_b::Value{ b.size }, + uniforms::u_scale_a::Value{ fading.fromScale }, + uniforms::u_scale_b::Value{ fading.toScale }, + uniforms::u_mix::Value{ fading.t }, + uniforms::u_image::Value{ 0 }, + uniforms::u_pixel_coord_upper::Value{ std::array<float, 2>{{ float(pixelX >> 16), float(pixelY >> 16) }} }, + uniforms::u_pixel_coord_lower::Value{ std::array<float, 2>{{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }} }, + uniforms::u_tile_units_to_pixels::Value{ 1.0f / tileID.pixelsToTileUnits(1.0f, state.getIntegerZoom()) }, + uniforms::u_height_factor::Value{ heightFactor }, + uniforms::u_lightcolor::Value{ lightColor(light) }, + uniforms::u_lightpos::Value{ lightPosition(light, state) }, + uniforms::u_lightintensity::Value{ lightIntensity(light) }, + }; +} + +} // namespace mbgl diff --git a/src/mbgl/programs/fill_extrusion_program.hpp b/src/mbgl/programs/fill_extrusion_program.hpp new file mode 100644 index 0000000000..b84e50298c --- /dev/null +++ b/src/mbgl/programs/fill_extrusion_program.hpp @@ -0,0 +1,129 @@ +#pragma once + +#include <mbgl/programs/program.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> +#include <mbgl/shaders/fill_extrusion.hpp> +#include <mbgl/shaders/fill_extrusion_pattern.hpp> +#include <mbgl/util/geometry.hpp> +#include <mbgl/util/mat4.hpp> +#include <mbgl/util/size.hpp> +#include <mbgl/style/layers/fill_extrusion_layer_properties.hpp> +#include <mbgl/style/style.hpp> +#include <mbgl/style/light_impl.hpp> + +#include <string> + +namespace mbgl { + +class SpriteAtlasElement; +class UnwrappedTileID; +class TransformState; + +namespace style { +template <class> class Faded; +} // namespace style + +namespace uniforms { +MBGL_DEFINE_UNIFORM_VECTOR(float, 3, u_lightpos); +MBGL_DEFINE_UNIFORM_VECTOR(float, 3, u_lightcolor); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_lightintensity); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_height_factor); +} // namespace uniforms + +struct FillExtrusionLayoutAttributes : gl::Attributes< + attributes::a_pos, + attributes::a_normal, + attributes::a_edgedistance> +{}; + +struct FillExtrusionUniforms : gl::Uniforms< + uniforms::u_matrix, + uniforms::u_lightcolor, + uniforms::u_lightpos, + uniforms::u_lightintensity> +{ + static Values values(mat4, + const TransformState&, + const style::EvaluatedLight&); +}; + +struct FillExtrusionPatternUniforms : gl::Uniforms< + uniforms::u_matrix, + uniforms::u_pattern_tl_a, + uniforms::u_pattern_br_a, + uniforms::u_pattern_tl_b, + uniforms::u_pattern_br_b, + uniforms::u_pattern_size_a, + uniforms::u_pattern_size_b, + uniforms::u_scale_a, + uniforms::u_scale_b, + uniforms::u_mix, + uniforms::u_image, + uniforms::u_pixel_coord_upper, + uniforms::u_pixel_coord_lower, + uniforms::u_tile_units_to_pixels, + uniforms::u_height_factor, + uniforms::u_lightcolor, + uniforms::u_lightpos, + uniforms::u_lightintensity> +{ + static Values values(mat4, + const SpriteAtlasElement&, + const SpriteAtlasElement&, + const style::Faded<std::string>&, + const UnwrappedTileID&, + const TransformState&, + const float, + const style::EvaluatedLight&); +}; + +class FillExtrusionProgram : public Program< + shaders::fill_extrusion, + gl::Triangle, + FillExtrusionLayoutAttributes, + FillExtrusionUniforms, + style::FillExtrusionPaintProperties> +{ +public: + using Program::Program; + + static LayoutVertex layoutVertex(Point<int16_t> p, double nx, double ny, double nz, unsigned short t, uint16_t e) { + const auto factor = pow(2, 13); + + return LayoutVertex { + {{ + p.x, + p.y + }}, + {{ + // Multiply normal vector components by 2^14 to pack them into integers + // We pack a bool (`t`) into the x component indicating whether it is an upper or lower vertex + static_cast<int16_t>(floor(nx * factor) * 2 + t), + static_cast<int16_t>(ny * factor * 2), + static_cast<int16_t>(nz * factor * 2) + + }}, + {{ + // The edgedistance attribute is used for wrapping fill_extrusion patterns + e + }} + }; + } +}; + +class FillExtrusionPatternProgram : public Program< + shaders::fill_extrusion_pattern, + gl::Triangle, + FillExtrusionLayoutAttributes, + FillExtrusionPatternUniforms, + style::FillExtrusionPaintProperties> +{ +public: + using Program::Program; +}; + +using FillExtrusionLayoutVertex = FillExtrusionProgram::LayoutVertex; +using FillExtrusionAttributes = FillExtrusionProgram::Attributes; + +} // namespace mbgl diff --git a/src/mbgl/programs/fill_program.hpp b/src/mbgl/programs/fill_program.hpp index 84ca2748d6..bbf5c39fb9 100644 --- a/src/mbgl/programs/fill_program.hpp +++ b/src/mbgl/programs/fill_program.hpp @@ -24,15 +24,6 @@ namespace style { template <class> class Faded; } // namespace style -namespace uniforms { -MBGL_DEFINE_UNIFORM_SCALAR(Size, u_world); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_a); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_b); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_tile_units_to_pixels); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_upper); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_lower); -} // namespace uniforms - struct FillLayoutAttributes : gl::Attributes< attributes::a_pos> {}; diff --git a/src/mbgl/programs/programs.hpp b/src/mbgl/programs/programs.hpp index dbf5b9e87d..ff6b1cd505 100644 --- a/src/mbgl/programs/programs.hpp +++ b/src/mbgl/programs/programs.hpp @@ -1,7 +1,9 @@ #pragma once #include <mbgl/programs/circle_program.hpp> +#include <mbgl/programs/extrusion_texture_program.hpp> #include <mbgl/programs/fill_program.hpp> +#include <mbgl/programs/fill_extrusion_program.hpp> #include <mbgl/programs/line_program.hpp> #include <mbgl/programs/raster_program.hpp> #include <mbgl/programs/symbol_program.hpp> @@ -15,7 +17,10 @@ class Programs { public: Programs(gl::Context& context, const ProgramParameters& programParameters) : circle(context, programParameters), + extrusionTexture(context, programParameters), fill(context, programParameters), + fillExtrusion(context, programParameters), + fillExtrusionPattern(context, programParameters), fillPattern(context, programParameters), fillOutline(context, programParameters), fillOutlinePattern(context, programParameters), @@ -31,7 +36,10 @@ public: } CircleProgram circle; + ExtrusionTextureProgram extrusionTexture; FillProgram fill; + FillExtrusionProgram fillExtrusion; + FillExtrusionPatternProgram fillExtrusionPattern; FillPatternProgram fillPattern; FillOutlineProgram fillOutline; FillOutlinePatternProgram fillOutlinePattern; diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp index e0c5a0d361..972405d5a9 100644 --- a/src/mbgl/programs/uniforms.hpp +++ b/src/mbgl/programs/uniforms.hpp @@ -17,6 +17,8 @@ MBGL_DEFINE_UNIFORM_SCALAR(float, u_zoom); MBGL_DEFINE_UNIFORM_SCALAR(float, u_pitch); MBGL_DEFINE_UNIFORM_SCALAR(float, u_bearing); +MBGL_DEFINE_UNIFORM_SCALAR(Size, u_world); + MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_extrude_scale); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_tl_a); @@ -25,9 +27,14 @@ MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_tl_b); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_br_b); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_size_a); MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_size_b); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_upper); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_lower); MBGL_DEFINE_UNIFORM_SCALAR(float, u_mix); MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_image); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_a); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_b); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_tile_units_to_pixels); } // namespace uniforms } // namespace mbgl diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/circle_bucket.hpp index 855565ebf4..b048fd7675 100644 --- a/src/mbgl/renderer/circle_bucket.hpp +++ b/src/mbgl/renderer/circle_bucket.hpp @@ -22,6 +22,7 @@ public: bool hasData() const override; void upload(gl::Context&) override; + void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override; float getQueryRadius(const RenderLayer&) const override; diff --git a/src/mbgl/renderer/fill_extrusion_bucket.cpp b/src/mbgl/renderer/fill_extrusion_bucket.cpp new file mode 100644 index 0000000000..2b352ab66a --- /dev/null +++ b/src/mbgl/renderer/fill_extrusion_bucket.cpp @@ -0,0 +1,177 @@ +#include <mbgl/renderer/fill_extrusion_bucket.hpp> +#include <mbgl/renderer/painter.hpp> +#include <mbgl/programs/fill_extrusion_program.hpp> +#include <mbgl/renderer/bucket_parameters.hpp> +#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp> +#include <mbgl/renderer/render_fill_extrusion_layer.hpp> +#include <mbgl/util/math.hpp> +#include <mbgl/util/constants.hpp> + +#include <mapbox/earcut.hpp> + +#include <cassert> + +namespace mapbox { +namespace util { +template <> +struct nth<0, mbgl::GeometryCoordinate> { + static int64_t get(const mbgl::GeometryCoordinate& t) { + return t.x; + }; +}; + +template <> +struct nth<1, mbgl::GeometryCoordinate> { + static int64_t get(const mbgl::GeometryCoordinate& t) { + return t.y; + }; +}; +} // namespace util +} // namespace mapbox + +namespace mbgl { + +using namespace style; + +struct GeometryTooLongException : std::exception {}; + +FillExtrusionBucket::FillExtrusionBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) { + for (const auto& layer : layers) { + paintPropertyBinders.emplace(std::piecewise_construct, + std::forward_as_tuple(layer->getID()), + std::forward_as_tuple( + layer->as<RenderFillExtrusionLayer>()->evaluated, + parameters.tileID.overscaledZ)); + } +} + +void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature, + const GeometryCollection& geometry) { + for (auto& polygon : classifyRings(geometry)) { + // Optimize polygons with many interior rings for earcut tesselation. + limitHoles(polygon, 500); + + std::size_t totalVertices = 0; + + for (const auto& ring : polygon) { + totalVertices += ring.size(); + if (totalVertices > std::numeric_limits<uint16_t>::max()) + throw GeometryTooLongException(); + } + + if (totalVertices == 0) continue; + + std::vector<uint32_t> flatIndices; + flatIndices.reserve(totalVertices); + + std::size_t startVertices = vertices.vertexSize(); + + if (triangleSegments.empty() || + triangleSegments.back().vertexLength + (5 * (totalVertices - 1) + 1) > + std::numeric_limits<uint16_t>::max()) { + triangleSegments.emplace_back(startVertices, triangles.indexSize()); + } + + auto& triangleSegment = triangleSegments.back(); + assert(triangleSegment.vertexLength <= std::numeric_limits<uint16_t>::max()); + uint16_t triangleIndex = triangleSegment.vertexLength; + + assert(triangleIndex + (5 * (totalVertices - 1) + 1) <= + std::numeric_limits<uint16_t>::max()); + + for (const auto& ring : polygon) { + std::size_t nVertices = ring.size(); + + if (nVertices == 0) + continue; + + auto edgeDistance = 0; + + for (uint32_t i = 0; i < nVertices; i++) { + const auto& p1 = ring[i]; + + vertices.emplace_back( + FillExtrusionProgram::layoutVertex(p1, 0, 0, 1, 1, edgeDistance)); + flatIndices.emplace_back(triangleIndex); + triangleIndex++; + + if (i != 0) { + const auto& p2 = ring[i - 1]; + + const auto d1 = convertPoint<double>(p1); + const auto d2 = convertPoint<double>(p2); + + const Point<double> perp = util::unit(util::perp(d1 - d2)); + + vertices.emplace_back( + FillExtrusionProgram::layoutVertex(p1, perp.x, perp.y, 0, 0, edgeDistance)); + vertices.emplace_back( + FillExtrusionProgram::layoutVertex(p1, perp.x, perp.y, 0, 1, edgeDistance)); + + edgeDistance += util::dist<int16_t>(d1, d2); + + vertices.emplace_back( + FillExtrusionProgram::layoutVertex(p2, perp.x, perp.y, 0, 0, edgeDistance)); + vertices.emplace_back( + FillExtrusionProgram::layoutVertex(p2, perp.x, perp.y, 0, 1, edgeDistance)); + + triangles.emplace_back(triangleIndex, triangleIndex + 1, triangleIndex + 2); + triangles.emplace_back(triangleIndex + 1, triangleIndex + 2, triangleIndex + 3); + triangleIndex += 4; + triangleSegment.vertexLength += 4; + triangleSegment.indexLength += 6; + } + } + } + + std::vector<uint32_t> indices = mapbox::earcut(polygon); + + std::size_t nIndices = indices.size(); + assert(nIndices % 3 == 0); + + for (uint32_t i = 0; i < nIndices; i += 3) { + triangles.emplace_back(flatIndices[indices[i]], flatIndices[indices[i + 1]], + flatIndices[indices[i + 2]]); + } + + triangleSegment.vertexLength += totalVertices; + triangleSegment.indexLength += nIndices; + } + + for (auto& pair : paintPropertyBinders) { + pair.second.populateVertexVectors(feature, vertices.vertexSize()); + } +} + +void FillExtrusionBucket::upload(gl::Context& context) { + vertexBuffer = context.createVertexBuffer(std::move(vertices)); + indexBuffer = context.createIndexBuffer(std::move(triangles)); + + for (auto& pair : paintPropertyBinders) { + pair.second.upload(context); + } + + uploaded = true; +} + +void FillExtrusionBucket::render(Painter& painter, + PaintParameters& parameters, + const RenderLayer& layer, + const RenderTile& tile) { + painter.renderFillExtrusion(parameters, *this, *layer.as<RenderFillExtrusionLayer>(), tile); +} + +bool FillExtrusionBucket::hasData() const { + return !triangleSegments.empty(); +} + +float FillExtrusionBucket::getQueryRadius(const RenderLayer& layer) const { + if (!layer.is<RenderFillExtrusionLayer>()) { + return 0; + } + + const std::array<float, 2>& translate = layer.as<RenderFillExtrusionLayer>()->evaluated.get<FillExtrusionTranslate>(); + return util::length(translate[0], translate[1]); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/fill_extrusion_bucket.hpp b/src/mbgl/renderer/fill_extrusion_bucket.hpp new file mode 100644 index 0000000000..c54805d743 --- /dev/null +++ b/src/mbgl/renderer/fill_extrusion_bucket.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include <mbgl/renderer/bucket.hpp> +#include <mbgl/tile/geometry_tile_data.hpp> +#include <mbgl/gl/vertex_buffer.hpp> +#include <mbgl/gl/index_buffer.hpp> +#include <mbgl/gl/segment.hpp> +#include <mbgl/programs/fill_extrusion_program.hpp> +#include <mbgl/style/layers/fill_extrusion_layer_properties.hpp> + +namespace mbgl { + +class BucketParameters; + +class FillExtrusionBucket : public Bucket { +public: + FillExtrusionBucket(const BucketParameters&, const std::vector<const RenderLayer*>&); + + void addFeature(const GeometryTileFeature&, + const GeometryCollection&) override; + bool hasData() const override; + + void upload(gl::Context&) override; + void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override; + + float getQueryRadius(const RenderLayer&) const override; + + gl::VertexVector<FillExtrusionLayoutVertex> vertices; + gl::IndexVector<gl::Triangles> triangles; + gl::SegmentVector<FillExtrusionAttributes> triangleSegments; + + optional<gl::VertexBuffer<FillExtrusionLayoutVertex>> vertexBuffer; + optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; + + std::unordered_map<std::string, FillExtrusionProgram::PaintPropertyBinders> paintPropertyBinders; +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index 0c4915d3e9..36dd4a793f 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -16,6 +16,7 @@ #include <mbgl/renderer/render_background_layer.hpp> #include <mbgl/renderer/render_custom_layer.hpp> #include <mbgl/style/layers/custom_layer_impl.hpp> +#include <mbgl/renderer/render_fill_extrusion_layer.hpp> #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/geometry/line_atlas.hpp> @@ -53,7 +54,7 @@ static gl::VertexVector<FillLayoutVertex> tileVertices() { return result; } -static gl::IndexVector<gl::Triangles> tileTriangleIndices() { +static gl::IndexVector<gl::Triangles> quadTriangleIndices() { gl::IndexVector<gl::Triangles> result; result.emplace_back(0, 1, 2); result.emplace_back(1, 2, 3); @@ -79,6 +80,16 @@ static gl::VertexVector<RasterLayoutVertex> rasterVertices() { return result; } +static gl::VertexVector<ExtrusionTextureLayoutVertex> extrusionTextureVertices() { + gl::VertexVector<ExtrusionTextureLayoutVertex> result; + result.emplace_back(ExtrusionTextureProgram::layoutVertex({ 0, 0 })); + result.emplace_back(ExtrusionTextureProgram::layoutVertex({ 1, 0 })); + result.emplace_back(ExtrusionTextureProgram::layoutVertex({ 0, 1 })); + result.emplace_back(ExtrusionTextureProgram::layoutVertex({ 1, 1 })); + return result; +} + + Painter::Painter(gl::Context& context_, const TransformState& state_, float pixelRatio, @@ -87,12 +98,14 @@ Painter::Painter(gl::Context& context_, state(state_), tileVertexBuffer(context.createVertexBuffer(tileVertices())), rasterVertexBuffer(context.createVertexBuffer(rasterVertices())), - tileTriangleIndexBuffer(context.createIndexBuffer(tileTriangleIndices())), + extrusionTextureVertexBuffer(context.createVertexBuffer(extrusionTextureVertices())), + quadTriangleIndexBuffer(context.createIndexBuffer(quadTriangleIndices())), tileBorderIndexBuffer(context.createIndexBuffer(tileLineStripIndices())) { tileTriangleSegments.emplace_back(0, 0, 4, 6); tileBorderSegments.emplace_back(0, 0, 4, 5); rasterSegments.emplace_back(0, 0, 4, 6); + extrusionTextureSegments.emplace_back(0, 0, 4, 6); programs = std::make_unique<Programs>(context, ProgramParameters{ pixelRatio, false, programCacheDir }); @@ -131,12 +144,18 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp spriteAtlas = style.spriteAtlas.get(); lineAtlas = style.lineAtlas.get(); + evaluatedLight = style.evaluatedLight; + RenderData renderData = style.getRenderData(frame.debugOptions, state.getAngle()); const std::vector<RenderItem>& order = renderData.order; const std::unordered_set<Source*>& sources = renderData.sources; // Update the default matrices to the current viewport dimensions. state.getProjMatrix(projMatrix); + // Calculate a second projection matrix with the near plane clipped to 100 so as + // not to waste lots of depth buffer precision on very close empty space, for layer + // types (fill-extrusion) that use the depth buffer to emulate real-world space. + state.getProjMatrix(nearClippedProjMatrix, 100); pixelsToGLUnits = {{ 2.0f / state.getSize().width, -2.0f / state.getSize().height }}; if (state.getViewportMode() == ViewportMode::FlippedY) { @@ -160,8 +179,11 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp annotationSpriteAtlas.upload(context, 0); for (const auto& item : order) { - if (item.bucket && item.bucket->needsUpload()) { - item.bucket->upload(context); + for (const auto& tileRef : item.tiles) { + const auto& bucket = tileRef.get().tile.getBucket(item.layer); + if (bucket && bucket->needsUpload()) { + bucket->upload(context); + } } } } @@ -187,7 +209,7 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp // Update all clipping IDs. algorithm::ClipIDGenerator generator; for (const auto& source : sources) { - source->baseImpl->startRender(generator, projMatrix, state); + source->baseImpl->startRender(generator, projMatrix, nearClippedProjMatrix, state); } MBGL_DEBUG_GROUP(context, "clipping masks"); @@ -208,7 +230,6 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp // Actually render the layers if (debug::renderTree) { Log::Info(Event::Render, "{"); indent++; } - // TODO: Correctly compute the number of layers recursively beforehand. depthRangeSize = 1 - (order.size() + 2) * numSublayers * depthEpsilon; // - OPAQUE PASS ------------------------------------------------------------------------------- @@ -302,9 +323,50 @@ void Painter::renderPass(PaintParameters& parameters, // the viewport or Framebuffer. parameters.view.bind(); context.setDirtyState(); + } else if (layer.is<RenderFillExtrusionLayer>()) { + const auto size = context.viewport.getCurrentValue().size; + + OffscreenTexture texture(context, size); + texture.bindRenderbuffers(1); + + context.setStencilMode(gl::StencilMode::disabled()); + context.setDepthMode(depthModeForSublayer(0, gl::DepthMode::ReadWrite)); + context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, 1.0f, {}); + + for (auto& tileRef : item.tiles) { + auto& tile = tileRef.get(); + + MBGL_DEBUG_GROUP(context, layer.baseImpl.id + " - " + util::toString(tile.id)); + auto bucket = tile.tile.getBucket(layer); + bucket->render(*this, parameters, layer, tile); + } + + parameters.view.bind(); + + mat4 viewportMat; + matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1); + + const PaintProperties<>::Evaluated properties{}; + + parameters.programs.extrusionTexture.draw( + context, gl::Triangles(), gl::DepthMode::disabled(), gl::StencilMode::disabled(), + colorModeForRenderPass(), + ExtrusionTextureProgram::UniformValues{ + uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size }, + uniforms::u_image::Value{ 1 }, + uniforms::u_opacity::Value{ + layer.as<RenderFillExtrusionLayer>()->evaluated.get<FillExtrusionOpacity>() } }, + extrusionTextureVertexBuffer, quadTriangleIndexBuffer, + extrusionTextureSegments, + ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 }, properties, + state.getZoom()); } else { - MBGL_DEBUG_GROUP(context, layer.baseImpl.id + " - " + util::toString(item.tile->id)); - item.bucket->render(*this, parameters, layer, *item.tile); + for (auto& tileRef : item.tiles) { + auto& tile = tileRef.get(); + MBGL_DEBUG_GROUP(context, layer.baseImpl.id + " - " + util::toString(tile.id)); + auto bucket = tile.tile.getBucket(layer); + bucket->render(*this, parameters, layer, tile); + } } } diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 9c6dd4505f..7706d2d451 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -12,6 +12,7 @@ #include <mbgl/programs/debug_program.hpp> #include <mbgl/programs/program_parameters.hpp> #include <mbgl/programs/fill_program.hpp> +#include <mbgl/programs/extrusion_texture_program.hpp> #include <mbgl/programs/raster_program.hpp> #include <mbgl/style/style.hpp> @@ -37,12 +38,14 @@ class Tile; class DebugBucket; class FillBucket; +class FillExtrusionBucket; class LineBucket; class CircleBucket; class SymbolBucket; class RasterBucket; class RenderFillLayer; +class RenderFillExtrusionLayer; class RenderLineLayer; class RenderCircleLayer; class RenderSymbolLayer; @@ -82,6 +85,7 @@ public: void renderClippingMask(const UnwrappedTileID&, const ClipID&); void renderTileDebug(const RenderTile&); void renderFill(PaintParameters&, FillBucket&, const RenderFillLayer&, const RenderTile&); + void renderFillExtrusion(PaintParameters&, FillExtrusionBucket&, const RenderFillExtrusionLayer&, const RenderTile&); void renderLine(PaintParameters&, LineBucket&, const RenderLineLayer&, const RenderTile&); void renderCircle(PaintParameters&, CircleBucket&, const RenderCircleLayer&, const RenderTile&); void renderSymbol(PaintParameters&, SymbolBucket&, const RenderSymbolLayer&, const RenderTile&); @@ -126,6 +130,7 @@ private: gl::Context& context; mat4 projMatrix; + mat4 nearClippedProjMatrix; std::array<float, 2> pixelsToGLUnits; @@ -152,6 +157,8 @@ private: GlyphAtlas* glyphAtlas = nullptr; LineAtlas* lineAtlas = nullptr; + style::EvaluatedLight evaluatedLight; + FrameHistory frameHistory; std::unique_ptr<Programs> programs; @@ -161,13 +168,15 @@ private: gl::VertexBuffer<FillLayoutVertex> tileVertexBuffer; gl::VertexBuffer<RasterLayoutVertex> rasterVertexBuffer; + gl::VertexBuffer<ExtrusionTextureLayoutVertex> extrusionTextureVertexBuffer; - gl::IndexBuffer<gl::Triangles> tileTriangleIndexBuffer; + gl::IndexBuffer<gl::Triangles> quadTriangleIndexBuffer; gl::IndexBuffer<gl::LineStrip> tileBorderIndexBuffer; gl::SegmentVector<FillAttributes> tileTriangleSegments; gl::SegmentVector<DebugAttributes> tileBorderSegments; gl::SegmentVector<RasterAttributes> rasterSegments; + gl::SegmentVector<ExtrusionTextureAttributes> extrusionTextureSegments; }; } // namespace mbgl diff --git a/src/mbgl/renderer/painter_background.cpp b/src/mbgl/renderer/painter_background.cpp index ac16627246..7cd9cbac5f 100644 --- a/src/mbgl/renderer/painter_background.cpp +++ b/src/mbgl/renderer/painter_background.cpp @@ -49,7 +49,7 @@ void Painter::renderBackground(PaintParameters& parameters, const RenderBackgrou state ), tileVertexBuffer, - tileTriangleIndexBuffer, + quadTriangleIndexBuffer, tileTriangleSegments, paintAttibuteData, properties, @@ -69,7 +69,7 @@ void Painter::renderBackground(PaintParameters& parameters, const RenderBackgrou uniforms::u_world::Value{ context.viewport.getCurrentValue().size }, }, tileVertexBuffer, - tileTriangleIndexBuffer, + quadTriangleIndexBuffer, tileTriangleSegments, paintAttibuteData, properties, diff --git a/src/mbgl/renderer/painter_clipping.cpp b/src/mbgl/renderer/painter_clipping.cpp index 70df9837e8..0d3b5f1504 100644 --- a/src/mbgl/renderer/painter_clipping.cpp +++ b/src/mbgl/renderer/painter_clipping.cpp @@ -26,7 +26,7 @@ void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& cl uniforms::u_world::Value{ context.viewport.getCurrentValue().size }, }, tileVertexBuffer, - tileTriangleIndexBuffer, + quadTriangleIndexBuffer, tileTriangleSegments, paintAttibuteData, properties, diff --git a/src/mbgl/renderer/painter_fill_extrusion.cpp b/src/mbgl/renderer/painter_fill_extrusion.cpp new file mode 100644 index 0000000000..af98cae569 --- /dev/null +++ b/src/mbgl/renderer/painter_fill_extrusion.cpp @@ -0,0 +1,87 @@ +#include <mbgl/renderer/painter.hpp> +#include <mbgl/renderer/paint_parameters.hpp> +#include <mbgl/renderer/fill_extrusion_bucket.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/renderer/render_fill_extrusion_layer.hpp> +#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp> +#include <mbgl/sprite/sprite_atlas.hpp> +#include <mbgl/programs/programs.hpp> +#include <mbgl/programs/fill_extrusion_program.hpp> +#include <mbgl/util/constants.hpp> +#include <mbgl/util/convert.hpp> + +namespace mbgl { + +using namespace style; + +void Painter::renderFillExtrusion(PaintParameters& parameters, + FillExtrusionBucket& bucket, + const RenderFillExtrusionLayer& layer, + const RenderTile& tile) { + const FillExtrusionPaintProperties::Evaluated& properties = layer.evaluated; + + if (pass == RenderPass::Opaque) { + return; + } + + if (!properties.get<FillExtrusionPattern>().from.empty()) { + optional<SpriteAtlasElement> imagePosA = + spriteAtlas->getPattern(properties.get<FillExtrusionPattern>().from); + optional<SpriteAtlasElement> imagePosB = + spriteAtlas->getPattern(properties.get<FillExtrusionPattern>().to); + + if (!imagePosA || !imagePosB) { + return; + } + + spriteAtlas->bind(true, context, 0); + + parameters.programs.fillExtrusionPattern.draw( + context, + gl::Triangles(), + depthModeForSublayer(0, gl::DepthMode::ReadWrite), + gl::StencilMode::disabled(), + colorModeForRenderPass(), + FillExtrusionPatternUniforms::values( + tile.translatedClipMatrix(properties.get<FillExtrusionTranslate>(), + properties.get<FillExtrusionTranslateAnchor>(), + state), + *imagePosA, + *imagePosB, + properties.get<FillExtrusionPattern>(), + tile.id, + state, + -std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f, + evaluatedLight + ), + *bucket.vertexBuffer, + *bucket.indexBuffer, + bucket.triangleSegments, + bucket.paintPropertyBinders.at(layer.getID()), + properties, + state.getZoom()); + + } else { + parameters.programs.fillExtrusion.draw( + context, + gl::Triangles(), + depthModeForSublayer(0, gl::DepthMode::ReadWrite), + gl::StencilMode::disabled(), + colorModeForRenderPass(), + FillExtrusionUniforms::values( + tile.translatedClipMatrix(properties.get<FillExtrusionTranslate>(), + properties.get<FillExtrusionTranslateAnchor>(), + state), + state, + evaluatedLight + ), + *bucket.vertexBuffer, + *bucket.indexBuffer, + bucket.triangleSegments, + bucket.paintPropertyBinders.at(layer.getID()), + properties, + state.getZoom()); + }; +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp index 31f10ed3ba..fbe025b5b0 100644 --- a/src/mbgl/renderer/painter_raster.cpp +++ b/src/mbgl/renderer/painter_raster.cpp @@ -77,7 +77,7 @@ void Painter::renderRaster(PaintParameters& parameters, uniforms::u_tl_parent::Value{ std::array<float, 2> {{ 0.0f, 0.0f }} }, }, rasterVertexBuffer, - tileTriangleIndexBuffer, + quadTriangleIndexBuffer, rasterSegments, paintAttributeData, properties, diff --git a/src/mbgl/renderer/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/render_fill_extrusion_layer.cpp index a378f12cf0..8df0d36900 100644 --- a/src/mbgl/renderer/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/render_fill_extrusion_layer.cpp @@ -1,26 +1,53 @@ #include <mbgl/renderer/render_fill_extrusion_layer.hpp> -#include <mbgl/renderer/bucket.hpp> +#include <mbgl/renderer/fill_extrusion_bucket.hpp> #include <mbgl/style/layers/fill_extrusion_layer_impl.hpp> +#include <mbgl/geometry/feature_index.hpp> +#include <mbgl/util/math.hpp> +#include <mbgl/util/intersection_tests.hpp> namespace mbgl { RenderFillExtrusionLayer::RenderFillExtrusionLayer(const style::FillExtrusionLayer::Impl& _impl) - : RenderLayer(style::LayerType::FillExtrusion, _impl) { + : RenderLayer(style::LayerType::FillExtrusion, _impl), + impl(&_impl) { } std::unique_ptr<RenderLayer> RenderFillExtrusionLayer::clone() const { return std::make_unique<RenderFillExtrusionLayer>(*this); } -std::unique_ptr<Bucket> RenderFillExtrusionLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const { - return nullptr; +std::unique_ptr<Bucket> RenderFillExtrusionLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const { + return std::make_unique<FillExtrusionBucket>(parameters, layers); } -void RenderFillExtrusionLayer::cascade(const style::CascadeParameters&) { +void RenderFillExtrusionLayer::cascade(const style::CascadeParameters& parameters) { + unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated)); } -bool RenderFillExtrusionLayer::evaluate(const style::PropertyEvaluationParameters&) { - return false; +bool RenderFillExtrusionLayer::evaluate(const style::PropertyEvaluationParameters& parameters) { + evaluated = unevaluated.evaluate(parameters); + + passes = (evaluated.get<style::FillExtrusionOpacity>() > 0) ? RenderPass::Translucent + : RenderPass::None; + + return unevaluated.hasTransition(); +} + +bool RenderFillExtrusionLayer::queryIntersectsFeature( + const GeometryCoordinates& queryGeometry, + const GeometryTileFeature& feature, + const float, + const float bearing, + const float pixelsToTileUnits) const { + + auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry( + queryGeometry, + evaluated.get<style::FillExtrusionTranslate>(), + evaluated.get<style::FillExtrusionTranslateAnchor>(), + bearing, + pixelsToTileUnits); + + return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries()); } } // namespace mbgl diff --git a/src/mbgl/renderer/render_fill_extrusion_layer.hpp b/src/mbgl/renderer/render_fill_extrusion_layer.hpp index 596ba02fee..87b6ad6071 100644 --- a/src/mbgl/renderer/render_fill_extrusion_layer.hpp +++ b/src/mbgl/renderer/render_fill_extrusion_layer.hpp @@ -17,11 +17,20 @@ public: void cascade(const style::CascadeParameters&) override; bool evaluate(const style::PropertyEvaluationParameters&) override; + bool queryIntersectsFeature( + const GeometryCoordinates&, + const GeometryTileFeature&, + const float, + const float, + const float) const override; + std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override; // Paint properties style::FillExtrusionPaintProperties::Unevaluated unevaluated; style::FillExtrusionPaintProperties::Evaluated evaluated; + + const style::FillExtrusionLayer::Impl* const impl; }; template <> diff --git a/src/mbgl/renderer/render_item.hpp b/src/mbgl/renderer/render_item.hpp index 575287d9c6..01bb263d1e 100644 --- a/src/mbgl/renderer/render_item.hpp +++ b/src/mbgl/renderer/render_item.hpp @@ -18,14 +18,12 @@ class Source; class RenderItem { public: RenderItem(const RenderLayer& layer_, - const RenderTile* tile_ = nullptr, - Bucket* bucket_ = nullptr) - : tile(tile_), bucket(bucket_), layer(layer_) { + std::vector<std::reference_wrapper<RenderTile>> tiles_ = {}) + : layer(layer_), tiles(std::move(tiles_)) { } - const RenderTile* const tile; - Bucket* const bucket; const RenderLayer& layer; + std::vector<std::reference_wrapper<RenderTile>> tiles; }; class RenderData { diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index 5c7c491be0..ce59186e61 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -5,11 +5,12 @@ namespace mbgl { using namespace style; -mat4 RenderTile::translatedMatrix(const std::array<float, 2>& translation, - TranslateAnchorType anchor, - const TransformState& state) const { +mat4 RenderTile::translateVtxMatrix(const mat4& tileMatrix, + const std::array<float, 2>& translation, + TranslateAnchorType anchor, + const TransformState& state) const { if (translation[0] == 0 && translation[1] == 0) { - return matrix; + return tileMatrix; } mat4 vtxMatrix; @@ -17,18 +18,41 @@ mat4 RenderTile::translatedMatrix(const std::array<float, 2>& translation, if (anchor == TranslateAnchorType::Viewport) { const double sin_a = std::sin(-state.getAngle()); const double cos_a = std::cos(-state.getAngle()); - matrix::translate(vtxMatrix, matrix, - id.pixelsToTileUnits(translation[0] * cos_a - translation[1] * sin_a, state.getZoom()), - id.pixelsToTileUnits(translation[0] * sin_a + translation[1] * cos_a, state.getZoom()), - 0); + matrix::translate(vtxMatrix, tileMatrix, + id.pixelsToTileUnits(translation[0] * cos_a - translation[1] * sin_a, state.getZoom()), + id.pixelsToTileUnits(translation[0] * sin_a + translation[1] * cos_a, state.getZoom()), + 0); } else { - matrix::translate(vtxMatrix, matrix, - id.pixelsToTileUnits(translation[0], state.getZoom()), - id.pixelsToTileUnits(translation[1], state.getZoom()), - 0); + matrix::translate(vtxMatrix, tileMatrix, + id.pixelsToTileUnits(translation[0], state.getZoom()), + id.pixelsToTileUnits(translation[1], state.getZoom()), + 0); } return vtxMatrix; } +mat4 RenderTile::translatedMatrix(const std::array<float, 2>& translation, + TranslateAnchorType anchor, + const TransformState& state) const { + return translateVtxMatrix(matrix, translation, anchor, state); +} + +mat4 RenderTile::translatedClipMatrix(const std::array<float, 2>& translation, + TranslateAnchorType anchor, + const TransformState& state) const { + return translateVtxMatrix(nearClippedMatrix, translation, anchor, state); +} + +void RenderTile::calculateMatrices(const mat4& projMatrix, + const mat4& projClipMatrix, + const TransformState& transform) { + // Calculate two matrices for this tile: matrix is the standard tile matrix; nearClippedMatrix + // clips the near plane to 100 to save depth buffer precision + transform.matrixFor(matrix, id); + transform.matrixFor(nearClippedMatrix, id); + matrix::multiply(matrix, projMatrix, matrix); + matrix::multiply(nearClippedMatrix, projClipMatrix, nearClippedMatrix); +} + } // namespace mbgl diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp index e2e0c3d656..02e8667eec 100644 --- a/src/mbgl/renderer/render_tile.hpp +++ b/src/mbgl/renderer/render_tile.hpp @@ -24,11 +24,25 @@ public: Tile& tile; ClipID clip; mat4 matrix; + mat4 nearClippedMatrix; bool used = false; mat4 translatedMatrix(const std::array<float, 2>& translate, style::TranslateAnchorType anchor, const TransformState&) const; + + mat4 translatedClipMatrix(const std::array<float, 2>& translate, + style::TranslateAnchorType anchor, + const TransformState&) const; + + void calculateMatrices(const mat4& projMatrix, + const mat4& projClipMatrix, + const TransformState&); +private: + mat4 translateVtxMatrix(const mat4& tileMatrix, + const std::array<float, 2>& translation, + style::TranslateAnchorType anchor, + const TransformState& state) const; }; } // namespace mbgl diff --git a/src/mbgl/shaders/extrusion_texture.cpp b/src/mbgl/shaders/extrusion_texture.cpp new file mode 100644 index 0000000000..c756db181c --- /dev/null +++ b/src/mbgl/shaders/extrusion_texture.cpp @@ -0,0 +1,39 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/shaders/extrusion_texture.hpp> + +namespace mbgl { +namespace shaders { + +const char* extrusion_texture::name = "extrusion_texture"; +const char* extrusion_texture::vertexSource = R"MBGL_SHADER( +uniform mat4 u_matrix; +uniform vec2 u_world; +attribute vec2 a_pos; +varying vec2 v_pos; + +void main() { + gl_Position = u_matrix * vec4(a_pos * u_world, 0, 1); + + v_pos.x = a_pos.x; + v_pos.y = 1.0 - a_pos.y; +} + +)MBGL_SHADER"; +const char* extrusion_texture::fragmentSource = R"MBGL_SHADER( +uniform sampler2D u_image; +uniform float u_opacity; +varying vec2 v_pos; + +void main() { + gl_FragColor = texture2D(u_image, v_pos) * u_opacity; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(0.0); +#endif +} + +)MBGL_SHADER"; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/extrusion_texture.hpp b/src/mbgl/shaders/extrusion_texture.hpp new file mode 100644 index 0000000000..05e54c5499 --- /dev/null +++ b/src/mbgl/shaders/extrusion_texture.hpp @@ -0,0 +1,16 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#pragma once + +namespace mbgl { +namespace shaders { + +class extrusion_texture { +public: + static const char* name; + static const char* vertexSource; + static const char* fragmentSource; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/fill_extrusion.cpp b/src/mbgl/shaders/fill_extrusion.cpp new file mode 100644 index 0000000000..ea1c80545e --- /dev/null +++ b/src/mbgl/shaders/fill_extrusion.cpp @@ -0,0 +1,98 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/shaders/fill_extrusion.hpp> + +namespace mbgl { +namespace shaders { + +const char* fill_extrusion::name = "fill_extrusion"; +const char* fill_extrusion::vertexSource = R"MBGL_SHADER( +uniform mat4 u_matrix; +uniform vec3 u_lightcolor; +uniform lowp vec3 u_lightpos; +uniform lowp float u_lightintensity; + +attribute vec2 a_pos; +attribute vec3 a_normal; +attribute float a_edgedistance; + +varying vec4 v_color; + +uniform lowp float a_base_t; +attribute lowp vec2 a_base; +varying lowp float base; +uniform lowp float a_height_t; +attribute lowp vec2 a_height; +varying lowp float height; + +uniform lowp float a_color_t; +attribute highp vec4 a_color; +varying highp vec4 color; + +void main() { + base = unpack_mix_vec2(a_base, a_base_t); + height = unpack_mix_vec2(a_height, a_height_t); + color = unpack_mix_vec4(a_color, a_color_t); + + base = max(0.0, base); + height = max(0.0, height); + + float ed = a_edgedistance; // use each attrib in order to not trip a VAO assert + float t = mod(a_normal.x, 2.0); + + gl_Position = u_matrix * vec4(a_pos, t > 0.0 ? height : base, 1); + + // Relative luminance (how dark/bright is the surface color?) + float colorvalue = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722; + + v_color = vec4(0.0, 0.0, 0.0, 1.0); + + // Add slight ambient lighting so no extrusions are totally black + vec4 ambientlight = vec4(0.03, 0.03, 0.03, 1.0); + color += ambientlight; + + // Calculate cos(theta), where theta is the angle between surface normal and diffuse light ray + float directional = clamp(dot(a_normal / 16384.0, u_lightpos), 0.0, 1.0); + + // Adjust directional so that + // the range of values for highlight/shading is narrower + // with lower light intensity + // and with lighter/brighter surface colors + directional = mix((1.0 - u_lightintensity), max((1.0 - colorvalue + u_lightintensity), 1.0), directional); + + // Add gradient along z axis of side surfaces + if (a_normal.y != 0.0) { + directional *= clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - u_lightintensity), 1.0); + } + + // Assign final color based on surface + ambient light color, diffuse light directional, and light color + // with lower bounds adjusted to hue of light + // so that shading is tinted with the complementary (opposite) color to the light color + v_color.r += clamp(color.r * directional * u_lightcolor.r, mix(0.0, 0.3, 1.0 - u_lightcolor.r), 1.0); + v_color.g += clamp(color.g * directional * u_lightcolor.g, mix(0.0, 0.3, 1.0 - u_lightcolor.g), 1.0); + v_color.b += clamp(color.b * directional * u_lightcolor.b, mix(0.0, 0.3, 1.0 - u_lightcolor.b), 1.0); +} + +)MBGL_SHADER"; +const char* fill_extrusion::fragmentSource = R"MBGL_SHADER( +varying vec4 v_color; +varying lowp float base; +varying lowp float height; +varying highp vec4 color; + +void main() { + + + + + gl_FragColor = v_color; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +)MBGL_SHADER"; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/fill_extrusion.hpp b/src/mbgl/shaders/fill_extrusion.hpp new file mode 100644 index 0000000000..949ae57f12 --- /dev/null +++ b/src/mbgl/shaders/fill_extrusion.hpp @@ -0,0 +1,16 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#pragma once + +namespace mbgl { +namespace shaders { + +class fill_extrusion { +public: + static const char* name; + static const char* vertexSource; + static const char* fragmentSource; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/fill_extrusion_pattern.cpp b/src/mbgl/shaders/fill_extrusion_pattern.cpp new file mode 100644 index 0000000000..e2de5c20b2 --- /dev/null +++ b/src/mbgl/shaders/fill_extrusion_pattern.cpp @@ -0,0 +1,111 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/shaders/fill_extrusion_pattern.hpp> + +namespace mbgl { +namespace shaders { + +const char* fill_extrusion_pattern::name = "fill_extrusion_pattern"; +const char* fill_extrusion_pattern::vertexSource = R"MBGL_SHADER( +uniform mat4 u_matrix; +uniform vec2 u_pattern_size_a; +uniform vec2 u_pattern_size_b; +uniform vec2 u_pixel_coord_upper; +uniform vec2 u_pixel_coord_lower; +uniform float u_scale_a; +uniform float u_scale_b; +uniform float u_tile_units_to_pixels; +uniform float u_height_factor; + +uniform vec3 u_lightcolor; +uniform lowp vec3 u_lightpos; +uniform lowp float u_lightintensity; + +attribute vec2 a_pos; +attribute vec3 a_normal; +attribute float a_edgedistance; + +varying vec2 v_pos_a; +varying vec2 v_pos_b; +varying vec4 v_lighting; +varying float v_directional; + +uniform lowp float a_base_t; +attribute lowp vec2 a_base; +varying lowp float base; +uniform lowp float a_height_t; +attribute lowp vec2 a_height; +varying lowp float height; + +void main() { + base = unpack_mix_vec2(a_base, a_base_t); + height = unpack_mix_vec2(a_height, a_height_t); + + base = max(0.0, base); + height = max(0.0, height); + + float t = mod(a_normal.x, 2.0); + float z = t > 0.0 ? height : base; + + gl_Position = u_matrix * vec4(a_pos, z, 1); + + vec2 pos = a_normal.x == 1.0 && a_normal.y == 0.0 && a_normal.z == 16384.0 + ? a_pos // extrusion top + : vec2(a_edgedistance, z * u_height_factor); // extrusion side + + v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, pos); + v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, pos); + + v_lighting = vec4(0.0, 0.0, 0.0, 1.0); + float directional = clamp(dot(a_normal / 16383.0, u_lightpos), 0.0, 1.0); + directional = mix((1.0 - u_lightintensity), max((0.5 + u_lightintensity), 1.0), directional); + + if (a_normal.y != 0.0) { + directional *= clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - u_lightintensity), 1.0); + } + + v_lighting.rgb += clamp(directional * u_lightcolor, mix(vec3(0.0), vec3(0.3), 1.0 - u_lightcolor), vec3(1.0)); +} + +)MBGL_SHADER"; +const char* fill_extrusion_pattern::fragmentSource = R"MBGL_SHADER( +uniform vec2 u_pattern_tl_a; +uniform vec2 u_pattern_br_a; +uniform vec2 u_pattern_tl_b; +uniform vec2 u_pattern_br_b; +uniform float u_mix; + +uniform sampler2D u_image; + +varying vec2 v_pos_a; +varying vec2 v_pos_b; +varying vec4 v_lighting; + +varying lowp float base; +varying lowp float height; + +void main() { + + + + vec2 imagecoord = mod(v_pos_a, 1.0); + vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord); + vec4 color1 = texture2D(u_image, pos); + + vec2 imagecoord_b = mod(v_pos_b, 1.0); + vec2 pos2 = mix(u_pattern_tl_b, u_pattern_br_b, imagecoord_b); + vec4 color2 = texture2D(u_image, pos2); + + vec4 mixedColor = mix(color1, color2, u_mix); + + gl_FragColor = mixedColor * v_lighting; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +)MBGL_SHADER"; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/fill_extrusion_pattern.hpp b/src/mbgl/shaders/fill_extrusion_pattern.hpp new file mode 100644 index 0000000000..e9ae001d4e --- /dev/null +++ b/src/mbgl/shaders/fill_extrusion_pattern.hpp @@ -0,0 +1,16 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#pragma once + +namespace mbgl { +namespace shaders { + +class fill_extrusion_pattern { +public: + static const char* name; + static const char* vertexSource; + static const char* fragmentSource; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/preludes.cpp b/src/mbgl/shaders/preludes.cpp index cca0f3e3f1..95fa624e8d 100644 --- a/src/mbgl/shaders/preludes.cpp +++ b/src/mbgl/shaders/preludes.cpp @@ -48,8 +48,9 @@ vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 v // packed like so: // packedValue = floor(input[0]) * 256 + input[1], vec2 unpack_float(const float packedValue) { - float v0 = floor(packedValue / 256.0); - return vec2(v0, packedValue - v0 * 256.0); + int packedIntValue = int(packedValue); + int v0 = packedIntValue / 256; + return vec2(v0, packedIntValue - v0 * 256); } diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp index f6f9753460..2353bd99fe 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp +++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp @@ -16,8 +16,6 @@ public: std::unique_ptr<RenderLayer> createRenderLayer() const override; FillExtrusionPaintProperties::Cascading cascading; - - //style::FillExtrusionLayer::Impl* const impl; }; } // namespace style diff --git a/src/mbgl/style/light_impl.hpp b/src/mbgl/style/light_impl.hpp new file mode 100644 index 0000000000..d1825090fc --- /dev/null +++ b/src/mbgl/style/light_impl.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include <mbgl/style/light.hpp> +#include <mbgl/style/transitioning_property.hpp> +#include <mbgl/style/cascade_parameters.hpp> +#include <mbgl/style/property_evaluator.hpp> +#include <mbgl/style/property_evaluation_parameters.hpp> +#include <mbgl/util/ignore.hpp> + +namespace mbgl { +namespace style { + +template <class TypeList> +class Transitioning; + +template <class... Ps> +class Transitioning<TypeList<Ps...>> : public IndexedTuple< + TypeList<Ps...>, + TypeList<TransitioningProperty<typename Ps::ValueType>...>> +{ +private: + using Properties = TypeList<Ps...>; + using Raw = IndexedTuple<Properties, Properties>; + using Super = IndexedTuple< + TypeList<Ps...>, + TypeList<TransitioningProperty<typename Ps::ValueType>...>>; + +public: + Transitioning() = default; + Transitioning(const Raw& raw, Transitioning&& prior, const CascadeParameters& params) + : Super { + TransitioningProperty<typename Ps::ValueType>( + raw.template get<Ps>().value, + std::move(prior.template get<Ps>()), + raw.template get<Ps>().transition.reverseMerge(params.transition), + params.now)... + } {} + + bool hasTransition() const { + bool result = false; + util::ignore({ result |= this->template get<Ps>().hasTransition()... }); + return result; + } +}; + +template <class TypeList> +class Evaluated; + +template <class... Ps> +class Evaluated<TypeList<Ps...>> : public IndexedTuple< + TypeList<Ps...>, + TypeList<typename Ps::Type...>> +{ +private: + using Properties = TypeList<Ps...>; + using TransitioningPs = Transitioning<Properties>; + using Super = IndexedTuple< + TypeList<Ps...>, + TypeList<typename Ps::Type...>>; + +public: + Evaluated() = default; + Evaluated(TransitioningPs& transitioning, const PropertyEvaluationParameters& params) + : Super { + transitioning.template get<Ps>() + .evaluate(PropertyEvaluator<typename Ps::Type>(params, Ps::defaultValue()), params.now)... + } {} +}; + +using TransitioningLight = Transitioning<LightProperties>; +using EvaluatedLight = Evaluated<LightProperties>; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp index 7f7018748c..dd8d6c0b50 100644 --- a/src/mbgl/style/paint_property.hpp +++ b/src/mbgl/style/paint_property.hpp @@ -1,5 +1,6 @@ #pragma once +#include <mbgl/style/transitioning_property.hpp> #include <mbgl/style/class_dictionary.hpp> #include <mbgl/style/property_value.hpp> #include <mbgl/style/data_driven_property_value.hpp> @@ -24,68 +25,6 @@ class GeometryTileFeature; namespace style { template <class Value> -class UnevaluatedPaintProperty { -public: - UnevaluatedPaintProperty() = default; - - UnevaluatedPaintProperty(Value value_, - UnevaluatedPaintProperty<Value> prior_, - TransitionOptions transition, - TimePoint now) - : begin(now + transition.delay.value_or(Duration::zero())), - end(begin + transition.duration.value_or(Duration::zero())), - value(std::move(value_)) { - if (transition.isDefined()) { - prior = { std::move(prior_) }; - } - } - - template <class Evaluator> - auto evaluate(const Evaluator& evaluator, TimePoint now) { - auto finalValue = value.evaluate(evaluator); - if (!prior) { - // No prior value. - return finalValue; - } else if (now >= end) { - // Transition from prior value is now complete. - prior = {}; - return finalValue; - } else if (value.isDataDriven()) { - // Transitions to data-driven properties are not supported. - // We snap immediately to the data-driven value so that, when we perform layout, - // we see the data-driven function and can use it to populate vertex buffers. - prior = {}; - return finalValue; - } else if (now < begin) { - // Transition hasn't started yet. - return prior->get().evaluate(evaluator, now); - } else { - // Interpolate between recursively-calculated prior value and final. - float t = std::chrono::duration<float>(now - begin) / (end - begin); - return util::interpolate(prior->get().evaluate(evaluator, now), finalValue, util::DEFAULT_TRANSITION_EASE.solve(t, 0.001)); - } - } - - bool hasTransition() const { - return bool(prior); - } - - bool isUndefined() const { - return value.isUndefined(); - } - - const Value& getValue() const { - return value; - } - -private: - optional<mapbox::util::recursive_wrapper<UnevaluatedPaintProperty<Value>>> prior; - TimePoint begin; - TimePoint end; - Value value; -}; - -template <class Value> class CascadingPaintProperty { public: bool isUndefined() const { @@ -112,8 +51,8 @@ public: transitions[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = transition; } - template <class UnevaluatedPaintProperty> - UnevaluatedPaintProperty cascade(const CascadeParameters& params, UnevaluatedPaintProperty prior) const { + template <class TransitioningProperty> + TransitioningProperty cascade(const CascadeParameters& params, TransitioningProperty prior) const { TransitionOptions transition; Value value; @@ -131,7 +70,7 @@ public: } } - return UnevaluatedPaintProperty(std::move(value), + return TransitioningProperty(std::move(value), std::move(prior), transition.reverseMerge(params.transition), params.now); @@ -147,7 +86,7 @@ class PaintProperty { public: using ValueType = PropertyValue<T>; using CascadingType = CascadingPaintProperty<ValueType>; - using UnevaluatedType = UnevaluatedPaintProperty<ValueType>; + using UnevaluatedType = TransitioningProperty<ValueType>; using EvaluatorType = PropertyEvaluator<T>; using EvaluatedType = T; static constexpr bool IsDataDriven = false; @@ -158,7 +97,7 @@ class DataDrivenPaintProperty { public: using ValueType = DataDrivenPropertyValue<T>; using CascadingType = CascadingPaintProperty<ValueType>; - using UnevaluatedType = UnevaluatedPaintProperty<ValueType>; + using UnevaluatedType = TransitioningProperty<ValueType>; using EvaluatorType = DataDrivenPropertyEvaluator<T>; using EvaluatedType = PossiblyEvaluatedPropertyValue<T>; static constexpr bool IsDataDriven = true; @@ -172,7 +111,7 @@ class CrossFadedPaintProperty { public: using ValueType = PropertyValue<T>; using CascadingType = CascadingPaintProperty<ValueType>; - using UnevaluatedType = UnevaluatedPaintProperty<ValueType>; + using UnevaluatedType = TransitioningProperty<ValueType>; using EvaluatorType = CrossFadedPropertyEvaluator<T>; using EvaluatedType = Faded<T>; static constexpr bool IsDataDriven = false; diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp index 19ea8cefee..c407e438fb 100644 --- a/src/mbgl/style/parser.cpp +++ b/src/mbgl/style/parser.cpp @@ -4,6 +4,7 @@ #include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/source.hpp> #include <mbgl/style/conversion/layer.hpp> +#include <mbgl/style/conversion/light.hpp> #include <mbgl/util/logging.hpp> @@ -82,6 +83,10 @@ StyleParseResult Parser::parse(const std::string& json) { } } + if (document.HasMember("light")) { + parseLight(document["light"]); + } + if (document.HasMember("sources")) { parseSources(document["sources"]); } @@ -107,6 +112,17 @@ StyleParseResult Parser::parse(const std::string& json) { return nullptr; } +void Parser::parseLight(const JSValue& value) { + conversion::Error error; + optional<Light> converted = conversion::convert<Light>(value, error); + if (!converted) { + Log::Warning(Event::ParseStyle, error.message); + return; + } + + light = *converted; +} + void Parser::parseSources(const JSValue& value) { if (!value.IsObject()) { Log::Warning(Event::ParseStyle, "sources must be an object"); diff --git a/src/mbgl/style/parser.hpp b/src/mbgl/style/parser.hpp index a05a0b316a..32b8a7a8bc 100644 --- a/src/mbgl/style/parser.hpp +++ b/src/mbgl/style/parser.hpp @@ -2,6 +2,7 @@ #include <mbgl/style/layer.hpp> #include <mbgl/style/source.hpp> +#include <mbgl/style/light.hpp> #include <mbgl/util/rapidjson.hpp> #include <mbgl/util/font_stack.hpp> @@ -31,6 +32,8 @@ public: std::vector<std::unique_ptr<Source>> sources; std::vector<std::unique_ptr<Layer>> layers; + Light light; + std::string name; LatLng latLng; double zoom = 0; @@ -41,6 +44,7 @@ public: std::vector<FontStack> fontStacks() const; private: + void parseLight(const JSValue&); void parseSources(const JSValue&); void parseLayers(const JSValue&); void parseLayer(const std::string& id, const JSValue&, std::unique_ptr<Layer>&); diff --git a/src/mbgl/style/source_impl.cpp b/src/mbgl/style/source_impl.cpp index 9fabc54f7d..7a65dd1ded 100644 --- a/src/mbgl/style/source_impl.cpp +++ b/src/mbgl/style/source_impl.cpp @@ -57,8 +57,9 @@ void Source::Impl::invalidateTiles() { } void Source::Impl::startRender(algorithm::ClipIDGenerator& generator, - const mat4& projMatrix, - const TransformState& transform) { + const mat4& projMatrix, + const mat4& clipMatrix, + const TransformState& transform) { if (type == SourceType::Vector || type == SourceType::GeoJSON || type == SourceType::Annotations) { @@ -67,8 +68,7 @@ void Source::Impl::startRender(algorithm::ClipIDGenerator& generator, for (auto& pair : renderTiles) { auto& tile = pair.second; - transform.matrixFor(tile.matrix, tile.id); - matrix::multiply(tile.matrix, projMatrix, tile.matrix); + tile.calculateMatrices(projMatrix, clipMatrix, transform); } } diff --git a/src/mbgl/style/source_impl.hpp b/src/mbgl/style/source_impl.hpp index b4473cbc84..387428ec59 100644 --- a/src/mbgl/style/source_impl.hpp +++ b/src/mbgl/style/source_impl.hpp @@ -60,6 +60,7 @@ public: void startRender(algorithm::ClipIDGenerator&, const mat4& projMatrix, + const mat4& clipMatrix, const TransformState&); void finishRender(Painter&); diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index e8141c3c6b..8dfe7eac06 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -54,6 +54,7 @@ Style::Style(Scheduler& scheduler_, FileSource& fileSource_, float pixelRatio) glyphAtlas(std::make_unique<GlyphAtlas>(Size{ 2048, 2048 }, fileSource)), spriteAtlas(std::make_unique<SpriteAtlas>(Size{ 1024, 1024 }, pixelRatio)), lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })), + light(std::make_unique<Light>()), observer(&nullObserver) { glyphAtlas->setObserver(this); spriteAtlas->setObserver(this); @@ -141,6 +142,7 @@ void Style::setJSON(const std::string& json) { defaultZoom = parser.zoom; defaultBearing = parser.bearing; defaultPitch = parser.pitch; + light = std::make_unique<Light>(parser.light); glyphAtlas->setURL(parser.glyphURL); spriteAtlas->load(parser.spriteURL, scheduler, fileSource); @@ -352,6 +354,8 @@ void Style::cascade(const TimePoint& timePoint, MapMode mode) { for (const auto& layer : renderLayers) { layer->cascade(parameters); } + + transitioningLight = TransitioningLight(*light, std::move(transitioningLight), parameters); } void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) { @@ -370,7 +374,7 @@ void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) { mode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Duration::zero() }; - hasPendingTransitions = false; + hasPendingTransitions = transitioningLight.hasTransition(); for (const auto& layer : renderLayers) { hasPendingTransitions |= layer->evaluate(parameters); @@ -389,6 +393,8 @@ void Style::recalculate(float z, const TimePoint& timePoint, MapMode mode) { } } + evaluatedLight = EvaluatedLight(transitioningLight, parameters); + // Remove the existing tiles if we didn't end up re-enabling the source. for (const auto& source : sources) { if (!source->baseImpl->enabled) { @@ -509,8 +515,9 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions, float angle) const }); } - for (auto& tileRef : sortedTiles) { - auto& tile = tileRef.get(); + std::vector<std::reference_wrapper<RenderTile>> sortedTilesForInsertion; + for (auto tileIt = sortedTiles.begin(); tileIt != sortedTiles.end(); ++tileIt) { + auto& tile = tileIt->get(); if (!tile.tile.isRenderable()) { continue; } @@ -523,8 +530,9 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions, float angle) const // Look back through the buckets we decided to render to find out whether there is // already a bucket from this layer that is a parent of this tile. Tiles are ordered // by zoom level when we obtain them from getTiles(). - for (auto it = result.order.rbegin(); it != result.order.rend() && (&it->layer == layer.get()); ++it) { - if (tile.tile.id.isChildOf(it->tile->tile.id)) { + for (auto it = sortedTilesForInsertion.rbegin(); + it != sortedTilesForInsertion.rend(); ++it) { + if (tile.tile.id.isChildOf(it->get().tile.id)) { skip = true; break; } @@ -536,10 +544,12 @@ RenderData Style::getRenderData(MapDebugOptions debugOptions, float angle) const auto bucket = tile.tile.getBucket(*layer); if (bucket) { - result.order.emplace_back(*layer, &tile, bucket); + sortedTilesForInsertion.emplace_back(tile); tile.used = true; } } + + result.order.emplace_back(*layer, std::move(sortedTilesForInsertion)); } return result; diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index 127430a89f..26959c9fbf 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -6,6 +6,7 @@ #include <mbgl/style/layer_observer.hpp> #include <mbgl/style/update_batch.hpp> #include <mbgl/renderer/render_layer.hpp> +#include <mbgl/style/light_impl.hpp> #include <mbgl/text/glyph_atlas_observer.hpp> #include <mbgl/sprite/sprite_atlas_observer.hpp> #include <mbgl/map/mode.hpp> @@ -120,6 +121,10 @@ public: std::unique_ptr<SpriteAtlas> spriteAtlas; std::unique_ptr<LineAtlas> lineAtlas; + std::unique_ptr<Light> light; + TransitioningLight transitioningLight; + EvaluatedLight evaluatedLight; + private: std::vector<std::unique_ptr<Source>> sources; std::vector<std::unique_ptr<Layer>> layers; diff --git a/src/mbgl/style/transitioning_property.hpp b/src/mbgl/style/transitioning_property.hpp new file mode 100644 index 0000000000..5456322b33 --- /dev/null +++ b/src/mbgl/style/transitioning_property.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include <mbgl/style/property_value.hpp> +#include <mbgl/style/data_driven_property_value.hpp> +#include <mbgl/style/transition_options.hpp> +#include <mbgl/util/interpolate.hpp> + +#include <utility> + +namespace mbgl { +namespace style { + +template <class Value> +class TransitioningProperty { +public: + TransitioningProperty() = default; + + TransitioningProperty(Value value_, + TransitioningProperty<Value> prior_, + TransitionOptions transition, + TimePoint now) + : begin(now + transition.delay.value_or(Duration::zero())), + end(begin + transition.duration.value_or(Duration::zero())), + value(std::move(value_)) { + if (transition.isDefined()) { + prior = { std::move(prior_) }; + } + } + + template <class Evaluator> + auto evaluate(const Evaluator& evaluator, TimePoint now) { + auto finalValue = value.evaluate(evaluator); + if (!prior) { + // No prior value. + return finalValue; + } else if (now >= end) { + // Transition from prior value is now complete. + prior = {}; + return finalValue; + } else if (value.isDataDriven()) { + // Transitions to data-driven properties are not supported. + // We snap immediately to the data-driven value so that, when we perform layout, + // we see the data-driven function and can use it to populate vertex buffers. + prior = {}; + return finalValue; + } else if (now < begin) { + // Transition hasn't started yet. + return prior->get().evaluate(evaluator, now); + } else { + // Interpolate between recursively-calculated prior value and final. + float t = std::chrono::duration<float>(now - begin) / (end - begin); + return util::interpolate(prior->get().evaluate(evaluator, now), finalValue, + util::DEFAULT_TRANSITION_EASE.solve(t, 0.001)); + } + } + + bool hasTransition() const { + return bool(prior); + } + + bool isUndefined() const { + return value.isUndefined(); + } + + const Value& getValue() const { + return value; + } + +private: + optional<mapbox::util::recursive_wrapper<TransitioningProperty<Value>>> prior; + TimePoint begin; + TimePoint end; + Value value; +}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/types.cpp b/src/mbgl/style/types.cpp index bf2ba8a793..b37e73ffb1 100644 --- a/src/mbgl/style/types.cpp +++ b/src/mbgl/style/types.cpp @@ -89,4 +89,9 @@ MBGL_DEFINE_ENUM(IconTextFitType, { { IconTextFitType::Height, "height" }, }); +MBGL_DEFINE_ENUM(LightAnchorType, { + { LightAnchorType::Map, "map" }, + { LightAnchorType::Viewport, "viewport" } +}); + } // namespace mbgl diff --git a/src/mbgl/util/indexed_tuple.hpp b/src/mbgl/util/indexed_tuple.hpp deleted file mode 100644 index a414639530..0000000000 --- a/src/mbgl/util/indexed_tuple.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include <mbgl/util/type_list.hpp> - -#include <type_traits> -#include <tuple> - -namespace mbgl { - -template <class T, class... Ts> -struct TypeIndex; - -template <class T, class... Ts> -struct TypeIndex<T, T, Ts...> : std::integral_constant<std::size_t, 0> {}; - -template <class T, class U, class... Ts> -struct TypeIndex<T, U, Ts...> : std::integral_constant<std::size_t, 1 + TypeIndex<T, Ts...>::value> {}; - -template <class...> class IndexedTuple; - -// A tuple of Ts, where individual members can be accessed via `t.get<I>()` for I ∈ Is. -// -// See https://github.com/mapbox/cpp/blob/master/C%2B%2B%20Structural%20Metaprogramming.md -// for motivation. -// -template <class... Is, class... Ts> -class IndexedTuple<TypeList<Is...>, TypeList<Ts...>> : public std::tuple<Ts...> { -public: - static_assert(sizeof...(Is) == sizeof...(Ts), "IndexedTuple size mismatch"); - - using std::tuple<Ts...>::tuple; - - template <class I> - static constexpr std::size_t Index = TypeIndex<I, Is...>::value; - - template <class I> - auto& get() { - return std::get<Index<I>>(*this); - } - - template <class I> - const auto& get() const { - return std::get<Index<I>>(*this); - } - - template <class... Js, class... Us> - IndexedTuple<TypeList<Is..., Js...>, TypeList<Ts..., Us...>> - concat(const IndexedTuple<TypeList<Js...>, TypeList<Us...>>& other) const { - return IndexedTuple<TypeList<Is..., Js...>, TypeList<Ts..., Us...>> { - get<Is>()..., - other.template get<Js>()... - }; - } -}; - -} // namespace mbgl diff --git a/src/mbgl/util/mat3.cpp b/src/mbgl/util/mat3.cpp index e2200867ce..107be81985 100644 --- a/src/mbgl/util/mat3.cpp +++ b/src/mbgl/util/mat3.cpp @@ -25,8 +25,9 @@ #include <cmath> namespace mbgl { +namespace matrix { -void matrix::identity(mat3& out) { +void identity(mat3& out) { out[0] = 1.0f; out[1] = 0.0f; out[2] = 0.0f; @@ -38,7 +39,7 @@ void matrix::identity(mat3& out) { out[8] = 1.0f; } -void matrix::translate(mat3& out, const mat3& a, double x, double y) { +void translate(mat3& out, const mat3& a, double x, double y) { double a00 = a[0], a01 = a[1], a02 = a[2], a10 = a[3], a11 = a[4], a12 = a[5], a20 = a[6], a21 = a[7], a22 = a[8]; @@ -56,7 +57,7 @@ void matrix::translate(mat3& out, const mat3& a, double x, double y) { out[8] = x * a02 + y * a12 + a22; } -void matrix::rotate(mat3& out, const mat3& a, double rad) { +void rotate(mat3& out, const mat3& a, double rad) { double s = std::sin(rad), c = std::cos(rad), a00 = a[0], @@ -82,7 +83,7 @@ void matrix::rotate(mat3& out, const mat3& a, double rad) { out[8] = a22; } -void matrix::scale(mat3& out, const mat3& a, double x, double y) { +void scale(mat3& out, const mat3& a, double x, double y) { out[0] = x * a[0]; out[1] = x * a[1]; out[2] = x * a[2]; @@ -94,4 +95,11 @@ void matrix::scale(mat3& out, const mat3& a, double x, double y) { out[8] = a[8]; } +void transformMat3f(vec3f& out, const vec3f& a, const mat3& m) { + out[0] = m[0] * a[0] + m[3] * a[1] + m[6] * a[2]; + out[1] = m[1] * a[0] + m[4] * a[1] + m[7] * a[2]; + out[2] = m[2] * a[0] + m[5] * a[1] + m[8] * a[2]; +} + +} // namespace matrix } // namespace mbgl diff --git a/src/mbgl/util/mat3.hpp b/src/mbgl/util/mat3.hpp index ca4955fe5f..c4203c940b 100644 --- a/src/mbgl/util/mat3.hpp +++ b/src/mbgl/util/mat3.hpp @@ -26,7 +26,9 @@ namespace mbgl { -typedef std::array<double, 9> mat3; +using vec3 = std::array<double, 3>; +using vec3f = std::array<float, 3>; +using mat3 = std::array<double, 9>; namespace matrix { @@ -35,5 +37,7 @@ void translate(mat3& out, const mat3& a, double x, double y); void rotate(mat3& out, const mat3& a, double rad); void scale(mat3& out, const mat3& a, double x, double y); +void transformMat3f(vec3f& out, const vec3f& a, const mat3& m); + } // namespace matrix } // namespace mbgl diff --git a/src/mbgl/util/offscreen_texture.cpp b/src/mbgl/util/offscreen_texture.cpp index 56ef60b15c..e719ac566e 100644 --- a/src/mbgl/util/offscreen_texture.cpp +++ b/src/mbgl/util/offscreen_texture.cpp @@ -14,12 +14,13 @@ public: void bind() { if (!framebuffer) { - texture = context.createTexture(size); + texture = context.createTexture(size, gl::TextureFormat::RGBA); framebuffer = context.createFramebuffer(*texture); } else { context.bindFramebuffer = framebuffer->framebuffer; } + context.activeTexture = 0; context.viewport = { 0, 0, size }; } @@ -36,6 +37,20 @@ public: return size; } + void bindRenderbuffers(gl::TextureUnit unit) { + if (!framebuffer) { + texture = context.createTexture(size, gl::TextureFormat::RGBA, unit); + gl::Renderbuffer<gl::RenderbufferType::DepthComponent> depthTarget = context.createRenderbuffer<gl::RenderbufferType::DepthComponent>(size); + framebuffer = context.createFramebuffer(*texture, depthTarget); + + } else { + context.bindFramebuffer = framebuffer->framebuffer; + } + + context.activeTexture = unit; + context.viewport = { 0, 0, size }; + } + private: gl::Context& context; const Size size; @@ -66,4 +81,8 @@ const Size& OffscreenTexture::getSize() const { return impl->getSize(); } +void OffscreenTexture::bindRenderbuffers(gl::TextureUnit unit) { + impl->bindRenderbuffers(unit); +} + } // namespace mbgl diff --git a/src/mbgl/util/offscreen_texture.hpp b/src/mbgl/util/offscreen_texture.hpp index b8bfabf7d3..4e9e936114 100644 --- a/src/mbgl/util/offscreen_texture.hpp +++ b/src/mbgl/util/offscreen_texture.hpp @@ -16,6 +16,7 @@ public: ~OffscreenTexture(); void bind() override; + void bindRenderbuffers(gl::TextureUnit unit = 0); PremultipliedImage readStillImage(); diff --git a/src/mbgl/util/type_list.hpp b/src/mbgl/util/type_list.hpp deleted file mode 100644 index 4a5e95c8a4..0000000000 --- a/src/mbgl/util/type_list.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include <type_traits> -#include <tuple> - -namespace mbgl { - -template <class...> -class TypeList {}; - -namespace detail { - -template <class, class> -struct TypeCons; - -template <class T, class... Ts> -struct TypeCons<T, TypeList<Ts...>> { - using Type = TypeList<T, Ts...>; -}; - -template <class, template <class> class> -struct TypeFilter; - -template <template <class> class Predicate> -struct TypeFilter<TypeList<>, Predicate> { - using Type = TypeList<>; -}; - -template <template <class> class Predicate, class T, class... Ts> -struct TypeFilter<TypeList<T, Ts...>, Predicate> { - using Tail = typename TypeFilter<TypeList<Ts...>, Predicate>::Type; - using Type = std::conditional_t<Predicate<T>::value, typename TypeCons<T, Tail>::Type, Tail>; -}; - -} // namespace detail - -template <class TypeList, template <class> class Predicate> -using FilteredTypeList = typename detail::TypeFilter<TypeList, Predicate>::Type; - -} // namespace mbgl |