227 lines
8.3 KiB
C++
227 lines
8.3 KiB
C++
#include <mbgl/map/transform_state.hpp>
|
|
#include <mbgl/math/log2.hpp>
|
|
#include <mbgl/renderer/buckets/raster_bucket.hpp>
|
|
#include <mbgl/renderer/paint_parameters.hpp>
|
|
#include <mbgl/renderer/render_tile.hpp>
|
|
#include <mbgl/renderer/sources/render_image_source.hpp>
|
|
#include <mbgl/renderer/tile_parameters.hpp>
|
|
#include <mbgl/renderer/render_static_data.hpp>
|
|
#include <mbgl/programs/programs.hpp>
|
|
#include <mbgl/gfx/cull_face_mode.hpp>
|
|
#include <mbgl/util/tile_coordinate.hpp>
|
|
#include <mbgl/util/tile_cover.hpp>
|
|
#include <mbgl/util/logging.hpp>
|
|
#include <mbgl/util/constants.hpp>
|
|
|
|
namespace mbgl {
|
|
|
|
using namespace style;
|
|
|
|
RenderImageSource::RenderImageSource(Immutable<style::ImageSource::Impl> impl_)
|
|
: RenderSource(impl_) {
|
|
}
|
|
|
|
RenderImageSource::~RenderImageSource() = default;
|
|
|
|
const style::ImageSource::Impl& RenderImageSource::impl() const {
|
|
return static_cast<const style::ImageSource::Impl&>(*baseImpl);
|
|
}
|
|
|
|
bool RenderImageSource::isLoaded() const {
|
|
return !!sharedData.bucket;
|
|
}
|
|
|
|
void RenderImageSource::upload(gfx::UploadPass& uploadPass) {
|
|
if (sharedData.bucket->needsUpload()) {
|
|
sharedData.bucket->upload(uploadPass);
|
|
}
|
|
}
|
|
|
|
void RenderImageSource::prepare(const SourcePrepareParameters& parameters) {
|
|
if (!isLoaded()) {
|
|
return;
|
|
}
|
|
|
|
sharedData.matrices = std::make_shared<std::vector<mat4>>(tileIds.size(), mat4());
|
|
const auto& transformParams = parameters.transform;
|
|
for (size_t i = 0u; i < tileIds.size(); ++i) {
|
|
mat4& matrix = (*sharedData.matrices)[i];
|
|
matrix::identity(matrix);
|
|
transformParams.state.matrixFor(matrix, tileIds[i]);
|
|
matrix::multiply(matrix, transformParams.alignedProjMatrix, matrix);
|
|
}
|
|
}
|
|
|
|
void RenderImageSource::finishRender(PaintParameters& parameters) {
|
|
if (!isLoaded() || !(parameters.debugOptions & MapDebugOptions::TileBorders)) {
|
|
return;
|
|
}
|
|
|
|
static const style::Properties<>::PossiblyEvaluated properties {};
|
|
static const DebugProgram::Binders paintAttributeData(properties, 0);
|
|
|
|
auto& programInstance = parameters.programs.debug;
|
|
|
|
for (auto matrix : *sharedData.matrices) {
|
|
programInstance.draw(
|
|
parameters.context,
|
|
*parameters.renderPass,
|
|
gfx::LineStrip { 4.0f * parameters.pixelRatio },
|
|
gfx::DepthMode::disabled(),
|
|
gfx::StencilMode::disabled(),
|
|
gfx::ColorMode::unblended(),
|
|
gfx::CullFaceMode::disabled(),
|
|
*parameters.staticData.tileBorderIndexBuffer,
|
|
parameters.staticData.tileBorderSegments,
|
|
programInstance.computeAllUniformValues(
|
|
DebugProgram::LayoutUniformValues {
|
|
uniforms::matrix::Value( matrix ),
|
|
uniforms::color::Value( Color::red() )
|
|
},
|
|
paintAttributeData,
|
|
properties,
|
|
parameters.state.getZoom()
|
|
),
|
|
programInstance.computeAllAttributeBindings(
|
|
*parameters.staticData.tileVertexBuffer,
|
|
paintAttributeData,
|
|
properties
|
|
),
|
|
DebugProgram::TextureBindings{},
|
|
"image"
|
|
);
|
|
}
|
|
}
|
|
|
|
std::unordered_map<std::string, std::vector<Feature>>
|
|
RenderImageSource::queryRenderedFeatures(const ScreenLineString&,
|
|
const TransformState&,
|
|
const std::vector<const RenderLayer*>&,
|
|
const RenderedQueryOptions&,
|
|
const mat4&) const {
|
|
return std::unordered_map<std::string, std::vector<Feature>> {};
|
|
}
|
|
|
|
std::vector<Feature> RenderImageSource::querySourceFeatures(const SourceQueryOptions&) const {
|
|
return {};
|
|
}
|
|
|
|
void RenderImageSource::update(Immutable<style::Source::Impl> baseImpl_,
|
|
const std::vector<Immutable<LayerProperties>>&,
|
|
const bool needsRendering,
|
|
const bool,
|
|
const TileParameters& parameters) {
|
|
enabled = needsRendering;
|
|
if (!needsRendering) {
|
|
return;
|
|
}
|
|
|
|
auto transformState = parameters.transformState;
|
|
std::swap(baseImpl, baseImpl_);
|
|
|
|
auto coords = impl().getCoordinates();
|
|
std::shared_ptr<PremultipliedImage> image = impl().getImage();
|
|
|
|
if (!image || !image->valid()) {
|
|
enabled = false;
|
|
return;
|
|
}
|
|
|
|
// Compute the z0 tile coordinates for the given LatLngs
|
|
TileCoordinatePoint nePoint = { -INFINITY, -INFINITY };
|
|
TileCoordinatePoint swPoint = { INFINITY, INFINITY };
|
|
std::vector<TileCoordinatePoint> tileCoordinates;
|
|
for (LatLng latLng : coords) {
|
|
auto point = TileCoordinate::fromLatLng(0, latLng).p;
|
|
tileCoordinates.push_back(point);
|
|
swPoint.x = std::min(swPoint.x, point.x);
|
|
nePoint.x = std::max(nePoint.x, point.x);
|
|
swPoint.y = std::min(swPoint.y, point.y);
|
|
nePoint.y = std::max(nePoint.y, point.y);
|
|
}
|
|
|
|
// Calculate the optimum zoom level to determine the tile ids to use for transforms
|
|
auto dx = nePoint.x - swPoint.x;
|
|
auto dy = nePoint.y - swPoint.y;
|
|
auto dMax = std::max(dx, dy);
|
|
double zoom = std::max(0.0, std::floor(-util::log2(dMax)));
|
|
|
|
// Only enable if the long side of the image is > 2 pixels. Resulting in a
|
|
// display of at least 2 x 1 px image
|
|
// A tile coordinate unit represents the length of one tile (tileSize) at a given zoom.
|
|
// To convert a tile coordinate to pixels, multiply by tileSize.
|
|
// Here dMax is in z0 tile units, so we also scale by 2^z to match current zoom.
|
|
enabled = dMax * std::pow(2.0, transformState.getZoom()) * util::tileSize > 2.0;
|
|
if (!enabled) {
|
|
return;
|
|
}
|
|
|
|
auto imageBounds = LatLngBounds::hull(coords[0], coords[1]);
|
|
imageBounds.extend(coords[2]);
|
|
imageBounds.extend(coords[3]);
|
|
auto tileCover = util::tileCover(imageBounds, zoom);
|
|
tileIds.clear();
|
|
tileIds.push_back(tileCover[0]);
|
|
|
|
bool hasVisibleTile = false;
|
|
// Add additional wrapped tile ids if neccessary
|
|
auto idealTiles = util::tileCover(transformState, transformState.getZoom());
|
|
for (auto tile : idealTiles) {
|
|
if (tile.wrap != 0 && tileCover[0].canonical.isChildOf(tile.canonical)) {
|
|
tileIds.emplace_back(tile.wrap, tileCover[0].canonical);
|
|
hasVisibleTile = true;
|
|
}
|
|
else if (!hasVisibleTile) {
|
|
for (auto coveringTile: tileCover) {
|
|
if(coveringTile.canonical == tile.canonical ||
|
|
coveringTile.canonical.isChildOf(tile.canonical) ||
|
|
tile.canonical.isChildOf(coveringTile.canonical)) {
|
|
hasVisibleTile = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
enabled = hasVisibleTile;
|
|
if (!enabled) {
|
|
return;
|
|
}
|
|
|
|
// Calculate Geometry Coordinates based on tile cover at ideal zoom
|
|
GeometryCoordinates geomCoords;
|
|
for (auto tileCoords : tileCoordinates) {
|
|
auto gc = TileCoordinate::toGeometryCoordinate(tileIds[0], tileCoords);
|
|
geomCoords.push_back(gc);
|
|
}
|
|
if (!sharedData.bucket) {
|
|
sharedData.bucket = std::make_unique<RasterBucket>(image);
|
|
} else {
|
|
sharedData.bucket->clear();
|
|
if (image != sharedData.bucket->image) {
|
|
sharedData.bucket->setImage(image);
|
|
}
|
|
}
|
|
|
|
// Set Bucket Vertices, Indices, and segments
|
|
sharedData.bucket->vertices.emplace_back(
|
|
RasterProgram::layoutVertex({ geomCoords[0].x, geomCoords[0].y }, { 0, 0 }));
|
|
sharedData.bucket->vertices.emplace_back(
|
|
RasterProgram::layoutVertex({ geomCoords[1].x, geomCoords[1].y }, { util::EXTENT, 0 }));
|
|
sharedData.bucket->vertices.emplace_back(
|
|
RasterProgram::layoutVertex({ geomCoords[3].x, geomCoords[3].y }, { 0, util::EXTENT }));
|
|
sharedData.bucket->vertices.emplace_back(
|
|
RasterProgram::layoutVertex({ geomCoords[2].x, geomCoords[2].y }, { util::EXTENT, util::EXTENT }));
|
|
|
|
sharedData.bucket->indices.emplace_back(0, 1, 2);
|
|
sharedData.bucket->indices.emplace_back(1, 2, 3);
|
|
|
|
sharedData.bucket->segments.emplace_back(0, 0, 4, 6);
|
|
}
|
|
|
|
void RenderImageSource::dumpDebugLogs() const {
|
|
Log::Info(Event::General, "RenderImageSource::id: %s", impl().id.c_str());
|
|
Log::Info(Event::General, "RenderImageSource::loaded: %s", isLoaded() ? "yes" : "no");
|
|
}
|
|
|
|
} // namespace mbgl
|