Files
MapLibreParticleLab/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
2019-03-12 11:03:54 +01:00

234 lines
9.7 KiB
C++

#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
#include <mbgl/renderer/buckets/fill_extrusion_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/renderer/renderer_backend.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/fill_extrusion_program.hpp>
#include <mbgl/tile/tile.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>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/gl/context.hpp>
namespace mbgl {
using namespace style;
RenderFillExtrusionLayer::RenderFillExtrusionLayer(Immutable<style::FillExtrusionLayer::Impl> _impl)
: RenderLayer(std::move(_impl)),
unevaluated(impl().paint.untransitioned()) {
}
const style::FillExtrusionLayer::Impl& RenderFillExtrusionLayer::impl() const {
return static_cast<const style::FillExtrusionLayer::Impl&>(*baseImpl);
}
void RenderFillExtrusionLayer::transition(const TransitionParameters& parameters) {
unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
}
void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& parameters) {
evaluated = unevaluated.evaluate(parameters);
crossfade = parameters.getCrossfadeParameters();
passes = (evaluated.get<style::FillExtrusionOpacity>() > 0)
? (RenderPass::Translucent | RenderPass::Pass3D)
: RenderPass::None;
}
bool RenderFillExtrusionLayer::hasTransition() const {
return unevaluated.hasTransition();
}
bool RenderFillExtrusionLayer::hasCrossfade() const {
return crossfade.t != 1;
}
void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*) {
if (parameters.pass == RenderPass::Opaque) {
return;
}
if (parameters.pass == RenderPass::Pass3D) {
const auto& size = parameters.staticData.backendSize;
if (!renderTexture || renderTexture->getSize() != size) {
renderTexture = OffscreenTexture(parameters.context, size, *parameters.staticData.depthRenderbuffer);
}
renderTexture->bind();
optional<float> depthClearValue = {};
if (parameters.staticData.depthRenderbuffer->needsClearing()) depthClearValue = 1.0;
// Flag the depth buffer as no longer needing to be cleared for the remainder of this pass.
parameters.staticData.depthRenderbuffer->shouldClear(false);
parameters.context.setStencilMode(gfx::StencilMode::disabled());
parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, depthClearValue, {});
auto draw = [&](auto& programInstance, const auto& tileBucket, auto&& uniformValues,
const optional<ImagePosition>& patternPositionA,
const optional<ImagePosition>& patternPositionB, auto&& textureBindings) {
const auto& paintPropertyBinders = tileBucket.paintPropertyBinders.at(getID());
paintPropertyBinders.setPatternParameters(patternPositionA, patternPositionB, crossfade);
const auto allUniformValues = programInstance.computeAllUniformValues(
std::move(uniformValues),
paintPropertyBinders,
evaluated,
parameters.state.getZoom()
);
const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
*tileBucket.vertexBuffer,
paintPropertyBinders,
evaluated
);
checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
programInstance.draw(
parameters.context,
gfx::Triangles(),
parameters.depthModeFor3D(gfx::DepthMaskType::ReadWrite),
gfx::StencilMode::disabled(),
parameters.colorModeForRenderPass(),
gfx::CullFaceMode::backCCW(),
*tileBucket.indexBuffer,
tileBucket.triangleSegments,
allUniformValues,
allAttributeBindings,
std::move(textureBindings),
getID());
};
if (unevaluated.get<FillExtrusionPattern>().isUndefined()) {
for (const RenderTile& tile : renderTiles) {
auto bucket_ = tile.tile.getBucket<FillExtrusionBucket>(*baseImpl);
if (!bucket_) {
continue;
}
FillExtrusionBucket& bucket = *bucket_;
draw(
parameters.programs.getFillExtrusionLayerPrograms().fillExtrusion.get(evaluated),
bucket,
FillExtrusionProgram::uniformValues(
tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
evaluated.get<FillExtrusionTranslateAnchor>(),
parameters.state),
parameters.state,
parameters.evaluatedLight
),
{},
{},
FillExtrusionProgram::TextureBindings{}
);
}
} else {
for (const RenderTile& tile : renderTiles) {
auto bucket_ = tile.tile.getBucket<FillExtrusionBucket>(*baseImpl);
if (!bucket_) {
continue;
}
const auto fillPatternValue = evaluated.get<FillExtrusionPattern>().constantOr(mbgl::Faded<std::basic_string<char> >{"", ""});
assert(dynamic_cast<GeometryTile*>(&tile.tile));
GeometryTile& geometryTile = static_cast<GeometryTile&>(tile.tile);
optional<ImagePosition> patternPosA = geometryTile.getPattern(fillPatternValue.from);
optional<ImagePosition> patternPosB = geometryTile.getPattern(fillPatternValue.to);
parameters.context.bindTexture(*geometryTile.iconAtlasTexture, 0, gfx::TextureFilterType::Linear);
FillExtrusionBucket& bucket = *bucket_;
draw(
parameters.programs.getFillExtrusionLayerPrograms().fillExtrusionPattern.get(evaluated),
bucket,
FillExtrusionPatternProgram::uniformValues(
tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
evaluated.get<FillExtrusionTranslateAnchor>(),
parameters.state),
geometryTile.iconAtlasTexture->size,
crossfade,
tile.id,
parameters.state,
-std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f,
parameters.pixelRatio,
parameters.evaluatedLight
),
patternPosA,
patternPosB,
FillExtrusionPatternProgram::TextureBindings{}
);
}
}
} else if (parameters.pass == RenderPass::Translucent) {
parameters.context.bindTexture(renderTexture->getTexture());
const auto& size = parameters.staticData.backendSize;
mat4 viewportMat;
matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1);
const Properties<>::PossiblyEvaluated properties;
const ExtrusionTextureProgram::Binders paintAttributeData{ properties, 0 };
auto& programInstance = parameters.programs.getFillExtrusionLayerPrograms().extrusionTexture;
const auto allUniformValues = programInstance.computeAllUniformValues(
ExtrusionTextureProgram::UniformValues{
uniforms::u_matrix::Value( viewportMat ), uniforms::u_world::Value( size ),
uniforms::u_image::Value( 0 ),
uniforms::u_opacity::Value( evaluated.get<FillExtrusionOpacity>() )
},
paintAttributeData,
properties,
parameters.state.getZoom()
);
const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
parameters.staticData.extrusionTextureVertexBuffer,
paintAttributeData,
properties
);
checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
programInstance.draw(
parameters.context,
gfx::Triangles(),
gfx::DepthMode::disabled(),
gfx::StencilMode::disabled(),
parameters.colorModeForRenderPass(),
gfx::CullFaceMode::disabled(),
parameters.staticData.quadTriangleIndexBuffer,
parameters.staticData.extrusionTextureSegments,
allUniformValues,
allAttributeBindings,
ExtrusionTextureProgram::TextureBindings{},
getID());
}
}
bool RenderFillExtrusionLayer::queryIntersectsFeature(
const GeometryCoordinates& queryGeometry,
const GeometryTileFeature& feature,
const float,
const TransformState& transformState,
const float pixelsToTileUnits,
const mat4&) const {
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
queryGeometry,
evaluated.get<style::FillExtrusionTranslate>(),
evaluated.get<style::FillExtrusionTranslateAnchor>(),
transformState.getBearing(),
pixelsToTileUnits);
return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries());
}
} // namespace mbgl