1 #include <mbgl/map/transform_state.hpp>
2 #include <mbgl/math/log2.hpp>
3 #include <mbgl/renderer/buckets/raster_bucket.hpp>
4 #include <mbgl/renderer/paint_parameters.hpp>
5 #include <mbgl/renderer/render_tile.hpp>
6 #include <mbgl/renderer/sources/render_image_source.hpp>
7 #include <mbgl/renderer/tile_parameters.hpp>
8 #include <mbgl/renderer/render_static_data.hpp>
9 #include <mbgl/programs/programs.hpp>
10 #include <mbgl/util/tile_coordinate.hpp>
11 #include <mbgl/util/tile_cover.hpp>
12 #include <mbgl/util/logging.hpp>
13 #include <mbgl/util/constants.hpp>
14 
15 namespace mbgl {
16 
17 using namespace style;
18 
RenderImageSource(Immutable<style::ImageSource::Impl> impl_)19 RenderImageSource::RenderImageSource(Immutable<style::ImageSource::Impl> impl_)
20     : RenderSource(impl_) {
21 }
22 
23 RenderImageSource::~RenderImageSource() = default;
24 
impl() const25 const style::ImageSource::Impl& RenderImageSource::impl() const {
26     return static_cast<const style::ImageSource::Impl&>(*baseImpl);
27 }
28 
isLoaded() const29 bool RenderImageSource::isLoaded() const {
30     return !!bucket;
31 }
32 
startRender(PaintParameters & parameters)33 void RenderImageSource::startRender(PaintParameters& parameters) {
34     if (!isLoaded()) {
35         return;
36     }
37 
38     matrices.clear();
39 
40     for (size_t i = 0; i < tileIds.size(); i++) {
41         mat4 matrix;
42         matrix::identity(matrix);
43         parameters.state.matrixFor(matrix, tileIds[i]);
44         matrix::multiply(matrix, parameters.alignedProjMatrix, matrix);
45         matrices.push_back(matrix);
46     }
47 
48     if (bucket->needsUpload()) {
49         bucket->upload(parameters.context);
50     }
51 }
52 
finishRender(PaintParameters & parameters)53 void RenderImageSource::finishRender(PaintParameters& parameters) {
54     if (!isLoaded() || !(parameters.debugOptions & MapDebugOptions::TileBorders)) {
55         return;
56     }
57 
58     static const style::Properties<>::PossiblyEvaluated properties {};
59     static const DebugProgram::PaintPropertyBinders paintAttributeData(properties, 0);
60 
61     auto& programInstance = parameters.programs.debug;
62 
63     for (auto matrix : matrices) {
64         programInstance.draw(
65             parameters.context,
66             gl::LineStrip { 4.0f * parameters.pixelRatio },
67             gl::DepthMode::disabled(),
68             gl::StencilMode::disabled(),
69             gl::ColorMode::unblended(),
70             parameters.staticData.tileBorderIndexBuffer,
71             parameters.staticData.tileBorderSegments,
72             programInstance.computeAllUniformValues(
73                 DebugProgram::UniformValues {
74                     uniforms::u_matrix::Value{ matrix },
75                     uniforms::u_color::Value{ Color::red() }
76                 },
77                 paintAttributeData,
78                 properties,
79                 parameters.state.getZoom()
80             ),
81             programInstance.computeAllAttributeBindings(
82                 parameters.staticData.tileVertexBuffer,
83                 paintAttributeData,
84                 properties
85             ),
86             "image"
87         );
88     }
89 }
90 
91 std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString &,const TransformState &,const std::vector<const RenderLayer * > &,const RenderedQueryOptions &,const mat4 &) const92 RenderImageSource::queryRenderedFeatures(const ScreenLineString&,
93                                          const TransformState&,
94                                          const std::vector<const RenderLayer*>&,
95                                          const RenderedQueryOptions&,
96                                          const mat4&) const {
97     return std::unordered_map<std::string, std::vector<Feature>> {};
98 }
99 
querySourceFeatures(const SourceQueryOptions &) const100 std::vector<Feature> RenderImageSource::querySourceFeatures(const SourceQueryOptions&) const {
101     return {};
102 }
103 
update(Immutable<style::Source::Impl> baseImpl_,const std::vector<Immutable<Layer::Impl>> &,const bool needsRendering,const bool,const TileParameters & parameters)104 void RenderImageSource::update(Immutable<style::Source::Impl> baseImpl_,
105                                const std::vector<Immutable<Layer::Impl>>&,
106                                const bool needsRendering,
107                                const bool,
108                                const TileParameters& parameters) {
109     enabled = needsRendering;
110     if (!needsRendering) {
111         return;
112     }
113 
114     auto transformState = parameters.transformState;
115     std::swap(baseImpl, baseImpl_);
116 
117     auto coords = impl().getCoordinates();
118     std::shared_ptr<PremultipliedImage> image = impl().getImage();
119 
120     if (!image || !image->valid()) {
121         enabled = false;
122         return;
123     }
124 
125     // Compute the z0 tile coordinates for the given LatLngs
126     TileCoordinatePoint nePoint = { -INFINITY, -INFINITY };
127     TileCoordinatePoint swPoint = { INFINITY, INFINITY };
128     std::vector<TileCoordinatePoint> tileCoordinates;
129     for (LatLng latLng : coords) {
130         auto point = TileCoordinate::fromLatLng(0, latLng).p;
131         tileCoordinates.push_back(point);
132         swPoint.x = std::min(swPoint.x, point.x);
133         nePoint.x = std::max(nePoint.x, point.x);
134         swPoint.y = std::min(swPoint.y, point.y);
135         nePoint.y = std::max(nePoint.y, point.y);
136    }
137 
138     // Calculate the optimum zoom level to determine the tile ids to use for transforms
139     auto dx = nePoint.x - swPoint.x;
140     auto dy = nePoint.y - swPoint.y;
141     auto dMax = std::max(dx, dy);
142     double zoom = std::max(0.0, std::floor(-::log2(dMax)));
143 
144     // Only enable if the long side of the image is > 2 pixels. Resulting in a
145     // display of at least 2 x 1 px image
146     // A tile coordinate unit represents the length of one tile (tileSize) at a given zoom.
147     // To convert a tile coordinate to pixels, multiply by tileSize.
148     // Here dMax is in z0 tile units, so we also scale by 2^z to match current zoom.
149     enabled = dMax * std::pow(2.0, transformState.getZoom()) * util::tileSize > 2.0;
150     if (!enabled) {
151         return;
152     }
153 
154     auto imageBounds = LatLngBounds::hull(coords[0], coords[1]);
155     imageBounds.extend(coords[2]);
156     imageBounds.extend(coords[3]);
157     auto tileCover = util::tileCover(imageBounds, zoom);
158     tileIds.clear();
159     tileIds.push_back(tileCover[0]);
160 
161     bool hasVisibleTile = false;
162     // Add additional wrapped tile ids if neccessary
163     auto idealTiles = util::tileCover(transformState, transformState.getZoom());
164     for (auto tile : idealTiles) {
165         if (tile.wrap != 0 && tileCover[0].canonical.isChildOf(tile.canonical)) {
166             tileIds.push_back({ tile.wrap, tileCover[0].canonical });
167             hasVisibleTile = true;
168         }
169         else if (!hasVisibleTile) {
170             for (auto coveringTile: tileCover) {
171                 if(coveringTile.canonical == tile.canonical ||
172                     coveringTile.canonical.isChildOf(tile.canonical) ||
173                     tile.canonical.isChildOf(coveringTile.canonical)) {
174                     hasVisibleTile = true;
175                 }
176             }
177         }
178     }
179 
180     enabled = hasVisibleTile;
181     if (!enabled) {
182         return;
183     }
184 
185     // Calculate Geometry Coordinates based on tile cover at ideal zoom
186     GeometryCoordinates geomCoords;
187     for (auto tileCoords : tileCoordinates) {
188         auto gc = TileCoordinate::toGeometryCoordinate(tileIds[0], tileCoords);
189         geomCoords.push_back(gc);
190     }
191     if (!bucket) {
192         bucket = std::make_unique<RasterBucket>(image);
193     } else {
194         bucket->clear();
195         if (image != bucket->image) {
196             bucket->setImage(image);
197         }
198     }
199 
200     // Set Bucket Vertices, Indices, and segments
201     bucket->vertices.emplace_back(
202         RasterProgram::layoutVertex({ geomCoords[0].x, geomCoords[0].y }, { 0, 0 }));
203     bucket->vertices.emplace_back(
204         RasterProgram::layoutVertex({ geomCoords[1].x, geomCoords[1].y }, { util::EXTENT, 0 }));
205     bucket->vertices.emplace_back(
206         RasterProgram::layoutVertex({ geomCoords[3].x, geomCoords[3].y }, { 0, util::EXTENT }));
207     bucket->vertices.emplace_back(
208         RasterProgram::layoutVertex({ geomCoords[2].x, geomCoords[2].y }, { util::EXTENT, util::EXTENT }));
209 
210     bucket->indices.emplace_back(0, 1, 2);
211     bucket->indices.emplace_back(1, 2, 3);
212 
213     bucket->segments.emplace_back(0, 0, 4, 6);
214 }
215 
dumpDebugLogs() const216 void RenderImageSource::dumpDebugLogs() const {
217     Log::Info(Event::General, "RenderImageSource::id: %s", impl().id.c_str());
218     Log::Info(Event::General, "RenderImageSource::loaded: %s", isLoaded() ? "yes" : "no");
219 }
220 
221 } // namespace mbgl
222