Files
MapLibreParticleLab/src/mbgl/renderer/layers/render_heatmap_layer.cpp
Mikhail Pozdnyakov e800f37547 [core] Layer manager is responsible for buckets and layouts creation
This is a step to stop using of render layers in tile worker thread.
2019-02-25 13:47:56 +02:00

224 lines
8.1 KiB
C++

#include <mbgl/renderer/layers/render_heatmap_layer.hpp>
#include <mbgl/renderer/buckets/heatmap_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/heatmap_program.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/style/layers/heatmap_layer.hpp>
#include <mbgl/style/layers/heatmap_layer_impl.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/intersection_tests.hpp>
namespace mbgl {
using namespace style;
RenderHeatmapLayer::RenderHeatmapLayer(Immutable<style::HeatmapLayer::Impl> _impl)
: RenderLayer(std::move(_impl)),
unevaluated(impl().paint.untransitioned()), colorRamp({256, 1}) {
}
const style::HeatmapLayer::Impl& RenderHeatmapLayer::impl() const {
return static_cast<const style::HeatmapLayer::Impl&>(*baseImpl);
}
void RenderHeatmapLayer::transition(const TransitionParameters& parameters) {
unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
}
void RenderHeatmapLayer::evaluate(const PropertyEvaluationParameters& parameters) {
evaluated = unevaluated.evaluate(parameters);
passes = (evaluated.get<style::HeatmapOpacity>() > 0)
? (RenderPass::Translucent | RenderPass::Pass3D)
: RenderPass::None;
}
bool RenderHeatmapLayer::hasTransition() const {
return unevaluated.hasTransition();
}
bool RenderHeatmapLayer::hasCrossfade() const {
return false;
}
void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) {
if (parameters.pass == RenderPass::Opaque) {
return;
}
if (parameters.pass == RenderPass::Pass3D) {
const auto& viewportSize = parameters.staticData.backendSize;
const auto size = Size{viewportSize.width / 4, viewportSize.height / 4};
if (!renderTexture || renderTexture->getSize() != size) {
if (parameters.context.supportsHalfFloatTextures) {
renderTexture = OffscreenTexture(parameters.context, size, gl::TextureType::HalfFloat);
try {
renderTexture->bind();
} catch (const std::runtime_error& ex) {
// can't render to a half-float texture; falling back to unsigned byte one
renderTexture = nullopt;
parameters.context.supportsHalfFloatTextures = false;
}
}
if (!parameters.context.supportsHalfFloatTextures || !renderTexture) {
renderTexture = OffscreenTexture(parameters.context, size, gl::TextureType::UnsignedByte);
renderTexture->bind();
}
} else {
renderTexture->bind();
}
if (!colorRampTexture) {
colorRampTexture = parameters.context.createTexture(colorRamp, 1, gl::TextureType::UnsignedByte);
}
parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 1.0f }, {}, {});
for (const RenderTile& tile : renderTiles) {
auto bucket_ = tile.tile.getBucket<HeatmapBucket>(*baseImpl);
if (!bucket_) {
continue;
}
HeatmapBucket& bucket = *bucket_;
const auto extrudeScale = tile.id.pixelsToTileUnits(1, parameters.state.getZoom());
const auto stencilMode = parameters.mapMode != MapMode::Continuous
? parameters.stencilModeForClipping(tile.clip)
: gl::StencilMode::disabled();
const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID());
auto& programInstance = parameters.programs.getHeatmapLayerPrograms().heatmap.get(evaluated);
const auto allUniformValues = programInstance.computeAllUniformValues(
HeatmapProgram::UniformValues {
uniforms::u_intensity::Value( evaluated.get<style::HeatmapIntensity>() ),
uniforms::u_matrix::Value( tile.matrix ),
uniforms::heatmap::u_extrude_scale::Value( extrudeScale )
},
paintPropertyBinders,
evaluated,
parameters.state.getZoom()
);
const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
*bucket.vertexBuffer,
paintPropertyBinders,
evaluated
);
checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
programInstance.draw(
parameters.context,
gl::Triangles(),
parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
stencilMode,
gl::ColorMode::additive(),
gl::CullFaceMode::disabled(),
*bucket.indexBuffer,
bucket.segments,
allUniformValues,
allAttributeBindings,
getID()
);
}
} else if (parameters.pass == RenderPass::Translucent) {
parameters.context.bindTexture(renderTexture->getTexture(), 0, gl::TextureFilter::Linear);
parameters.context.bindTexture(*colorRampTexture, 1, gl::TextureFilter::Linear);
const auto& size = parameters.staticData.backendSize;
mat4 viewportMat;
matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1);
const Properties<>::PossiblyEvaluated properties;
const HeatmapTextureProgram::PaintPropertyBinders paintAttributeData{ properties, 0 };
auto& programInstance = parameters.programs.getHeatmapLayerPrograms().heatmapTexture;
const auto allUniformValues = programInstance.computeAllUniformValues(
HeatmapTextureProgram::UniformValues{
uniforms::u_matrix::Value( viewportMat ), uniforms::u_world::Value( size ),
uniforms::u_image::Value( 0 ),
uniforms::u_color_ramp::Value( 1 ),
uniforms::u_opacity::Value( evaluated.get<HeatmapOpacity>() )
},
paintAttributeData,
properties,
parameters.state.getZoom()
);
const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
parameters.staticData.extrusionTextureVertexBuffer,
paintAttributeData,
properties
);
checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
programInstance.draw(
parameters.context,
gl::Triangles(),
gl::DepthMode::disabled(),
gl::StencilMode::disabled(),
parameters.colorModeForRenderPass(),
gl::CullFaceMode::disabled(),
parameters.staticData.quadTriangleIndexBuffer,
parameters.staticData.extrusionTextureSegments,
allUniformValues,
allAttributeBindings,
getID()
);
}
}
void RenderHeatmapLayer::update() {
updateColorRamp();
}
void RenderHeatmapLayer::updateColorRamp() {
auto colorValue = unevaluated.get<HeatmapColor>().getValue();
if (colorValue.isUndefined()) {
colorValue = HeatmapLayer::getDefaultHeatmapColor();
}
const auto length = colorRamp.bytes();
for (uint32_t i = 0; i < length; i += 4) {
const auto color = colorValue.evaluate(static_cast<double>(i) / length);
colorRamp.data[i + 0] = std::floor(color.r * 255);
colorRamp.data[i + 1] = std::floor(color.g * 255);
colorRamp.data[i + 2] = std::floor(color.b * 255);
colorRamp.data[i + 3] = std::floor(color.a * 255);
}
if (colorRampTexture) {
colorRampTexture = nullopt;
}
}
bool RenderHeatmapLayer::queryIntersectsFeature(
const GeometryCoordinates& queryGeometry,
const GeometryTileFeature& feature,
const float zoom,
const TransformState&,
const float pixelsToTileUnits,
const mat4&) const {
(void) queryGeometry;
(void) feature;
(void) zoom;
(void) pixelsToTileUnits;
return false;
}
} // namespace mbgl