Custom drawable layer v2 (#1754)
This commit is contained in:
@@ -13,207 +13,106 @@
|
||||
#if MLN_DRAWABLE_RENDERER
|
||||
|
||||
#include <mbgl/style/layers/custom_drawable_layer.hpp>
|
||||
#include <mbgl/gfx/context.hpp>
|
||||
#include <mbgl/gfx/drawable.hpp>
|
||||
#include <mbgl/gfx/drawable_tweaker.hpp>
|
||||
#include <mbgl/gfx/shader_registry.hpp>
|
||||
#include <mbgl/gfx/color_mode.hpp>
|
||||
#include <mbgl/gfx/cull_face_mode.hpp>
|
||||
#include <mbgl/gfx/drawable_builder.hpp>
|
||||
|
||||
#include <mbgl/shaders/shader_program_base.hpp>
|
||||
#include <mbgl/util/string_indexer.hpp>
|
||||
#include <mbgl/renderer/layer_tweaker.hpp>
|
||||
#include <mbgl/renderer/layer_group.hpp>
|
||||
#include <mbgl/renderer/render_tile.hpp>
|
||||
#include <mbgl/shaders/line_layer_ubo.hpp>
|
||||
#include <mbgl/util/string_indexer.hpp>
|
||||
#include <mbgl/util/convert.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
|
||||
class TestDrawableTweaker : public gfx::DrawableTweaker {
|
||||
public:
|
||||
TestDrawableTweaker() {}
|
||||
~TestDrawableTweaker() override = default;
|
||||
|
||||
void init(gfx::Drawable&) override{};
|
||||
|
||||
void execute(gfx::Drawable& drawable, const PaintParameters& parameters) override {
|
||||
if (!drawable.getTileID().has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped();
|
||||
const auto zoom = parameters.state.getZoom();
|
||||
mat4 tileMatrix;
|
||||
parameters.state.matrixFor(/*out*/ tileMatrix, tileID);
|
||||
|
||||
const auto matrix = LayerTweaker::getTileMatrix(
|
||||
tileID, parameters, {{0, 0}}, style::TranslateAnchorType::Viewport, false, false, false);
|
||||
|
||||
static const StringIdentity idLineUBOName = stringIndexer().get("LineUBO");
|
||||
const shaders::LineUBO lineUBO{
|
||||
/*matrix = */ util::cast<float>(matrix),
|
||||
/*units_to_pixels = */ {1.0f / parameters.pixelsToGLUnits[0], 1.0f / parameters.pixelsToGLUnits[1]},
|
||||
/*ratio = */ 1.0f / tileID.pixelsToTileUnits(1.0f, zoom),
|
||||
/*device_pixel_ratio = */ parameters.pixelRatio};
|
||||
|
||||
static const StringIdentity idLinePropertiesUBOName = stringIndexer().get("LinePropertiesUBO");
|
||||
const shaders::LinePropertiesUBO linePropertiesUBO{/*color =*/Color(1.f, 0.f, 1.f, 1.f),
|
||||
/*blur =*/0.f,
|
||||
/*opacity =*/1.f,
|
||||
/*gapwidth =*/0.f,
|
||||
/*offset =*/0.f,
|
||||
/*width =*/8.f,
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
|
||||
static const StringIdentity idLineInterpolationUBOName = stringIndexer().get("LineInterpolationUBO");
|
||||
const shaders::LineInterpolationUBO lineInterpolationUBO{/*color_t =*/0.f,
|
||||
/*blur_t =*/0.f,
|
||||
/*opacity_t =*/0.f,
|
||||
/*gapwidth_t =*/0.f,
|
||||
/*offset_t =*/0.f,
|
||||
/*width_t =*/0.f,
|
||||
0,
|
||||
0};
|
||||
auto& uniforms = drawable.mutableUniformBuffers();
|
||||
uniforms.createOrUpdate(idLineUBOName, &lineUBO, parameters.context);
|
||||
uniforms.createOrUpdate(idLinePropertiesUBOName, &linePropertiesUBO, parameters.context);
|
||||
uniforms.createOrUpdate(idLineInterpolationUBOName, &lineInterpolationUBO, parameters.context);
|
||||
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
static const StringIdentity idExpressionInputsUBOName = stringIndexer().get("ExpressionInputsUBO");
|
||||
const auto expressionUBO = LayerTweaker::buildExpressionUBO(zoom, parameters.frameCount);
|
||||
uniforms.createOrUpdate(idExpressionInputsUBOName, &expressionUBO, parameters.context);
|
||||
|
||||
static const StringIdentity idLinePermutationUBOName = stringIndexer().get("LinePermutationUBO");
|
||||
const shaders::LinePermutationUBO permutationUBO = {
|
||||
/* .color = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
|
||||
/* .blur = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
|
||||
/* .opacity = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
|
||||
/* .gapwidth = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
|
||||
/* .offset = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
|
||||
/* .width = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
|
||||
/* .floorwidth = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
|
||||
/* .pattern_from = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
|
||||
/* .pattern_to = */ {/*.source=*/shaders::AttributeSource::Constant, /*.expression=*/{}},
|
||||
/* .overdrawInspector = */ false,
|
||||
/* .pad = */ 0,
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
uniforms.createOrUpdate(idLinePermutationUBOName, &permutationUBO, parameters.context);
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
};
|
||||
};
|
||||
#include <cmath>
|
||||
|
||||
class TestDrawableLayer : public mbgl::style::CustomDrawableLayerHost {
|
||||
public:
|
||||
void initialize() override {}
|
||||
|
||||
/**
|
||||
* @brief Create Drawables for the Custom Drawable Layer
|
||||
*
|
||||
* @param proxyLayer
|
||||
* @param shaders
|
||||
* @param context
|
||||
* @param state
|
||||
* @param updateParameters
|
||||
* @param renderTree
|
||||
* @param changes
|
||||
*/
|
||||
void update(RenderLayer& proxyLayer,
|
||||
gfx::ShaderRegistry& shaders,
|
||||
gfx::Context& context,
|
||||
[[maybe_unused]] const TransformState& state,
|
||||
[[maybe_unused]] const std::shared_ptr<UpdateParameters>& updateParameters,
|
||||
[[maybe_unused]] const RenderTree& renderTree,
|
||||
UniqueChangeRequestVec& changes) override {
|
||||
// Set up a layer group
|
||||
if (!layerGroup) {
|
||||
if (auto layerGroup_ = context.createTileLayerGroup(
|
||||
/*layerIndex*/ proxyLayer.getLayerIndex(), /*initialCapacity=*/2, proxyLayer.getID())) {
|
||||
changes.emplace_back(std::make_unique<AddLayerGroupRequest>(layerGroup_));
|
||||
layerGroup = std::move(layerGroup_);
|
||||
}
|
||||
}
|
||||
void update(Interface& interface) override {
|
||||
// if we have built our drawable(s) already, either update or skip
|
||||
if (interface.getDrawableCount()) return;
|
||||
|
||||
if (!layerGroup) return;
|
||||
|
||||
// if we have build our drawable(s) already, either update or skip
|
||||
if (layerGroup->getDrawableCount()) return;
|
||||
|
||||
// create drawable(s)
|
||||
const OverscaledTileID tileID{11, 327, 791};
|
||||
|
||||
auto createLineBuilder = [&](const std::string& name,
|
||||
gfx::ShaderPtr shader) -> std::unique_ptr<gfx::DrawableBuilder> {
|
||||
std::unique_ptr<gfx::DrawableBuilder> builder = context.createDrawableBuilder(name);
|
||||
builder->setShader(std::static_pointer_cast<gfx::ShaderProgramBase>(shader));
|
||||
builder->setSubLayerIndex(0);
|
||||
builder->setEnableDepth(false);
|
||||
builder->setColorMode(gfx::ColorMode::alphaBlended());
|
||||
builder->setCullFaceMode(gfx::CullFaceMode::disabled());
|
||||
builder->setEnableStencil(false);
|
||||
builder->setRenderPass(RenderPass::Translucent);
|
||||
|
||||
return builder;
|
||||
};
|
||||
|
||||
gfx::ShaderGroupPtr lineShaderGroup = shaders.getShaderGroup("LineShader");
|
||||
|
||||
const std::unordered_set<StringIdentity> propertiesAsUniforms{
|
||||
stringIndexer().get("a_color"),
|
||||
stringIndexer().get("a_blur"),
|
||||
stringIndexer().get("a_opacity"),
|
||||
stringIndexer().get("a_gapwidth"),
|
||||
stringIndexer().get("a_offset"),
|
||||
stringIndexer().get("a_width"),
|
||||
};
|
||||
|
||||
auto shader = lineShaderGroup->getOrCreateShader(context, propertiesAsUniforms);
|
||||
auto builder = createLineBuilder("thick-lines", shader);
|
||||
|
||||
auto* tileLayerGroup = static_cast<TileLayerGroup*>(layerGroup.get());
|
||||
// set tile
|
||||
interface.setTileID({11, 327, 791});
|
||||
|
||||
// add polylines
|
||||
const auto size{util::EXTENT};
|
||||
GeometryCoordinates geom{{0, 0}, {size, 0}, {0, size}, {size, size}, {size / 3, size / 3}};
|
||||
using namespace mbgl;
|
||||
|
||||
gfx::PolylineGeneratorOptions options;
|
||||
options.beginCap = style::LineCapType::Round;
|
||||
options.endCap = style::LineCapType::Round;
|
||||
options.joinType = style::LineJoinType::Round;
|
||||
builder->addPolyline(geom, options);
|
||||
constexpr auto numLines = 6;
|
||||
Interface::LineOptions options[numLines]{
|
||||
{/*color=*/Color::red(),
|
||||
/*blur=*/0.0f,
|
||||
/*opacity=*/1.0f,
|
||||
/*gapWidth=*/0.0f,
|
||||
/*offset=*/0.0f,
|
||||
/*width=*/8.0f,
|
||||
{}},
|
||||
{/*color=*/Color::blue(),
|
||||
/*blur=*/4.0f,
|
||||
/*opacity=*/1.0f,
|
||||
/*gapWidth=*/2.0f,
|
||||
/*offset=*/-1.0f,
|
||||
/*width=*/4.0f,
|
||||
{}},
|
||||
{/*color=*/Color(1.f, 0.5f, 0, 0.5f),
|
||||
/*blur=*/16.0f,
|
||||
/*opacity=*/1.0f,
|
||||
/*gapWidth=*/1.0f,
|
||||
/*offset=*/2.0f,
|
||||
/*width=*/16.0f,
|
||||
{}},
|
||||
{/*color=*/Color(1.f, 1.f, 0, 0.3f),
|
||||
/*blur=*/2.0f,
|
||||
/*opacity=*/1.0f,
|
||||
/*gapWidth=*/1.0f,
|
||||
/*offset=*/-2.0f,
|
||||
/*width=*/2.0f,
|
||||
{}},
|
||||
{/*color=*/Color::black(),
|
||||
/*blur=*/0.5f,
|
||||
/*opacity=*/0.5f,
|
||||
/*gapWidth=*/1.0f,
|
||||
/*offset=*/0.5f,
|
||||
/*width=*/0.5f,
|
||||
{}},
|
||||
{/*color=*/Color(1.f, 0, 1.f, 0.2f),
|
||||
/*blur=*/24.0f,
|
||||
/*opacity=*/0.5f,
|
||||
/*gapWidth=*/1.0f,
|
||||
/*offset=*/-5.0f,
|
||||
/*width=*/24.0f,
|
||||
{}},
|
||||
};
|
||||
for (auto& opt : options) {
|
||||
opt.geometry.beginCap = style::LineCapType::Round;
|
||||
opt.geometry.endCap = style::LineCapType::Round;
|
||||
opt.geometry.joinType = style::LineJoinType::Round;
|
||||
}
|
||||
|
||||
// create tweaker
|
||||
auto tweaker = std::make_shared<TestDrawableTweaker>();
|
||||
constexpr auto numPoints = 100;
|
||||
GeometryCoordinates polyline;
|
||||
for (auto ipoint{0}; ipoint < numPoints; ++ipoint) {
|
||||
polyline.emplace_back(ipoint * util::EXTENT / numPoints,
|
||||
std::sin(ipoint * 2 * M_PI / numPoints) * util::EXTENT / numLines / 2.f);
|
||||
}
|
||||
|
||||
for (auto index{0}; index < numLines; ++index) {
|
||||
for (auto& p : polyline) {
|
||||
p.y += util::EXTENT / numLines;
|
||||
}
|
||||
|
||||
// set property values
|
||||
interface.setLineOptions(options[index]);
|
||||
|
||||
// add polyline
|
||||
interface.addPolyline(polyline);
|
||||
}
|
||||
|
||||
// finish
|
||||
builder->flush();
|
||||
for (auto& drawable : builder->clearDrawables()) {
|
||||
drawable->setTileID(tileID);
|
||||
drawable->addTweaker(tweaker);
|
||||
|
||||
tileLayerGroup->addDrawable(RenderPass::Translucent, tileID, std::move(drawable));
|
||||
}
|
||||
interface.finish();
|
||||
}
|
||||
|
||||
void deinitialize() override {
|
||||
// layerGroup->reset();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<TileLayerGroup> layerGroup;
|
||||
void deinitialize() override {}
|
||||
};
|
||||
|
||||
TEST(CustomDrawableLayer, Basic) {
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
|
||||
util::RunLoop loop;
|
||||
|
||||
HeadlessFrontend frontend{1};
|
||||
|
||||
Reference in New Issue
Block a user