544 lines
24 KiB
C++
544 lines
24 KiB
C++
#include <mbgl/renderer/layers/render_hillshade_layer.hpp>
|
|
#include <mbgl/renderer/buckets/hillshade_bucket.hpp>
|
|
#include <mbgl/renderer/render_tile.hpp>
|
|
#include <mbgl/renderer/sources/render_raster_dem_source.hpp>
|
|
#include <mbgl/renderer/paint_parameters.hpp>
|
|
#include <mbgl/renderer/render_static_data.hpp>
|
|
#include <mbgl/programs/programs.hpp>
|
|
#include <mbgl/tile/tile.hpp>
|
|
#include <mbgl/style/layers/hillshade_layer_impl.hpp>
|
|
#include <mbgl/gfx/cull_face_mode.hpp>
|
|
#include <mbgl/gfx/offscreen_texture.hpp>
|
|
#include <mbgl/gfx/render_pass.hpp>
|
|
#include <mbgl/math/angles.hpp>
|
|
#include <mbgl/util/geo.hpp>
|
|
|
|
#if MLN_DRAWABLE_RENDERER
|
|
#include <mbgl/renderer/layers/hillshade_layer_tweaker.hpp>
|
|
#include <mbgl/renderer/layers/hillshade_prepare_layer_tweaker.hpp>
|
|
#include <mbgl/renderer/layer_group.hpp>
|
|
#include <mbgl/renderer/render_target.hpp>
|
|
#include <mbgl/renderer/update_parameters.hpp>
|
|
#include <mbgl/shaders/shader_program_base.hpp>
|
|
#include <mbgl/gfx/drawable_builder.hpp>
|
|
#include <mbgl/gfx/drawable_impl.hpp>
|
|
#include <mbgl/gfx/hillshade_prepare_drawable_data.hpp>
|
|
#include <mbgl/gfx/shader_group.hpp>
|
|
#include <mbgl/gfx/shader_registry.hpp>
|
|
#endif
|
|
|
|
namespace mbgl {
|
|
|
|
using namespace style;
|
|
using namespace shaders;
|
|
|
|
namespace {
|
|
|
|
inline const HillshadeLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& impl) {
|
|
assert(impl->getTypeInfo() == HillshadeLayer::Impl::staticTypeInfo());
|
|
return static_cast<const HillshadeLayer::Impl&>(*impl);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
RenderHillshadeLayer::RenderHillshadeLayer(Immutable<style::HillshadeLayer::Impl> _impl)
|
|
: RenderLayer(makeMutable<HillshadeLayerProperties>(std::move(_impl))),
|
|
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {
|
|
styleDependencies = unevaluated.getDependencies();
|
|
}
|
|
|
|
RenderHillshadeLayer::~RenderHillshadeLayer() = default;
|
|
|
|
std::array<float, 2> RenderHillshadeLayer::getLatRange(const UnwrappedTileID& id) {
|
|
const LatLng latlng0 = LatLng(id);
|
|
const LatLng latlng1 = LatLng(UnwrappedTileID(id.canonical.z, id.canonical.x, id.canonical.y + 1));
|
|
return {{static_cast<float>(latlng0.latitude()), static_cast<float>(latlng1.latitude())}};
|
|
}
|
|
|
|
std::array<float, 2> RenderHillshadeLayer::getLight(const PaintParameters& parameters) {
|
|
const auto& evaluated = static_cast<const HillshadeLayerProperties&>(*evaluatedProperties).evaluated;
|
|
float azimuthal = util::deg2radf(evaluated.get<HillshadeIlluminationDirection>());
|
|
if (evaluated.get<HillshadeIlluminationAnchor>() == HillshadeIlluminationAnchorType::Viewport)
|
|
azimuthal = azimuthal - static_cast<float>(parameters.state.getBearing());
|
|
return {{evaluated.get<HillshadeExaggeration>(), azimuthal}};
|
|
}
|
|
|
|
void RenderHillshadeLayer::transition(const TransitionParameters& parameters) {
|
|
unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated));
|
|
}
|
|
|
|
#if MLN_DRAWABLE_RENDERER
|
|
void RenderHillshadeLayer::layerChanged(const TransitionParameters& parameters,
|
|
const Immutable<style::Layer::Impl>& impl,
|
|
UniqueChangeRequestVec& changes) {
|
|
RenderLayer::layerChanged(parameters, impl, changes);
|
|
prepareLayerTweaker.reset();
|
|
}
|
|
#endif
|
|
|
|
void RenderHillshadeLayer::evaluate(const PropertyEvaluationParameters& parameters) {
|
|
const auto previousProperties = staticImmutableCast<HillshadeLayerProperties>(evaluatedProperties);
|
|
auto properties = makeMutable<HillshadeLayerProperties>(
|
|
staticImmutableCast<HillshadeLayer::Impl>(baseImpl),
|
|
unevaluated.evaluate(parameters, previousProperties->evaluated));
|
|
|
|
passes = (properties->evaluated.get<style::HillshadeExaggeration>() > 0)
|
|
? (RenderPass::Translucent | RenderPass::Pass3D)
|
|
: RenderPass::None;
|
|
properties->renderPasses = mbgl::underlying_type(passes);
|
|
evaluatedProperties = std::move(properties);
|
|
#if MLN_DRAWABLE_RENDERER
|
|
if (layerTweaker) {
|
|
layerTweaker->updateProperties(evaluatedProperties);
|
|
}
|
|
if (prepareLayerTweaker) {
|
|
prepareLayerTweaker->updateProperties(evaluatedProperties);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool RenderHillshadeLayer::hasTransition() const {
|
|
return unevaluated.hasTransition();
|
|
}
|
|
|
|
bool RenderHillshadeLayer::hasCrossfade() const {
|
|
return false;
|
|
}
|
|
|
|
void RenderHillshadeLayer::prepare(const LayerPrepareParameters& params) {
|
|
renderTiles = params.source->getRenderTiles();
|
|
maxzoom = params.source->getMaxZoom();
|
|
|
|
#if MLN_DRAWABLE_RENDERER
|
|
updateRenderTileIDs();
|
|
#endif // MLN_DRAWABLE_RENDERER
|
|
}
|
|
|
|
#if MLN_LEGACY_RENDERER
|
|
void RenderHillshadeLayer::render(PaintParameters& parameters) {
|
|
assert(renderTiles);
|
|
if (parameters.pass != RenderPass::Translucent && parameters.pass != RenderPass::Pass3D) return;
|
|
|
|
if (!parameters.shaders.getLegacyGroup().populate(hillshadeProgram)) return;
|
|
if (!parameters.shaders.getLegacyGroup().populate(hillshadePrepareProgram)) return;
|
|
|
|
const auto& evaluated = static_cast<const HillshadeLayerProperties&>(*evaluatedProperties).evaluated;
|
|
auto draw = [&](const mat4& matrix,
|
|
const auto& vertexBuffer,
|
|
const auto& indexBuffer,
|
|
const auto& segments,
|
|
const UnwrappedTileID& id,
|
|
const auto& textureBindings) {
|
|
const HillshadeProgram::Binders paintAttributeData{evaluated, 0};
|
|
|
|
const auto allUniformValues = HillshadeProgram::computeAllUniformValues(
|
|
HillshadeProgram::LayoutUniformValues{
|
|
uniforms::matrix::Value(matrix),
|
|
uniforms::highlight::Value(evaluated.get<HillshadeHighlightColor>()),
|
|
uniforms::shadow::Value(evaluated.get<HillshadeShadowColor>()),
|
|
uniforms::accent::Value(evaluated.get<HillshadeAccentColor>()),
|
|
uniforms::light::Value(getLight(parameters)),
|
|
uniforms::latrange::Value(getLatRange(id)),
|
|
},
|
|
paintAttributeData,
|
|
evaluated,
|
|
static_cast<float>(parameters.state.getZoom()));
|
|
const auto allAttributeBindings = HillshadeProgram::computeAllAttributeBindings(
|
|
vertexBuffer, paintAttributeData, evaluated);
|
|
|
|
checkRenderability(parameters, HillshadeProgram::activeBindingCount(allAttributeBindings));
|
|
|
|
hillshadeProgram->draw(parameters.context,
|
|
*parameters.renderPass,
|
|
gfx::Triangles(),
|
|
parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly),
|
|
gfx::StencilMode::disabled(),
|
|
parameters.colorModeForRenderPass(),
|
|
gfx::CullFaceMode::disabled(),
|
|
indexBuffer,
|
|
segments,
|
|
allUniformValues,
|
|
allAttributeBindings,
|
|
textureBindings,
|
|
getID());
|
|
};
|
|
|
|
mat4 mat;
|
|
matrix::ortho(mat, 0, util::EXTENT, -util::EXTENT, 0, 0, 1);
|
|
matrix::translate(mat, mat, 0, -util::EXTENT, 0);
|
|
|
|
for (const RenderTile& tile : *renderTiles) {
|
|
auto* bucket_ = tile.getBucket(*baseImpl);
|
|
if (!bucket_) {
|
|
continue;
|
|
}
|
|
auto& bucket = static_cast<HillshadeBucket&>(*bucket_);
|
|
|
|
if (!bucket.hasData()) {
|
|
continue;
|
|
}
|
|
|
|
if (!bucket.isPrepared() && parameters.pass == RenderPass::Pass3D) {
|
|
assert(bucket.dem);
|
|
const uint16_t stride = bucket.getDEMData().stride;
|
|
const uint16_t tilesize = bucket.getDEMData().dim;
|
|
auto view = parameters.context.createOffscreenTexture({tilesize, tilesize},
|
|
gfx::TextureChannelDataType::UnsignedByte);
|
|
|
|
auto renderPass = parameters.encoder->createRenderPass("hillshade prepare",
|
|
{*view, Color{0.0f, 0.0f, 0.0f, 0.0f}, {}, {}});
|
|
|
|
const Properties<>::PossiblyEvaluated properties;
|
|
const HillshadePrepareProgram::Binders paintAttributeData{properties, 0};
|
|
|
|
const auto allUniformValues = HillshadePrepareProgram::computeAllUniformValues(
|
|
HillshadePrepareProgram::LayoutUniformValues{
|
|
uniforms::matrix::Value(mat),
|
|
uniforms::dimension::Value({{stride, stride}}),
|
|
uniforms::zoom::Value(static_cast<float>(tile.id.canonical.z)),
|
|
uniforms::maxzoom::Value(static_cast<float>(maxzoom)),
|
|
uniforms::unpack::Value(bucket.getDEMData().getUnpackVector()),
|
|
},
|
|
paintAttributeData,
|
|
properties,
|
|
static_cast<float>(parameters.state.getZoom()));
|
|
const auto allAttributeBindings = HillshadePrepareProgram::computeAllAttributeBindings(
|
|
*parameters.staticData.rasterVertexBuffer, paintAttributeData, properties);
|
|
|
|
checkRenderability(parameters, HillshadePrepareProgram::activeBindingCount(allAttributeBindings));
|
|
|
|
// Copy over the segments so that we can create our own DrawScopes
|
|
// that get destroyed after this draw call.
|
|
auto segments = RenderStaticData::rasterSegments();
|
|
hillshadePrepareProgram->draw(parameters.context,
|
|
*renderPass,
|
|
gfx::Triangles(),
|
|
parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly),
|
|
gfx::StencilMode::disabled(),
|
|
parameters.colorModeForRenderPass(),
|
|
gfx::CullFaceMode::disabled(),
|
|
*parameters.staticData.quadTriangleIndexBuffer,
|
|
segments,
|
|
allUniformValues,
|
|
allAttributeBindings,
|
|
HillshadePrepareProgram::TextureBindings{
|
|
textures::image::Value{bucket.dem->getResource()},
|
|
},
|
|
"prepare");
|
|
bucket.texture = std::move(view->getTexture());
|
|
bucket.setPrepared(true);
|
|
} else if (parameters.pass == RenderPass::Translucent) {
|
|
assert(bucket.texture);
|
|
|
|
if (bucket.vertexBuffer && bucket.indexBuffer) {
|
|
// Draw only the parts of the tile that aren't drawn by another tile in the layer.
|
|
draw(parameters.matrixForTile(tile.id, true),
|
|
*bucket.vertexBuffer,
|
|
*bucket.indexBuffer,
|
|
bucket.segments,
|
|
tile.id,
|
|
HillshadeProgram::TextureBindings{
|
|
textures::image::Value{bucket.texture->getResource(), gfx::TextureFilterType::Linear},
|
|
});
|
|
} else {
|
|
// Draw the full tile.
|
|
if (bucket.segments.empty()) {
|
|
// Copy over the segments so that we can create our own DrawScopes.
|
|
bucket.segments = RenderStaticData::rasterSegments();
|
|
}
|
|
draw(parameters.matrixForTile(tile.id, true),
|
|
*parameters.staticData.rasterVertexBuffer,
|
|
*parameters.staticData.quadTriangleIndexBuffer,
|
|
bucket.segments,
|
|
tile.id,
|
|
HillshadeProgram::TextureBindings{
|
|
textures::image::Value{bucket.texture->getResource(), gfx::TextureFilterType::Linear},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // MLN_LEGACY_RENDERER
|
|
|
|
#if MLN_DRAWABLE_RENDERER
|
|
namespace {
|
|
void activateRenderTarget(const RenderTargetPtr& renderTarget_, bool activate, UniqueChangeRequestVec& changes) {
|
|
if (renderTarget_) {
|
|
if (activate) {
|
|
// The RenderTree has determined this render target should be included in the renderable set for a frame
|
|
changes.emplace_back(std::make_unique<AddRenderTargetRequest>(renderTarget_));
|
|
} else {
|
|
// The RenderTree is informing us we should not render anything
|
|
changes.emplace_back(std::make_unique<RemoveRenderTargetRequest>(renderTarget_));
|
|
}
|
|
}
|
|
}
|
|
} // namespace
|
|
|
|
void RenderHillshadeLayer::markLayerRenderable(bool willRender, UniqueChangeRequestVec& changes) {
|
|
RenderLayer::markLayerRenderable(willRender, changes);
|
|
removeRenderTargets(changes);
|
|
}
|
|
|
|
void RenderHillshadeLayer::layerRemoved(UniqueChangeRequestVec& changes) {
|
|
RenderLayer::layerRemoved(changes);
|
|
removeRenderTargets(changes);
|
|
}
|
|
|
|
void RenderHillshadeLayer::addRenderTarget(const RenderTargetPtr& renderTarget, UniqueChangeRequestVec& changes) {
|
|
activateRenderTarget(renderTarget, true, changes);
|
|
activatedRenderTargets.emplace_back(renderTarget);
|
|
}
|
|
|
|
void RenderHillshadeLayer::removeRenderTargets(UniqueChangeRequestVec& changes) {
|
|
for (const auto& renderTarget : activatedRenderTargets) {
|
|
activateRenderTarget(renderTarget, false, changes);
|
|
}
|
|
activatedRenderTargets.clear();
|
|
}
|
|
|
|
static const std::string HillshadePrepareShaderGroupName = "HillshadePrepareShader";
|
|
static const std::string HillshadeShaderGroupName = "HillshadeShader";
|
|
|
|
void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders,
|
|
gfx::Context& context,
|
|
[[maybe_unused]] const TransformState& state,
|
|
const std::shared_ptr<UpdateParameters>&,
|
|
[[maybe_unused]] const RenderTree& renderTree,
|
|
UniqueChangeRequestVec& changes) {
|
|
if (!renderTiles || renderTiles->empty()) {
|
|
removeAllDrawables();
|
|
return;
|
|
}
|
|
|
|
// Set up a layer group
|
|
if (!layerGroup) {
|
|
if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) {
|
|
setLayerGroup(std::move(layerGroup_), changes);
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
auto* tileLayerGroup = static_cast<TileLayerGroup*>(layerGroup.get());
|
|
|
|
if (!layerTweaker) {
|
|
layerTweaker = std::make_shared<HillshadeLayerTweaker>(getID(), evaluatedProperties);
|
|
layerGroup->addLayerTweaker(layerTweaker);
|
|
}
|
|
|
|
if (!hillshadePrepareShader) {
|
|
hillshadePrepareShader = context.getGenericShader(shaders, HillshadePrepareShaderGroupName);
|
|
}
|
|
if (!hillshadeShader) {
|
|
hillshadeShader = context.getGenericShader(shaders, HillshadeShaderGroupName);
|
|
}
|
|
if (!hillshadePrepareShader || !hillshadeShader) {
|
|
removeAllDrawables();
|
|
return;
|
|
}
|
|
|
|
auto renderPass = RenderPass::Translucent;
|
|
if (!(mbgl::underlying_type(renderPass) & evaluatedProperties->renderPasses)) {
|
|
return;
|
|
}
|
|
|
|
stats.drawablesRemoved += tileLayerGroup->removeDrawablesIf(
|
|
[&](gfx::Drawable& drawable) { return drawable.getTileID() && !hasRenderTile(*drawable.getTileID()); });
|
|
|
|
if (!staticDataSharedVertices) {
|
|
staticDataSharedVertices = std::make_shared<HillshadeVertexVector>(RenderStaticData::rasterVertices());
|
|
}
|
|
const auto staticDataIndices = RenderStaticData::quadTriangleIndices();
|
|
const auto staticDataSegments = RenderStaticData::rasterSegments();
|
|
|
|
std::unique_ptr<gfx::DrawableBuilder> hillshadeBuilder;
|
|
std::unique_ptr<gfx::DrawableBuilder> hillshadePrepareBuilder;
|
|
|
|
gfx::VertexAttributeArrayPtr hillshadePrepareVertexAttrs;
|
|
const auto getPrepareVertexAttributes = [&] {
|
|
if (!hillshadePrepareVertexAttrs) {
|
|
hillshadePrepareVertexAttrs = context.createVertexAttributeArray();
|
|
|
|
if (const auto& attr = hillshadePrepareVertexAttrs->set(idHillshadePosVertexAttribute)) {
|
|
attr->setSharedRawData(staticDataSharedVertices,
|
|
offsetof(HillshadeLayoutVertex, a1),
|
|
0,
|
|
sizeof(HillshadeLayoutVertex),
|
|
gfx::AttributeDataType::Short2);
|
|
}
|
|
if (const auto& attr = hillshadePrepareVertexAttrs->set(idHillshadeTexturePosVertexAttribute)) {
|
|
attr->setSharedRawData(staticDataSharedVertices,
|
|
offsetof(HillshadeLayoutVertex, a2),
|
|
0,
|
|
sizeof(HillshadeLayoutVertex),
|
|
gfx::AttributeDataType::Short2);
|
|
}
|
|
}
|
|
return hillshadePrepareVertexAttrs;
|
|
};
|
|
|
|
for (const RenderTile& tile : *renderTiles) {
|
|
const auto& tileID = tile.getOverscaledTileID();
|
|
|
|
auto* bucket_ = tile.getBucket(*baseImpl);
|
|
if (!bucket_ || !bucket_->hasData()) {
|
|
removeTile(renderPass, tileID);
|
|
continue;
|
|
}
|
|
|
|
auto& bucket = static_cast<HillshadeBucket&>(*bucket_);
|
|
|
|
const auto prevBucketID = getRenderTileBucketID(tileID);
|
|
if (prevBucketID != util::SimpleIdentity::Empty && prevBucketID != bucket.getID()) {
|
|
// This tile was previously set up from a different bucket, drop and re-create any drawables for it.
|
|
removeTile(renderPass, tileID);
|
|
}
|
|
setRenderTileBucketID(tileID, bucket.getID());
|
|
|
|
if (!bucket.renderTargetPrepared) {
|
|
// Set up tile render target
|
|
const uint16_t tilesize = bucket.getDEMData().dim;
|
|
auto renderTarget = context.createRenderTarget({tilesize, tilesize},
|
|
gfx::TextureChannelDataType::UnsignedByte);
|
|
if (!renderTarget) {
|
|
continue;
|
|
}
|
|
bucket.renderTarget = renderTarget;
|
|
bucket.renderTargetPrepared = true;
|
|
addRenderTarget(renderTarget, changes);
|
|
|
|
auto singleTileLayerGroup = context.createTileLayerGroup(0, /*initialCapacity=*/1, getID());
|
|
if (!singleTileLayerGroup) {
|
|
return;
|
|
}
|
|
renderTarget->addLayerGroup(singleTileLayerGroup, /*replace=*/true);
|
|
|
|
if (!prepareLayerTweaker) {
|
|
prepareLayerTweaker = std::make_shared<HillshadePrepareLayerTweaker>(getID(), evaluatedProperties);
|
|
}
|
|
singleTileLayerGroup->addLayerTweaker(prepareLayerTweaker);
|
|
|
|
hillshadePrepareBuilder = context.createDrawableBuilder("hillshadePrepare");
|
|
hillshadePrepareBuilder->setShader(hillshadePrepareShader);
|
|
hillshadePrepareBuilder->setDepthType(gfx::DepthMaskType::ReadOnly);
|
|
hillshadePrepareBuilder->setColorMode(gfx::ColorMode::unblended());
|
|
hillshadePrepareBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
|
|
hillshadePrepareBuilder->setRenderPass(renderPass);
|
|
hillshadePrepareBuilder->setVertexAttributes(getPrepareVertexAttributes());
|
|
hillshadePrepareBuilder->setRawVertices(
|
|
{}, staticDataSharedVertices->elements(), gfx::AttributeDataType::Short2);
|
|
hillshadePrepareBuilder->setSegments(
|
|
gfx::Triangles(), staticDataIndices.vector(), staticDataSegments.data(), staticDataSegments.size());
|
|
|
|
std::shared_ptr<gfx::Texture2D> texture = context.createTexture2D();
|
|
texture->setImage(bucket.getDEMData().getImagePtr());
|
|
texture->setSamplerConfiguration(
|
|
{gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp});
|
|
hillshadePrepareBuilder->setTexture(texture, idHillshadeImageTexture);
|
|
|
|
hillshadePrepareBuilder->flush(context);
|
|
|
|
for (auto& drawable : hillshadePrepareBuilder->clearDrawables()) {
|
|
drawable->setTileID(tileID);
|
|
drawable->setLayerTweaker(prepareLayerTweaker);
|
|
drawable->setData(std::make_unique<gfx::HillshadePrepareDrawableData>(
|
|
bucket.getDEMData().stride, bucket.getDEMData().encoding, maxzoom));
|
|
singleTileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
|
|
++stats.drawablesAdded;
|
|
}
|
|
}
|
|
|
|
// Set up tile drawable
|
|
auto vertices = staticDataSharedVertices;
|
|
auto* indices = &staticDataIndices;
|
|
auto* segments = &staticDataSegments;
|
|
|
|
if (!bucket.vertices.empty() && !bucket.indices.empty() && !bucket.segments.empty()) {
|
|
vertices = bucket.sharedVertices;
|
|
indices = &bucket.indices;
|
|
segments = &bucket.segments;
|
|
}
|
|
|
|
hillshadeBuilder = context.createDrawableBuilder("hillshade");
|
|
|
|
gfx::VertexAttributeArrayPtr hillshadeVertexAttrs;
|
|
auto buildVertexAttributes = [&] {
|
|
if (!hillshadeVertexAttrs) {
|
|
hillshadeVertexAttrs = context.createVertexAttributeArray();
|
|
|
|
if (const auto& attr = hillshadeVertexAttrs->set(idHillshadePosVertexAttribute)) {
|
|
attr->setSharedRawData(vertices,
|
|
offsetof(HillshadeLayoutVertex, a1),
|
|
0,
|
|
sizeof(HillshadeLayoutVertex),
|
|
gfx::AttributeDataType::Short2);
|
|
}
|
|
if (const auto& attr = hillshadeVertexAttrs->set(idHillshadeTexturePosVertexAttribute)) {
|
|
attr->setSharedRawData(vertices,
|
|
offsetof(HillshadeLayoutVertex, a2),
|
|
0,
|
|
sizeof(HillshadeLayoutVertex),
|
|
gfx::AttributeDataType::Short2);
|
|
}
|
|
}
|
|
return hillshadeVertexAttrs;
|
|
};
|
|
|
|
const auto updateExisting = [&](gfx::Drawable& drawable) {
|
|
// Only current drawables are updated, ones produced for
|
|
// a previous style retain the attribute values for that style.
|
|
if (drawable.getLayerTweaker() != layerTweaker) {
|
|
return false;
|
|
}
|
|
|
|
drawable.setVertexAttributes(buildVertexAttributes());
|
|
drawable.setVertices({}, vertices->elements(), gfx::AttributeDataType::Short2);
|
|
|
|
// Rebuild segments, since they're not shared.
|
|
std::vector<std::unique_ptr<gfx::Drawable::DrawSegment>> drawSegments;
|
|
drawSegments.reserve(segments->size());
|
|
for (const auto& seg : *segments) {
|
|
auto segCopy = SegmentBase{
|
|
// no copy constructor
|
|
seg.vertexOffset,
|
|
seg.indexOffset,
|
|
seg.vertexLength,
|
|
seg.indexLength,
|
|
seg.sortKey,
|
|
};
|
|
drawSegments.emplace_back(hillshadeBuilder->createSegment(gfx::Triangles(), std::move(segCopy)));
|
|
}
|
|
drawable.setIndexData(indices->vector(), std::move(drawSegments));
|
|
drawable.setTexture(bucket.renderTarget->getTexture(), idHillshadeImageTexture);
|
|
return true;
|
|
};
|
|
if (updateTile(renderPass, tileID, std::move(updateExisting))) {
|
|
continue;
|
|
}
|
|
|
|
hillshadeBuilder->setShader(hillshadeShader);
|
|
hillshadeBuilder->setDepthType(gfx::DepthMaskType::ReadOnly);
|
|
hillshadeBuilder->setColorMode(gfx::ColorMode::alphaBlended());
|
|
hillshadeBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
|
|
hillshadeBuilder->setRenderPass(renderPass);
|
|
hillshadeBuilder->setVertexAttributes(buildVertexAttributes());
|
|
hillshadeBuilder->setRawVertices({}, vertices->elements(), gfx::AttributeDataType::Short2);
|
|
hillshadeBuilder->setSegments(gfx::Triangles(), indices->vector(), segments->data(), segments->size());
|
|
hillshadeBuilder->setTexture(bucket.renderTarget->getTexture(), idHillshadeImageTexture);
|
|
|
|
hillshadeBuilder->flush(context);
|
|
|
|
for (auto& drawable : hillshadeBuilder->clearDrawables()) {
|
|
drawable->setTileID(tileID);
|
|
drawable->setLayerTweaker(layerTweaker);
|
|
|
|
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
|
|
++stats.drawablesAdded;
|
|
}
|
|
}
|
|
}
|
|
#endif // MLN_DRAWABLE_RENDERER
|
|
|
|
} // namespace mbgl
|