From 40396944bffa7dcc2bc655a59c251c93e810fb13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Mon, 7 Jul 2025 01:50:21 -0400 Subject: [PATCH 01/49] Very prelim --- bazel/core.bzl | 2 + platform/darwin/src/MLNPluginLayer.h | 13 ++ platform/darwin/src/MLNPluginLayer.mm | 12 ++ platform/ios/src/MLNMapView.mm | 45 ++++++ src/mbgl/plugin/plugin_layer.hpp | 6 +- src/mbgl/plugin/plugin_layer_factory.cpp | 14 +- src/mbgl/plugin/plugin_layer_factory.hpp | 3 + src/mbgl/plugin/plugin_layer_impl.hpp | 7 + src/mbgl/plugin/raw_bucket.cpp | 185 ++++++++++++++++++++++ src/mbgl/plugin/raw_bucket.hpp | 113 +++++++++++++ src/mbgl/renderer/render_orchestrator.cpp | 7 + src/mbgl/tile/geometry_tile_worker.cpp | 10 +- 12 files changed, 410 insertions(+), 7 deletions(-) create mode 100644 src/mbgl/plugin/raw_bucket.cpp create mode 100644 src/mbgl/plugin/raw_bucket.hpp diff --git a/bazel/core.bzl b/bazel/core.bzl index b27bbd8d925b..efc259dbed87 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -4,6 +4,7 @@ MLN_LAYER_PLUGIN_HEADERS = [ "src/mbgl/plugin/plugin_layer_impl.hpp", "src/mbgl/plugin/plugin_layer_render.hpp", "src/mbgl/plugin/plugin_layer_properties.hpp", + "src/mbgl/plugin/raw_bucket.hpp", ] MLN_LAYER_PLUGIN_SOURCE = [ @@ -12,6 +13,7 @@ MLN_LAYER_PLUGIN_SOURCE = [ "src/mbgl/plugin/plugin_layer_impl.cpp", "src/mbgl/plugin/plugin_layer_render.cpp", "src/mbgl/plugin/plugin_layer_properties.cpp", + "src/mbgl/plugin/raw_bucket.cpp", ] MLN_PUBLIC_GENERATED_STYLE_HEADERS = [ diff --git a/platform/darwin/src/MLNPluginLayer.h b/platform/darwin/src/MLNPluginLayer.h index b188e4fb2376..3b87995e1862 100644 --- a/platform/darwin/src/MLNPluginLayer.h +++ b/platform/darwin/src/MLNPluginLayer.h @@ -42,6 +42,13 @@ MLN_EXPORT @end +@interface MLNPluginLayerTileFeature : NSObject + +@property NSDictionary *featureProperties; +@property NSArray *featureCoordinates; + +@end + typedef enum { MLNPluginLayerTileKindGeometry, MLNPluginLayerTileKindRaster, @@ -55,6 +62,9 @@ MLN_EXPORT @property (copy) NSString *layerID; @property BOOL requiresPass3D; +//! Set this to true if this layer can support reading features from the tiles +@property BOOL supportsReadingTileFeatures; + //! This is a list of layer properties that this layer supports. @property (copy) NSArray *layerProperties; @@ -101,6 +111,9 @@ MLN_EXPORT /// dynamic properties are updated - (void)onUpdateLayerProperties:(NSDictionary *)layerProperties; +/// Called when a feature is loaded from the tile +- (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature; + /// Added to a map view - (void)didMoveToMapView:(MLNMapView *)mapView; diff --git a/platform/darwin/src/MLNPluginLayer.mm b/platform/darwin/src/MLNPluginLayer.mm index cff0044d05ac..712552d9f39d 100644 --- a/platform/darwin/src/MLNPluginLayer.mm +++ b/platform/darwin/src/MLNPluginLayer.mm @@ -1,5 +1,9 @@ #import "MLNPluginLayer.h" +@implementation MLNPluginLayerTileFeature + +@end + @implementation MLNPluginLayerProperty +(MLNPluginLayerProperty *)propertyWithName:(NSString *)propertyName @@ -65,12 +69,20 @@ - (void)onUpdateLayer:(MLNPluginLayerDrawingContext)drawingContext { -(void)onUpdateLayerProperties:(NSDictionary *)layerProperties { // Base class does nothing } + +// If the layer properties indicate that this layer has a the ability to intercept +// features, then this method will be called when a feature is loaded +- (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature { + // Base class does nothing +} + /// Added to a map view - (void)didMoveToMapView:(MLNMapView *)mapView { // Base class does nothing } + @end diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index 1337f0c6bd36..43b93c081e55 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -7675,6 +7676,10 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { if (capabilities.requiresPass3D) { pass3D = mbgl::style::LayerTypeInfo::Pass3D::Required; } + + + tileKind = mbgl::style::LayerTypeInfo::TileKind::Geometry; + source = mbgl::style::LayerTypeInfo::Source::Required; auto factory = std::make_unique(layerType, source, @@ -7687,6 +7692,7 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { __weak MLNMapView *weakMapView = self; Class layerClass = pluginLayerClass; + factory->_supportsRawBuckets = capabilities.supportsReadingTileFeatures; factory->setOnLayerCreatedEvent([layerClass, weakMapView, pluginLayerClass](mbgl::style::PluginLayer *pluginLayer) { //NSLog(@"Creating Plugin Layer: %@", layerClass); @@ -7782,6 +7788,45 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { [weakPlugInLayer onUpdateLayerProperties:properties]; } }); + + // If this layer can read tile features, then setup that lambda + if (capabilities.supportsReadingTileFeatures) { + pluginLayerImpl->setFeatureLoadedFunction([weakPlugInLayer](const std::shared_ptr feature) { + + @autoreleasepool { + MLNPluginLayerTileFeature *tileFeature = [[MLNPluginLayerTileFeature alloc] init]; + + NSMutableDictionary *tileProperties = [NSMutableDictionary dictionary]; + for (auto p: feature->_featureProperties) { + NSString *key = [NSString stringWithUTF8String:p.first.c_str()]; + NSString *value = [NSString stringWithUTF8String:p.second.c_str()]; + [tileProperties setObject:value forKey:key]; + } + + tileFeature.featureProperties = [NSDictionary dictionaryWithDictionary:tileProperties]; + + NSMutableArray *featureCoordinates = [NSMutableArray array]; + for (auto & coordinateCollection: feature->_featureCoordinates) { + + for (auto & coordinate: coordinateCollection._coordinates) { + CLLocationCoordinate2D c = CLLocationCoordinate2DMake(coordinate._lat, coordinate._lon); + NSValue *value = [NSValue valueWithBytes:&c objCType:@encode(CLLocationCoordinate2D)]; + [featureCoordinates addObject:value]; + } + + } + // TODO: Need to figure out how we're going to handle multiple coordinate groups/etc + if ([featureCoordinates count] > 0) { + tileFeature.featureCoordinates = [NSArray arrayWithArray:featureCoordinates]; + } + + + [weakPlugInLayer onFeatureLoaded:tileFeature]; + + } + + }); + } }); diff --git a/src/mbgl/plugin/plugin_layer.hpp b/src/mbgl/plugin/plugin_layer.hpp index f8f95a4c4c70..7b5ae19f349b 100644 --- a/src/mbgl/plugin/plugin_layer.hpp +++ b/src/mbgl/plugin/plugin_layer.hpp @@ -6,8 +6,11 @@ namespace mbgl { +class RawBucketFeature; + namespace style { + class PluginLayer final : public Layer { public: PluginLayer(const std::string& layerID, @@ -28,7 +31,8 @@ class PluginLayer final : public Layer { using OnRenderLayer = std::function; using OnUpdateLayer = std::function; using OnUpdateLayerProperties = std::function; - + using OnFeatureLoaded = std::function feature)>; + void* _platformReference = nullptr; protected: diff --git a/src/mbgl/plugin/plugin_layer_factory.cpp b/src/mbgl/plugin/plugin_layer_factory.cpp index f33fb701f29f..4d68fad43fb3 100644 --- a/src/mbgl/plugin/plugin_layer_factory.cpp +++ b/src/mbgl/plugin/plugin_layer_factory.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -66,7 +67,7 @@ PluginLayerFactory::PluginLayerFactory(std::string& layerType, mbgl::style::LayerTypeInfo::TileKind tileKind) : _layerTypeInfo(getDefaultInfo()), _layerType(layerType) { - _layerTypeInfo.type = layerType.c_str(); + _layerTypeInfo.type = _layerType.c_str(); plugins::NonConstLayerTypeInfo* lti = (plugins::NonConstLayerTypeInfo*)&_layerTypeInfo; lti->source = (plugins::NonConstLayerTypeInfo::Source)((int)source); lti->pass3d = (plugins::NonConstLayerTypeInfo::Pass3D)((int)pass3D); @@ -149,10 +150,11 @@ std::unique_ptr PluginLayerFactory::createLayer(const std::string& } } - std::string source = "source"; + auto source = getSource(value); + std::string sourceStr = source.has_value() ? source.value() : "source"; auto tempResult = std::unique_ptr(new (std::nothrow) - style::PluginLayer(id, source, _layerTypeInfo, layerProperties + style::PluginLayer(id, sourceStr, _layerTypeInfo, layerProperties //,*customProperties )); @@ -172,8 +174,10 @@ std::unique_ptr PluginLayerFactory::createLayer(const std::string& std::unique_ptr PluginLayerFactory::createBucket( [[maybe_unused]] const BucketParameters& parameters, [[maybe_unused]] const std::vector>& layers) noexcept { - // Returning null for now. Not using buckets in plug-ins yet. - return nullptr; + if (_supportsRawBuckets) { + return std::make_unique(parameters, layers); + } + return nullptr; } std::unique_ptr PluginLayerFactory::createRenderLayer(Immutable impl) noexcept { diff --git a/src/mbgl/plugin/plugin_layer_factory.hpp b/src/mbgl/plugin/plugin_layer_factory.hpp index 0a976b37a9f1..d35c5ca8bc48 100644 --- a/src/mbgl/plugin/plugin_layer_factory.hpp +++ b/src/mbgl/plugin/plugin_layer_factory.hpp @@ -23,6 +23,9 @@ class PluginLayerFactory : public LayerFactory { mbgl::style::LayerTypeInfo::CrossTileIndex crossTileIndex, mbgl::style::LayerTypeInfo::TileKind tileKind); + // Set to false, but if the caller wants to support on features loaded, then set this to true + bool _supportsRawBuckets = false; + using OnLayerCreatedEvent = std::function; void setOnLayerCreatedEvent(OnLayerCreatedEvent onLayerCreated) { _onLayerCreated = onLayerCreated; } diff --git a/src/mbgl/plugin/plugin_layer_impl.hpp b/src/mbgl/plugin/plugin_layer_impl.hpp index 512cec427a33..6b58c42f8e7f 100644 --- a/src/mbgl/plugin/plugin_layer_impl.hpp +++ b/src/mbgl/plugin/plugin_layer_impl.hpp @@ -99,6 +99,10 @@ class PluginLayer::Impl : public Layer::Impl { _updateLayerPropertiesFunction = updateLayerPropertiesFunction; } + void setFeatureLoadedFunction(OnFeatureLoaded featureLoadedFunction) { + _featureLoadedFunction = featureLoadedFunction; + } + //! The property manager handles all of the custom properties for this layer type / instance PluginLayerPropertyManager _propertyManager; @@ -113,6 +117,9 @@ class PluginLayer::Impl : public Layer::Impl { //! Optional: Called when the layer properties change. The properties are passed as JSON for now OnUpdateLayerProperties _updateLayerPropertiesFunction; + //! Optional: Called when feature is loaded + OnFeatureLoaded _featureLoadedFunction; + private: LayerTypeInfo _layerTypeInfo; std::string _layerProperties; diff --git a/src/mbgl/plugin/raw_bucket.cpp b/src/mbgl/plugin/raw_bucket.cpp new file mode 100644 index 000000000000..9322cc4b3e8a --- /dev/null +++ b/src/mbgl/plugin/raw_bucket.cpp @@ -0,0 +1,185 @@ +// +// raw_bucket.cpp +// App +// +// Created by Malcolm Toon on 7/3/25. +// + +#include +#include +#include + +#include "raw_bucket.hpp" + +#include + +using namespace mbgl; + +RawBucket::~RawBucket() { + +} + +RawBucket::RawBucket(const BucketParameters& bucketParameters, + const std::vector>& layers) { + _layers = layers; +} + +void geometryToLatLon( + const GeometryCoordinate& coord, + int tileX, int tileY, int zoom, + double& lat, double& lon, + int extent = 8192, + int tileSize = 512 +) { + double px = coord.x / double(extent); + double py = coord.y / double(extent); + + double worldPixelX = (tileX + px) * tileSize; + double worldPixelY = (tileY + py) * tileSize; + + double worldSize = tileSize * (1 << zoom); + + double mercX = worldPixelX / worldSize * 2.0 - 1.0; + double mercY = 1.0 - worldPixelY / worldSize * 2.0; + + lon = mercX * 180.0; + lat = 180.0 / M_PI * (2.0 * atan(exp(mercY * M_PI)) - M_PI / 2.0); +} + +void RawBucket::addFeature(const GeometryTileFeature& tileFeature, + const GeometryCollection& geometeryCollection, + const mbgl::ImagePositions& imagePositions, + const PatternLayerMap& patternLayerMap, + std::size_t size, + const CanonicalTileID& tileID) { + + std::shared_ptr tempFeature = std::make_shared(); + + switch (tileFeature.getType()) { + case FeatureType::Point: + std::cout << "Adding Point" << "\n"; + tempFeature->_featureType = RawBucketFeature::FeatureType::FeatureTypePoint; + break; + case FeatureType::Unknown: + std::cout << "Unknown Type Found\n"; + break; + case FeatureType::LineString: + std::cout << "LineString Type Found\n"; + tempFeature->_featureType = RawBucketFeature::FeatureType::FeatureTypeLine; + break; + case FeatureType::Polygon: + std::cout << "Polygon Type Found\n"; + tempFeature->_featureType = RawBucketFeature::FeatureType::FeatureTypePolygon; + break; + + + } + + auto pm = tileFeature.getProperties(); + for (auto p: pm) { + + auto name = p.first; + mapbox::feature::value value = p.second; + + if (auto iVal = value.getInt()) { + std::cout << "Found Int: " << name << ": " << *iVal << "\n"; + tempFeature->_featureProperties[name] = std::to_string(*iVal); + } else if (auto uIVal = value.getUint()) { + std::cout << "Found UInt: " << name << ": " << *uIVal << "\n"; + tempFeature->_featureProperties[name] = std::to_string(*uIVal); + + } else if (auto s = value.getString()) { + + std::cout << "Found String: " << name << ": " << *s << "\n"; + tempFeature->_featureProperties[name] = *s; + + } else if (auto d = value.getDouble()) { + std::cout << "Found Double: " << name << ": " << *d << "\n"; + tempFeature->_featureProperties[name] = std::to_string(*d); + } else if (auto b = value.getBool()) { + std::cout << "Found Bool: " << name << ": " << *b << "\n"; + tempFeature->_featureProperties[name] = std::to_string(*b); + } else if (auto a = value.getArray()) { + std::cout << "Found Array: " << name << ": " << *b << "\n"; + tempFeature->_featureProperties[name] = std::to_string(*b); + } + + +// DECLARE_VALUE_TYPE_ACCESOR(Array, array_type) +// DECLARE_VALUE_TYPE_ACCESOR(Object, object_type) + + } + + LatLngBounds b(tileID); + + + + for (const auto& g : geometeryCollection) { + // g is GeometryCoordinates + RawBucketFeatureCoordinateCollection c; + for (std::size_t i = 0, len = g.size(); i < len; i++) { + const GeometryCoordinate& p1 = g[i]; + + auto d = b.west(); + +// auto c = project( + + +// void geometryToLatLon( +// const GeometryCoordinate& coord, +// int tileX, int tileY, int zoom, +// double& lat, double& lon, +// int extent = 8192, +// int tileSize = 512 + double lat = 0; + double lon = 0; + geometryToLatLon(p1, tileID.x, tileID.y, tileID.z, lat, lon); + + c._coordinates.push_back(RawBucketFeatureCoordinate(lat, lon)); + } + tempFeature->_featureCoordinates.push_back(c); + + } + + for (auto l: _layers) { + auto bi = l->baseImpl; + auto bip = bi.get(); + auto pluginLayer = static_cast(bip); + if (pluginLayer != nullptr) { + if (pluginLayer->_featureLoadedFunction != nullptr) { + pluginLayer->_featureLoadedFunction(tempFeature); + } + + } + // auto pluginLayer = std::dynamic_pointer_cast>(bi); + +// auto pluginLayer = std::dynamic_pointer_cast(l->baseImpl); +// if (pluginLayer != nullptr) { +// if (pluginLayer->_featureLoadedFunction != nullptr) { +// pluginLayer->_featureLoadedFunction(tempFeature); +// } +// } + } + + _features.push_back(tempFeature); + +// std::cout << "Adding Feature Type: " << tileFeature.getType() << "\n"; + +} + +bool RawBucket::hasData() const { + return true; +} + +void RawBucket::upload(gfx::UploadPass&) { + +} + +float RawBucket::getQueryRadius(const RenderLayer&) const { + return 0; +} + +void RawBucket::update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) { + +} + diff --git a/src/mbgl/plugin/raw_bucket.hpp b/src/mbgl/plugin/raw_bucket.hpp new file mode 100644 index 000000000000..507667375d23 --- /dev/null +++ b/src/mbgl/plugin/raw_bucket.hpp @@ -0,0 +1,113 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace mbgl { + +class BucketParameters; +class RenderFillLayer; + +//using FillBinders = PaintPropertyBinders; +//using FillLayoutVertex = gfx::Vertex>; + +class RawBucketFeatureCoordinate { +public: + RawBucketFeatureCoordinate(double lat, double lon) : _lat(lat), _lon(lon) { + + } + double _lat = 0; + double _lon = 0; +}; + +// This is a list of coordinates. Broken out into it's own class because +// a raw bucket feature can have an array of these +class RawBucketFeatureCoordinateCollection { +public: + std::vector _coordinates; +}; + +class RawBucketFeature { +public: + RawBucketFeature() {}; + enum class FeatureType { + FeatureTypeUnknown, + FeatureTypePoint, + FeatureTypeLine, + FeatureTypePolygon + }; + FeatureType _featureType = FeatureType::FeatureTypeUnknown; + std::map _featureProperties; + std::vector _featureCoordinates; +}; + +class RawBucket final : public Bucket { +public: + ~RawBucket() override; + //using PossiblyEvaluatedLayoutProperties = style::FillLayoutProperties::PossiblyEvaluated; + + RawBucket(const BucketParameters&, const std::vector>&); + + void addFeature(const GeometryTileFeature&, + const GeometryCollection&, + const mbgl::ImagePositions&, + const PatternLayerMap&, + std::size_t, + const CanonicalTileID&) override; + + bool hasData() const override; + + void upload(gfx::UploadPass&) override; + + float getQueryRadius(const RenderLayer&) const override; + + void update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) override; + + // Array of features + std::vector> _features; + + std::vector> _layers; + + /* + static FillLayoutVertex layoutVertex(Point p) { return FillLayoutVertex{{{p.x, p.y}}}; } + +#if MLN_TRIANGULATE_FILL_OUTLINES + using LineVertexVector = gfx::VertexVector; + const std::shared_ptr sharedLineVertices = std::make_shared(); + LineVertexVector& lineVertices = *sharedLineVertices; + + using LineIndexVector = gfx::IndexVector; + const std::shared_ptr sharedLineIndexes = std::make_shared(); + LineIndexVector& lineIndexes = *sharedLineIndexes; + + SegmentVector lineSegments; +#endif // MLN_TRIANGULATE_FILL_OUTLINES + + using BasicLineIndexVector = gfx::IndexVector; + const std::shared_ptr sharedBasicLineIndexes = std::make_shared(); + BasicLineIndexVector& basicLines = *sharedBasicLineIndexes; + + SegmentVector basicLineSegments; + + using VertexVector = gfx::VertexVector; + const std::shared_ptr sharedVertices = std::make_shared(); + VertexVector& vertices = *sharedVertices; + + using TriangleIndexVector = gfx::IndexVector; + const std::shared_ptr sharedTriangles = std::make_shared(); + TriangleIndexVector& triangles = *sharedTriangles; + + SegmentVector triangleSegments; + + std::map paintPropertyBinders; + */ +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 8f6e3abf0419..127355fa769d 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -29,6 +29,8 @@ #include #include +#include + namespace mbgl { using namespace style; @@ -371,6 +373,11 @@ std::unique_ptr RenderOrchestrator::createRenderTree( for (std::size_t index = 0; index < orderedLayers.size(); ++index) { RenderLayer& layer = orderedLayers[index]; const auto* layerInfo = layer.baseImpl->getTypeInfo(); + std::string s1(layerInfo->type); + //std::cout << " -> " << s1 << "\n"; +// if (s1 == "hudhud::gltf-model-layer") { +// std::cout << "Found plugin\n"; +// } const bool layerIsVisible = layer.baseImpl->visibility != style::VisibilityType::None; const bool zoomFitsLayer = layer.supportsZoom(zoomHistory.lastZoom); renderTreeParameters->has3D |= (layerInfo->pass3d == LayerTypeInfo::Pass3D::Required); diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index 4935bc5f3382..874494cd94a5 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -24,6 +24,7 @@ #include #include +#include namespace mbgl { @@ -396,7 +397,14 @@ void GeometryTileWorker::parse() { groupMap.reserve(layers->size()); for (auto layer : *layers) { - groupMap[layoutKey(*layer->baseImpl)].push_back(std::move(layer)); + auto lk = layoutKey(*layer->baseImpl); + //std::cout << "LK: " << lk << "\n"; + if (lk.find("parking_space1") != std::string::npos) { + // std::cout << " Found PLugin\n"; + } else { + // continue; + } + groupMap[lk].push_back(std::move(layer)); } for (auto& pair : groupMap) { From 3aa92dbe8a1d0888495cd8909e3e6f8e0c3ff409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Fri, 25 Jul 2025 10:35:16 -0400 Subject: [PATCH 02/49] Initial commit --- bazel/core.bzl | 6 +- platform/darwin/app/PluginLayerExample.mm | 58 +++++- platform/darwin/src/MLNPluginLayer.h | 19 ++ platform/darwin/src/MLNPluginLayer.mm | 15 ++ platform/ios/src/MLNMapView.mm | 119 ++++++++--- src/mbgl/plugin/feature_collection.cpp | 8 + src/mbgl/plugin/feature_collection.hpp | 74 +++++++ ...cket.cpp => feature_collection_bucket.cpp} | 103 +++++++--- ...cket.hpp => feature_collection_bucket.hpp} | 73 ++++--- src/mbgl/plugin/plugin_layer.hpp | 7 +- src/mbgl/plugin/plugin_layer_factory.cpp | 16 +- src/mbgl/plugin/plugin_layer_factory.hpp | 2 +- src/mbgl/plugin/plugin_layer_impl.hpp | 14 ++ src/mbgl/plugin/plugin_layer_render.cpp | 191 +++++++++++++++++- src/mbgl/plugin/plugin_layer_render.hpp | 4 + src/mbgl/renderer/render_orchestrator.cpp | 5 - src/mbgl/tile/geometry_tile.cpp | 2 +- 17 files changed, 603 insertions(+), 113 deletions(-) create mode 100644 src/mbgl/plugin/feature_collection.cpp create mode 100644 src/mbgl/plugin/feature_collection.hpp rename src/mbgl/plugin/{raw_bucket.cpp => feature_collection_bucket.cpp} (58%) rename src/mbgl/plugin/{raw_bucket.hpp => feature_collection_bucket.hpp} (66%) diff --git a/bazel/core.bzl b/bazel/core.bzl index efc259dbed87..3fbf7eeea8aa 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -4,7 +4,8 @@ MLN_LAYER_PLUGIN_HEADERS = [ "src/mbgl/plugin/plugin_layer_impl.hpp", "src/mbgl/plugin/plugin_layer_render.hpp", "src/mbgl/plugin/plugin_layer_properties.hpp", - "src/mbgl/plugin/raw_bucket.hpp", + "src/mbgl/plugin/feature_collection_bucket.hpp", + "src/mbgl/plugin/feature_collection.hpp", ] MLN_LAYER_PLUGIN_SOURCE = [ @@ -13,7 +14,8 @@ MLN_LAYER_PLUGIN_SOURCE = [ "src/mbgl/plugin/plugin_layer_impl.cpp", "src/mbgl/plugin/plugin_layer_render.cpp", "src/mbgl/plugin/plugin_layer_properties.cpp", - "src/mbgl/plugin/raw_bucket.cpp", + "src/mbgl/plugin/feature_collection_bucket.cpp", + "src/mbgl/plugin/feature_collection.cpp", ] MLN_PUBLIC_GENERATED_STYLE_HEADERS = [ diff --git a/platform/darwin/app/PluginLayerExample.mm b/platform/darwin/app/PluginLayerExample.mm index 0cb01054d155..9aa8d60fc88f 100644 --- a/platform/darwin/app/PluginLayerExample.mm +++ b/platform/darwin/app/PluginLayerExample.mm @@ -7,15 +7,17 @@ @implementation PluginLayerExample +(MLNPluginLayerCapabilities *)layerCapabilities { MLNPluginLayerCapabilities *tempResult = [[MLNPluginLayerCapabilities alloc] init]; - tempResult.layerID = @"plugin-layer-test"; + tempResult.layerID = @"hudhud::gltf-model-layer"; tempResult.requiresPass3D = YES; + tempResult.supportsReadingTileFeatures = YES; return tempResult; } // The overrides --(void)onRenderLayer { - NSLog(@"PluginLayerExample: On Render Layer"); +-(void)onRenderLayer:(MLNMapView *)mapView + renderEncoder:(id)renderEncoder { + // NSLog(@"PluginLayerExample: On Render Layer"); } @@ -23,8 +25,56 @@ -(void)onUpdateLayer { } +//-(void)onBucketLoaded:(MLNRawBucket *)bucket { +// +//} + -(void)onUpdateLayerProperties:(NSDictionary *)layerProperties { - // NSLog(@"Layer Properties: %@", layerProperties); + // NSLog(@"Layer Properties: %@", layerProperties); +} + +-(void)featureLoaded:(MLNPluginLayerTileFeature *)tileFeature { + // NSLog(@"Tile Feature Properties: %@", tileFeature.featureProperties); + + for (NSValue *v in tileFeature.featureCoordinates) { + + +// NSValue *value = [NSValue valueWithBytes:&c objCType:@encode(CLLocationCoordinate2D)]; +// [featureCoordinates addObject:value]; + + CLLocationCoordinate2D coord; + [v getValue:&coord]; + + } +} + +-(void)featureUnloaded:(MLNPluginLayerTileFeature *)tileFeature { + // NSLog(@"Tile Features Unloaded: %@", tileFeature.featureProperties); + +} + + +- (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature { + + [self featureLoaded:tileFeature]; + +} + +/// Called when a set of features are loaded from the tile +- (void)onFeatureCollectionLoaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection { + //NSLog(@"Feature Collection Loaded for tile: %@", tileFeatureCollection.tileID); + for (MLNPluginLayerTileFeature *feature in tileFeatureCollection.features) { + [self featureLoaded:feature]; + } + +} + +/// Called when a set of features are unloaded because the tile goes out of scene/etc +- (void)onFeatureCollectionUnloaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection { + //NSLog(@"Feature Collection Unloaded for tile: %@", tileFeatureCollection.tileID); + for (MLNPluginLayerTileFeature *feature in tileFeatureCollection.features) { + [self featureUnloaded:feature]; + } } @end diff --git a/platform/darwin/src/MLNPluginLayer.h b/platform/darwin/src/MLNPluginLayer.h index bc4962324831..7fb38a34338c 100644 --- a/platform/darwin/src/MLNPluginLayer.h +++ b/platform/darwin/src/MLNPluginLayer.h @@ -44,11 +44,20 @@ MLN_EXPORT @interface MLNPluginLayerTileFeature : NSObject +// This is the unique feature ID in the tile source if applicable. Can be empty +@property NSString *featureID; @property NSDictionary *featureProperties; @property NSArray *featureCoordinates; @end +@interface MLNPluginLayerTileFeatureCollection : NSObject + +@property NSArray *features; +@property NSString *tileID; // z,x,y + +@end + typedef enum { MLNPluginLayerTileKindGeometry, MLNPluginLayerTileKindRaster, @@ -117,6 +126,16 @@ MLN_EXPORT /// Called when a feature is loaded from the tile - (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature; +/// Called when a set of features are loaded from the tile +/* + TODO: Think about returning that this layer doesn't care about this feature collection via a bool/etc and then + the underlying layer won't have to track this collection. + */ +- (void)onFeatureCollectionLoaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection; + +/// Called when a set of features are unloaded because the tile goes out of scene/etc +- (void)onFeatureCollectionUnloaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection; + /// Added to a map view - (void)didMoveToMapView:(MLNMapView *)mapView; diff --git a/platform/darwin/src/MLNPluginLayer.mm b/platform/darwin/src/MLNPluginLayer.mm index 712552d9f39d..73327779d8b2 100644 --- a/platform/darwin/src/MLNPluginLayer.mm +++ b/platform/darwin/src/MLNPluginLayer.mm @@ -4,6 +4,10 @@ @implementation MLNPluginLayerTileFeature @end +@implementation MLNPluginLayerTileFeatureCollection + +@end + @implementation MLNPluginLayerProperty +(MLNPluginLayerProperty *)propertyWithName:(NSString *)propertyName @@ -76,6 +80,17 @@ - (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature { // Base class does nothing } +// If the layer properties indicate that this layer has a the ability to intercept +// features, then this method will be called when a feature is loaded +- (void)onFeatureCollectionLoaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection { + // Base class does nothing +} + +/// Called when a set of features are unloaded because the tile goes out of scene/etc +- (void)onFeatureCollectionUnloaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection { + // Base class does nothing +} + /// Added to a map view - (void)didMoveToMapView:(MLNMapView *)mapView { diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index eab051c8bc1b..38faabadb6ba 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -7653,6 +7653,44 @@ - (void)triggerRepaint _mbglMap->triggerRepaint(); } +-(MLNPluginLayerTileFeature *)featureFromCore:(std::shared_ptr)feature { + + MLNPluginLayerTileFeature *tempResult = [[MLNPluginLayerTileFeature alloc] init]; + + NSMutableDictionary *tileProperties = [NSMutableDictionary dictionary]; + for (auto p: feature->_featureProperties) { + NSString *key = [NSString stringWithUTF8String:p.first.c_str()]; + NSString *value = [NSString stringWithUTF8String:p.second.c_str()]; + [tileProperties setObject:value forKey:key]; + } + + tempResult.featureProperties = [NSDictionary dictionaryWithDictionary:tileProperties]; + + NSMutableArray *featureCoordinates = [NSMutableArray array]; + for (auto & coordinateCollection: feature->_featureCoordinates) { + + for (auto & coordinate: coordinateCollection._coordinates) { + CLLocationCoordinate2D c = CLLocationCoordinate2DMake(coordinate._lat, coordinate._lon); + NSValue *value = [NSValue valueWithBytes:&c objCType:@encode(CLLocationCoordinate2D)]; + [featureCoordinates addObject:value]; + } + + } + // TODO: Need to figure out how we're going to handle multiple coordinate groups/etc + if ([featureCoordinates count] > 0) { + tempResult.featureCoordinates = [NSArray arrayWithArray:featureCoordinates]; + } + + tempResult.featureID = [NSString stringWithUTF8String:feature->_featureID.c_str()]; + + return tempResult; +} + +-(NSString *)tileIDToString:(mbgl::OverscaledTileID &)tileID { + NSString *tempResult = [NSString stringWithFormat:@"%i,%i,%i", tileID.canonical.z, tileID.canonical.x, tileID.canonical.y]; + return tempResult; +} + /** Adds a plug-in layer that is external to this library */ @@ -7678,8 +7716,11 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { } - tileKind = mbgl::style::LayerTypeInfo::TileKind::Geometry; - source = mbgl::style::LayerTypeInfo::Source::Required; + // If we read tile features, then we need to set these things + if (capabilities.supportsReadingTileFeatures) { + tileKind = mbgl::style::LayerTypeInfo::TileKind::Geometry; + source = mbgl::style::LayerTypeInfo::Source::Required; + } auto factory = std::make_unique(layerType, source, @@ -7692,7 +7733,7 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { __weak MLNMapView *weakMapView = self; Class layerClass = pluginLayerClass; - factory->_supportsRawBuckets = capabilities.supportsReadingTileFeatures; + factory->_supportsFeatureCollectionBuckets = capabilities.supportsReadingTileFeatures; factory->setOnLayerCreatedEvent([layerClass, weakMapView, pluginLayerClass](mbgl::style::PluginLayer *pluginLayer) { //NSLog(@"Creating Plugin Layer: %@", layerClass); @@ -7788,41 +7829,65 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { // If this layer can read tile features, then setup that lambda if (capabilities.supportsReadingTileFeatures) { - pluginLayerImpl->setFeatureLoadedFunction([weakPlugInLayer](const std::shared_ptr feature) { + pluginLayerImpl->setFeatureLoadedFunction([weakPlugInLayer, weakMapView](const std::shared_ptr feature) { @autoreleasepool { - MLNPluginLayerTileFeature *tileFeature = [[MLNPluginLayerTileFeature alloc] init]; + MLNPluginLayerTileFeature *tileFeature = [weakMapView featureFromCore:feature]; - NSMutableDictionary *tileProperties = [NSMutableDictionary dictionary]; - for (auto p: feature->_featureProperties) { - NSString *key = [NSString stringWithUTF8String:p.first.c_str()]; - NSString *value = [NSString stringWithUTF8String:p.second.c_str()]; - [tileProperties setObject:value forKey:key]; - } + [weakPlugInLayer onFeatureLoaded:tileFeature]; + + } + + }); + + + pluginLayerImpl->setFeatureCollectionLoadedFunction([weakPlugInLayer, weakMapView](const std::shared_ptr featureCollection) { + + @autoreleasepool { - tileFeature.featureProperties = [NSDictionary dictionaryWithDictionary:tileProperties]; + MLNPluginLayerTileFeatureCollection *collection = [[MLNPluginLayerTileFeatureCollection alloc] init]; - NSMutableArray *featureCoordinates = [NSMutableArray array]; - for (auto & coordinateCollection: feature->_featureCoordinates) { - - for (auto & coordinate: coordinateCollection._coordinates) { - CLLocationCoordinate2D c = CLLocationCoordinate2DMake(coordinate._lat, coordinate._lon); - NSValue *value = [NSValue valueWithBytes:&c objCType:@encode(CLLocationCoordinate2D)]; - [featureCoordinates addObject:value]; - } - - } - // TODO: Need to figure out how we're going to handle multiple coordinate groups/etc - if ([featureCoordinates count] > 0) { - tileFeature.featureCoordinates = [NSArray arrayWithArray:featureCoordinates]; + // Add the features + NSMutableArray *featureList = [NSMutableArray arrayWithCapacity:featureCollection->_features.size()]; + for (auto f: featureCollection->_features) { + [featureList addObject:[weakMapView featureFromCore:f]]; } + collection.features = [NSArray arrayWithArray:featureList]; + collection.tileID = [weakMapView tileIDToString:featureCollection->_featureCollectionTileID]; + + + [weakPlugInLayer onFeatureCollectionLoaded:collection]; + + } + + }); + + pluginLayerImpl->setFeatureCollectionUnloadedFunction([weakPlugInLayer, weakMapView](const std::shared_ptr featureCollection) { + + @autoreleasepool { + // TODO: Map these collections to local vars and maybe don't keep recreating it - [weakPlugInLayer onFeatureLoaded:tileFeature]; + MLNPluginLayerTileFeatureCollection *collection = [[MLNPluginLayerTileFeatureCollection alloc] init]; + + // Add the features + NSMutableArray *featureList = [NSMutableArray arrayWithCapacity:featureCollection->_features.size()]; + for (auto f: featureCollection->_features) { + [featureList addObject:[weakMapView featureFromCore:f]]; + } + collection.features = [NSArray arrayWithArray:featureList]; + collection.tileID = [weakMapView tileIDToString:featureCollection->_featureCollectionTileID]; + + [weakPlugInLayer onFeatureCollectionUnloaded:collection]; } }); + + + + + } }); diff --git a/src/mbgl/plugin/feature_collection.cpp b/src/mbgl/plugin/feature_collection.cpp new file mode 100644 index 000000000000..c5d067494a8a --- /dev/null +++ b/src/mbgl/plugin/feature_collection.cpp @@ -0,0 +1,8 @@ +// +// feature_collection.cpp +// App +// +// Created by Malcolm Toon on 7/15/25. +// + +#include "feature_collection.hpp" diff --git a/src/mbgl/plugin/feature_collection.hpp b/src/mbgl/plugin/feature_collection.hpp new file mode 100644 index 000000000000..6b170d321e09 --- /dev/null +++ b/src/mbgl/plugin/feature_collection.hpp @@ -0,0 +1,74 @@ +// +// feature_collection.hpp +// App +// +// Created by Malcolm Toon on 7/15/25. +// + +#ifndef feature_collection_hpp +#define feature_collection_hpp + +#include + +#include +#include +#include +#include + +namespace mbgl { + +namespace plugin { + +//using FillBinders = PaintPropertyBinders; +//using FillLayoutVertex = gfx::Vertex>; + +class FeatureCoordinate { +public: + FeatureCoordinate(double lat, double lon) : _lat(lat), _lon(lon) { + + } + double _lat = 0; + double _lon = 0; + double _tileX = 0; // Tile coord + double _tileY = 0; // Tile coord +}; + +// This is a list of coordinates. Broken out into it's own class because +// a raw bucket feature can have an array of these +class FeatureCoordinateCollection { +public: + std::vector _coordinates; +}; + +class Feature { +public: + Feature() {}; + enum class FeatureType { + FeatureTypeUnknown, + FeatureTypePoint, + FeatureTypeLine, + FeatureTypePolygon + }; + FeatureType _featureType = FeatureType::FeatureTypeUnknown; + std::map _featureProperties; + std::vector _featureCoordinates; + std::string _featureID; // Unique id from the data source for this + +}; + +class FeatureCollection { +public: + FeatureCollection(OverscaledTileID tileID): _featureCollectionTileID(tileID) {}; + std::vector> _features; + + // TODO: Open question about this.. should feature collections be tied to tile id? + // TODO: Question: Is overscaled the right thing or just canonical? + OverscaledTileID _featureCollectionTileID; +}; + + +} + +} + +#endif /* feature_collection_hpp */ diff --git a/src/mbgl/plugin/raw_bucket.cpp b/src/mbgl/plugin/feature_collection_bucket.cpp similarity index 58% rename from src/mbgl/plugin/raw_bucket.cpp rename to src/mbgl/plugin/feature_collection_bucket.cpp index 9322cc4b3e8a..4028ae214e38 100644 --- a/src/mbgl/plugin/raw_bucket.cpp +++ b/src/mbgl/plugin/feature_collection_bucket.cpp @@ -8,20 +8,21 @@ #include #include #include - -#include "raw_bucket.hpp" +#include #include using namespace mbgl; -RawBucket::~RawBucket() { +FeatureCollectionBucket::~FeatureCollectionBucket() { } -RawBucket::RawBucket(const BucketParameters& bucketParameters, - const std::vector>& layers) { +FeatureCollectionBucket::FeatureCollectionBucket(const BucketParameters& bucketParameters, + const std::vector>& layers): +_tileID(bucketParameters.tileID) { _layers = layers; + _featureCollection = std::make_shared(bucketParameters.tileID); } void geometryToLatLon( @@ -46,30 +47,72 @@ void geometryToLatLon( lat = 180.0 / M_PI * (2.0 * atan(exp(mercY * M_PI)) - M_PI / 2.0); } -void RawBucket::addFeature(const GeometryTileFeature& tileFeature, +std::string toString(FeatureIdentifier & v) { + // auto v = toValue(value); + + // null_value_t, uint64_t, int64_t, double, std::string> + + std::string tempResult = ""; + auto ti = v.which(); + if (ti == 0) { + return tempResult; + } else if (ti == 1) { + tempResult = std::to_string(v.get()); + } else if (ti == 2) { + tempResult = std::to_string(v.get()); + } else if (ti == 3) { + tempResult = v.get(); + } + return tempResult; + /* + if (auto iVal = v.value().getInt()) { + std::string tempResult = std::to_string(*iVal); + output.append(tempResult); + } else if (auto uIVal = v.value().getUint()) { + std::string tempResult = std::to_string(*uIVal); + output.append(tempResult); + + } else if (auto s = v.value().getString()) { + output.append("\""); + output.append(s->c_str()); + output.append("\""); + + } else if (auto d = v.value().getDouble()) { + output.append(std::to_string(*d)); + } + */ + +} + +void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, const GeometryCollection& geometeryCollection, const mbgl::ImagePositions& imagePositions, const PatternLayerMap& patternLayerMap, std::size_t size, const CanonicalTileID& tileID) { - std::shared_ptr tempFeature = std::make_shared(); + std::shared_ptr tempFeature = std::make_shared(); + + auto featureID = tileFeature.getID(); + auto featureIDString = toString(featureID); + tempFeature->_featureID = featureIDString; + switch (tileFeature.getType()) { case FeatureType::Point: - std::cout << "Adding Point" << "\n"; - tempFeature->_featureType = RawBucketFeature::FeatureType::FeatureTypePoint; + //std::cout << "Adding Point" << "\n"; + tempFeature->_featureType = plugin::Feature::FeatureType::FeatureTypePoint; break; case FeatureType::Unknown: - std::cout << "Unknown Type Found\n"; + //std::cout << "Unknown Type Found\n"; break; case FeatureType::LineString: - std::cout << "LineString Type Found\n"; - tempFeature->_featureType = RawBucketFeature::FeatureType::FeatureTypeLine; + //std::cout << "LineString Type Found\n"; + tempFeature->_featureType = plugin::Feature::FeatureType::FeatureTypeLine; break; case FeatureType::Polygon: - std::cout << "Polygon Type Found\n"; - tempFeature->_featureType = RawBucketFeature::FeatureType::FeatureTypePolygon; + //std::cout << "Polygon Type Found\n"; + tempFeature->_featureType = plugin::Feature::FeatureType::FeatureTypePolygon; break; @@ -90,17 +133,17 @@ void RawBucket::addFeature(const GeometryTileFeature& tileFeature, } else if (auto s = value.getString()) { - std::cout << "Found String: " << name << ": " << *s << "\n"; + // std::cout << "Found String: " << name << ": " << *s << "\n"; tempFeature->_featureProperties[name] = *s; } else if (auto d = value.getDouble()) { - std::cout << "Found Double: " << name << ": " << *d << "\n"; + // std::cout << "Found Double: " << name << ": " << *d << "\n"; tempFeature->_featureProperties[name] = std::to_string(*d); } else if (auto b = value.getBool()) { - std::cout << "Found Bool: " << name << ": " << *b << "\n"; + // std::cout << "Found Bool: " << name << ": " << *b << "\n"; tempFeature->_featureProperties[name] = std::to_string(*b); } else if (auto a = value.getArray()) { - std::cout << "Found Array: " << name << ": " << *b << "\n"; + // std::cout << "Found Array: " << name << ": " << *b << "\n"; tempFeature->_featureProperties[name] = std::to_string(*b); } @@ -116,7 +159,7 @@ void RawBucket::addFeature(const GeometryTileFeature& tileFeature, for (const auto& g : geometeryCollection) { // g is GeometryCoordinates - RawBucketFeatureCoordinateCollection c; + plugin::FeatureCoordinateCollection c; for (std::size_t i = 0, len = g.size(); i < len; i++) { const GeometryCoordinate& p1 = g[i]; @@ -135,7 +178,7 @@ void RawBucket::addFeature(const GeometryTileFeature& tileFeature, double lon = 0; geometryToLatLon(p1, tileID.x, tileID.y, tileID.z, lat, lon); - c._coordinates.push_back(RawBucketFeatureCoordinate(lat, lon)); + c._coordinates.push_back(plugin::FeatureCoordinate(lat, lon)); } tempFeature->_featureCoordinates.push_back(c); @@ -161,25 +204,29 @@ void RawBucket::addFeature(const GeometryTileFeature& tileFeature, // } } - _features.push_back(tempFeature); + + _featureCollection->_features.push_back(tempFeature); + // _features.push_back(tempFeature); // std::cout << "Adding Feature Type: " << tileFeature.getType() << "\n"; } -bool RawBucket::hasData() const { - return true; +bool FeatureCollectionBucket::hasData() const { + return _featureCollection->_features.size() > 0; } -void RawBucket::upload(gfx::UploadPass&) { - +void FeatureCollectionBucket::upload(gfx::UploadPass&) { + std::cout << "FeatureCollectionBucket::upload\n"; + uploaded = true; } -float RawBucket::getQueryRadius(const RenderLayer&) const { +float FeatureCollectionBucket::getQueryRadius(const RenderLayer&) const { return 0; } -void RawBucket::update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) { - +void FeatureCollectionBucket::update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) { + std::cout << "FeatureCollectionBucket::update\n"; + } diff --git a/src/mbgl/plugin/raw_bucket.hpp b/src/mbgl/plugin/feature_collection_bucket.hpp similarity index 66% rename from src/mbgl/plugin/raw_bucket.hpp rename to src/mbgl/plugin/feature_collection_bucket.hpp index 507667375d23..c78a5a811a39 100644 --- a/src/mbgl/plugin/raw_bucket.hpp +++ b/src/mbgl/plugin/feature_collection_bucket.hpp @@ -7,53 +7,48 @@ #include #include #include +#include #include -namespace mbgl { +/* + + Open Questions + + + * Should we load up a vector of these RawFeatures by tile? + * How does that interop with the render layer's update flow + * Should the call back from render layer be more of a batch thing at that update stage? + * Should there be a callback when a tile or collection of these features go out of scope? + * Should the concept of managing arrays of features be something done by the core or just + hand off the features to the plug-in layer and let it do it's thing or have the option for both? + + * How do we get to the osm id of features in the stream? Is that tileFeature.getID()? + * Is there already a set of classes or a paradigm out there that could be used to represent the + feature / feature geometry? + * What are the "binders"? + + + Thoughts + * Possibly have ability to keep tile coordinates using some kind flag + + + + */ -class BucketParameters; -class RenderFillLayer; -//using FillBinders = PaintPropertyBinders; -//using FillLayoutVertex = gfx::Vertex>; -class RawBucketFeatureCoordinate { -public: - RawBucketFeatureCoordinate(double lat, double lon) : _lat(lat), _lon(lon) { - - } - double _lat = 0; - double _lon = 0; -}; - -// This is a list of coordinates. Broken out into it's own class because -// a raw bucket feature can have an array of these -class RawBucketFeatureCoordinateCollection { -public: - std::vector _coordinates; -}; +namespace mbgl { -class RawBucketFeature { -public: - RawBucketFeature() {}; - enum class FeatureType { - FeatureTypeUnknown, - FeatureTypePoint, - FeatureTypeLine, - FeatureTypePolygon - }; - FeatureType _featureType = FeatureType::FeatureTypeUnknown; - std::map _featureProperties; - std::vector _featureCoordinates; -}; +class BucketParameters; +class RenderFillLayer; -class RawBucket final : public Bucket { +class FeatureCollectionBucket final : public Bucket { public: - ~RawBucket() override; + ~FeatureCollectionBucket() override; //using PossiblyEvaluatedLayoutProperties = style::FillLayoutProperties::PossiblyEvaluated; - RawBucket(const BucketParameters&, const std::vector>&); + FeatureCollectionBucket(const BucketParameters&, const std::vector>&); void addFeature(const GeometryTileFeature&, const GeometryCollection&, @@ -70,8 +65,12 @@ class RawBucket final : public Bucket { void update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) override; + // The tile ID + OverscaledTileID _tileID; + // Array of features - std::vector> _features; + std::shared_ptr _featureCollection = nullptr; + //std::vector> _features; std::vector> _layers; diff --git a/src/mbgl/plugin/plugin_layer.hpp b/src/mbgl/plugin/plugin_layer.hpp index 7b5ae19f349b..0767491022c5 100644 --- a/src/mbgl/plugin/plugin_layer.hpp +++ b/src/mbgl/plugin/plugin_layer.hpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace mbgl { @@ -31,8 +32,10 @@ class PluginLayer final : public Layer { using OnRenderLayer = std::function; using OnUpdateLayer = std::function; using OnUpdateLayerProperties = std::function; - using OnFeatureLoaded = std::function feature)>; - + using OnFeatureLoaded = std::function feature)>; + using OnFeatureCollectionLoaded = std::function featureCollection)>; + using OnFeatureCollectionUnloaded = std::function featureCollection)>; + void* _platformReference = nullptr; protected: diff --git a/src/mbgl/plugin/plugin_layer_factory.cpp b/src/mbgl/plugin/plugin_layer_factory.cpp index 4d68fad43fb3..1354113065e8 100644 --- a/src/mbgl/plugin/plugin_layer_factory.cpp +++ b/src/mbgl/plugin/plugin_layer_factory.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include @@ -150,8 +150,14 @@ std::unique_ptr PluginLayerFactory::createLayer(const std::string& } } - auto source = getSource(value); - std::string sourceStr = source.has_value() ? source.value() : "source"; + std::string sourceStr = "pluginLayerNoSource"; + if (_supportsFeatureCollectionBuckets) { + auto source = getSource(value); + if (source.has_value()) { + sourceStr = source.value(); + } + } + auto tempResult = std::unique_ptr(new (std::nothrow) style::PluginLayer(id, sourceStr, _layerTypeInfo, layerProperties @@ -174,8 +180,8 @@ std::unique_ptr PluginLayerFactory::createLayer(const std::string& std::unique_ptr PluginLayerFactory::createBucket( [[maybe_unused]] const BucketParameters& parameters, [[maybe_unused]] const std::vector>& layers) noexcept { - if (_supportsRawBuckets) { - return std::make_unique(parameters, layers); + if (_supportsFeatureCollectionBuckets) { + return std::make_unique(parameters, layers); } return nullptr; } diff --git a/src/mbgl/plugin/plugin_layer_factory.hpp b/src/mbgl/plugin/plugin_layer_factory.hpp index d35c5ca8bc48..7d75b7681c45 100644 --- a/src/mbgl/plugin/plugin_layer_factory.hpp +++ b/src/mbgl/plugin/plugin_layer_factory.hpp @@ -24,7 +24,7 @@ class PluginLayerFactory : public LayerFactory { mbgl::style::LayerTypeInfo::TileKind tileKind); // Set to false, but if the caller wants to support on features loaded, then set this to true - bool _supportsRawBuckets = false; + bool _supportsFeatureCollectionBuckets = false; using OnLayerCreatedEvent = std::function; void setOnLayerCreatedEvent(OnLayerCreatedEvent onLayerCreated) { _onLayerCreated = onLayerCreated; } diff --git a/src/mbgl/plugin/plugin_layer_impl.hpp b/src/mbgl/plugin/plugin_layer_impl.hpp index 6b58c42f8e7f..ee4d3982230f 100644 --- a/src/mbgl/plugin/plugin_layer_impl.hpp +++ b/src/mbgl/plugin/plugin_layer_impl.hpp @@ -102,6 +102,14 @@ class PluginLayer::Impl : public Layer::Impl { void setFeatureLoadedFunction(OnFeatureLoaded featureLoadedFunction) { _featureLoadedFunction = featureLoadedFunction; } + + void setFeatureCollectionLoadedFunction(OnFeatureCollectionLoaded featureCollectionLoadedFunction) { + _featureCollectionLoadedFunction = featureCollectionLoadedFunction; + } + + void setFeatureCollectionUnloadedFunction(OnFeatureCollectionUnloaded featureCollectionUnloadedFunction) { + _featureCollectionUnloadedFunction = featureCollectionUnloadedFunction; + } //! The property manager handles all of the custom properties for this layer type / instance PluginLayerPropertyManager _propertyManager; @@ -120,6 +128,12 @@ class PluginLayer::Impl : public Layer::Impl { //! Optional: Called when feature is loaded OnFeatureLoaded _featureLoadedFunction; + //! Optional: Called when a feature collection is loaded + OnFeatureCollectionLoaded _featureCollectionLoadedFunction; + + //! Optional: Called when a feature colleciton is unloaded from the scene (tile goes out of scene/etc) + OnFeatureCollectionUnloaded _featureCollectionUnloadedFunction; + private: LayerTypeInfo _layerTypeInfo; std::string _layerProperties; diff --git a/src/mbgl/plugin/plugin_layer_render.cpp b/src/mbgl/plugin/plugin_layer_render.cpp index 5021fa33f82f..2a3eae53e2bd 100644 --- a/src/mbgl/plugin/plugin_layer_render.cpp +++ b/src/mbgl/plugin/plugin_layer_render.cpp @@ -14,8 +14,13 @@ #include #include +// TODO: Remove #include + +#include +#include + using namespace mbgl; namespace mbgl { @@ -85,6 +90,166 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis [[maybe_unused]] const std::shared_ptr& updateParameters, [[maybe_unused]] const RenderTree& renderTree, [[maybe_unused]] UniqueChangeRequestVec& changes) { + + auto pluginLayer = static_cast(*baseImpl); + + std::vector removedTiles; + bool removeAllTiles = ((renderTiles == nullptr) || (renderTiles->empty())); + + // TODO: Remove + static int passCount = 0; + passCount++; + if (removeAllTiles) { + std::cout << passCount << ": Remove All Tiles\n"; + } + + // Get list of tiles to remove and then remove them + for (auto currentCollection: _featureCollectionByTile) { + if (removeAllTiles || !hasRenderTile(currentCollection.first)) { + removedTiles.push_back(currentCollection.first); + } + } + if (removedTiles.size() > 0) { + for (auto tileID: removedTiles) { + auto featureCollection = _featureCollectionByTile[tileID]; + if (pluginLayer._featureCollectionUnloadedFunction) { + pluginLayer._featureCollectionUnloadedFunction(featureCollection); + } + // TODO: Remove this logging + std::cout << passCount << ": Removing Feature Collection for Tile: " << (int)tileID.canonical.z << "," << tileID.canonical.x << "," << tileID.canonical.y << "\n"; + _featureCollectionByTile.erase(tileID); + } + } + + + if (renderTiles) { + if (!renderTiles->empty()) { + + auto drawPass = RenderPass::Pass3D; + + // If we're reading feature collections, go through + // and notify the plugin of any new feature collections + for (const RenderTile& tile : *renderTiles) { + const auto& tileID = tile.getOverscaledTileID(); + + if (!hasRenderTile(tileID)) { + std::cout << passCount << ": Tile was there and not anymore\n"; + } + + // TODO: Remove +// if ((tileID.canonical.x == 1289) && (tileID.canonical.y == 879)) { +// std::cout << "Found tile\n"; +// } + + const auto* optRenderData = getRenderDataForPass(tile, drawPass); + if (!optRenderData || !optRenderData->bucket || !optRenderData->bucket->hasData()) { + removeTile(drawPass, tileID); + continue; + } + const auto& renderData = *optRenderData; + auto& bucket = static_cast(*renderData.bucket); + // TODO: Remove + //std::cout << "Found Bucket\n"; + auto featureCollection = bucket._featureCollection; + if (featureCollection == nullptr) { + continue; + } + + // See if we already have this tile'a feature collection + if (_featureCollectionByTile.contains(tileID)) { + continue; + } + + _featureCollectionByTile[tileID] = featureCollection; + +// static_cast(*baseImpl); +// auto layer = static_cast(*renderData.layerProperties->baseImpl); + if (pluginLayer._featureCollectionLoadedFunction) { + if (featureCollection != nullptr) { + pluginLayer._featureCollectionLoadedFunction(featureCollection); + + // TODO: Remove logging + std::cout << passCount << ": Adding Feature Collection for Tile: " << (int)tileID.canonical.z << "," << tileID.canonical.x << "," << tileID.canonical.y << "\n"; + + } + } + + /* + + 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(drawPass, tileID); + } + setRenderTileBucketID(tileID, bucket.getID()); + */ + + } + + } + + } + + /* + if (!renderTiles || renderTiles->empty() || passes == RenderPass::None) { +// removeAllDrawables(); + return; + } + + // Set up a layer group + if (!layerGroup) { + if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, + 64, // initialCapacity= + getID())) { + setLayerGroup(std::move(layerGroup_), changes); + } else { + return; + } + } + + auto* tileLayerGroup = static_cast(layerGroup.get()); + +// const auto& evaluated = static_cast(*evaluatedProperties).evaluated; + + constexpr auto drawPass = RenderPass::Translucent; + + for (const RenderTile& tile : *renderTiles) { + const auto& tileID = tile.getOverscaledTileID(); + + const auto* optRenderData = getRenderDataForPass(tile, drawPass); + if (!optRenderData || !optRenderData->bucket || !optRenderData->bucket->hasData()) { + removeTile(drawPass, tileID); + continue; + } + + const auto& renderData = *optRenderData; + auto& bucket = static_cast(*renderData.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(drawPass, tileID); + } + setRenderTileBucketID(tileID, bucket.getID()); + } + + */ + + + + + + + + + + + + + + + + // create layer group if (!layerGroup) { if (auto layerGroup_ = context.createLayerGroup(layerIndex, /*initialCapacity=*/1, getID())) { @@ -128,6 +293,15 @@ void RenderPluginLayer::render(PaintParameters& paintParameters) { } void RenderPluginLayer::prepare(const LayerPrepareParameters& layerParameters) { + + // This check is here because base prepare will assert on these and crash + if (layerParameters.source != nullptr) { + if (layerParameters.source->isEnabled()) { + RenderLayer::prepare(layerParameters); + } + } + + if (_updateFunction) { _updateFunction(layerParameters); } @@ -163,6 +337,20 @@ void RenderPluginLayer::evaluate(const PropertyEvaluationParameters& parameters) std::string jsonProperties = pm.propertiesAsJSON(); i->_updateLayerPropertiesFunction(jsonProperties); + + + auto properties = makeMutable(staticImmutableCast(baseImpl)); + passes = RenderPass::Pass3D; +// passes = RenderPass::Pass3D; (evaluated.get().constantOr(1.0) > 0 && +// evaluated.get().constantOr(Color::black()).a > 0 && +// evaluated.get().constantOr(1.0) > 0) +// ? RenderPass::Translucent +// : RenderPass::None; + properties->renderPasses = mbgl::underlying_type(passes); + evaluatedProperties = std::move(properties); + + + } bool RenderPluginLayer::hasTransition() const { @@ -188,7 +376,8 @@ void RenderPluginLayer::layerChanged([[maybe_unused]] const TransitionParameters /// Remove all drawables for the tile from the layer group /// @return The number of drawables actually removed. -std::size_t RenderPluginLayer::removeTile([[maybe_unused]] RenderPass, [[maybe_unused]] const OverscaledTileID&) { +std::size_t RenderPluginLayer::removeTile([[maybe_unused]] RenderPass renderPass, + [[maybe_unused]] const OverscaledTileID& tileID) { return 0; } diff --git a/src/mbgl/plugin/plugin_layer_render.hpp b/src/mbgl/plugin/plugin_layer_render.hpp index cc2ea2db7a6e..847aea6003f8 100644 --- a/src/mbgl/plugin/plugin_layer_render.hpp +++ b/src/mbgl/plugin/plugin_layer_render.hpp @@ -5,6 +5,7 @@ #include #include +#include #include namespace mbgl { @@ -67,6 +68,9 @@ class RenderPluginLayer final : public RenderLayer { style::PluginLayer::OnUpdateLayer _updateFunction = nullptr; style::PluginLayer::OnUpdateLayerProperties _updateLayerPropertiesFunction = nullptr; + + std::map> _featureCollectionByTile; + }; } // namespace mbgl diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 127355fa769d..9805979f524a 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -373,11 +373,6 @@ std::unique_ptr RenderOrchestrator::createRenderTree( for (std::size_t index = 0; index < orderedLayers.size(); ++index) { RenderLayer& layer = orderedLayers[index]; const auto* layerInfo = layer.baseImpl->getTypeInfo(); - std::string s1(layerInfo->type); - //std::cout << " -> " << s1 << "\n"; -// if (s1 == "hudhud::gltf-model-layer") { -// std::cout << "Found plugin\n"; -// } const bool layerIsVisible = layer.baseImpl->visibility != style::VisibilityType::None; const bool zoomFitsLayer = layer.supportsZoom(zoomHistory.lastZoom); renderTreeParameters->has3D |= (layerInfo->pass3d == LayerTypeInfo::Pass3D::Required); diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 1d71c8b99084..6d6c6f7025d2 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -35,7 +35,7 @@ LayerRenderData* GeometryTile::LayoutResult::getLayerRenderData(const style::Lay return nullptr; } LayerRenderData& result = it->second; - if (result.layerProperties->baseImpl->getTypeInfo() != layerImpl.getTypeInfo()) { + if (!layerTypeInfoEquals(result.layerProperties->baseImpl->getTypeInfo(), layerImpl.getTypeInfo())) { // Layer data might be outdated, see issue #12432. return nullptr; } From 4e2f4e692226dc136f973024fdb02fdf8440557a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Fri, 25 Jul 2025 10:48:48 -0400 Subject: [PATCH 03/49] Updates --- platform/darwin/app/PluginLayerExample.mm | 6 +++--- platform/darwin/app/PluginLayerTestStyle.json | 7 +++++++ platform/ios/app/MBXViewController.mm | 11 ++++++----- src/mbgl/plugin/plugin_layer_render.cpp | 13 ++++++++++--- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/platform/darwin/app/PluginLayerExample.mm b/platform/darwin/app/PluginLayerExample.mm index 9aa8d60fc88f..16df1dd440da 100644 --- a/platform/darwin/app/PluginLayerExample.mm +++ b/platform/darwin/app/PluginLayerExample.mm @@ -7,7 +7,7 @@ @implementation PluginLayerExample +(MLNPluginLayerCapabilities *)layerCapabilities { MLNPluginLayerCapabilities *tempResult = [[MLNPluginLayerCapabilities alloc] init]; - tempResult.layerID = @"hudhud::gltf-model-layer"; + tempResult.layerID = @"maplibre::filter_features"; tempResult.requiresPass3D = YES; tempResult.supportsReadingTileFeatures = YES; return tempResult; @@ -17,7 +17,7 @@ +(MLNPluginLayerCapabilities *)layerCapabilities { // The overrides -(void)onRenderLayer:(MLNMapView *)mapView renderEncoder:(id)renderEncoder { - // NSLog(@"PluginLayerExample: On Render Layer"); + //NSLog(@"PluginLayerExample: On Render Layer"); } @@ -34,7 +34,7 @@ -(void)onUpdateLayerProperties:(NSDictionary *)layerProperties { } -(void)featureLoaded:(MLNPluginLayerTileFeature *)tileFeature { - // NSLog(@"Tile Feature Properties: %@", tileFeature.featureProperties); + NSLog(@"Tile Feature (id:%@) Properties: %@", tileFeature.featureID, tileFeature.featureProperties); for (NSValue *v in tileFeature.featureCoordinates) { diff --git a/platform/darwin/app/PluginLayerTestStyle.json b/platform/darwin/app/PluginLayerTestStyle.json index 25ce408bd77f..826236d2a135 100644 --- a/platform/darwin/app/PluginLayerTestStyle.json +++ b/platform/darwin/app/PluginLayerTestStyle.json @@ -583,6 +583,13 @@ ] } }, + { "id": "centroid-features", + "type": "maplibre::filter_features", + "source": "maplibre", + "source-layer": "centroids", + "maxzoom": 24, + "minzoom": 1 + }, { "id": "crimea-fill", "type": "fill", diff --git a/platform/ios/app/MBXViewController.mm b/platform/ios/app/MBXViewController.mm index 4c13a767ea51..3e1a02568f11 100644 --- a/platform/ios/app/MBXViewController.mm +++ b/platform/ios/app/MBXViewController.mm @@ -2332,17 +2332,18 @@ - (void)setStyles - - /// Style that does not require an `apiKey` nor any further configuration - [self.styleNames addObject:@"MapLibre Basic"]; - [self.styleURLs addObject:[NSURL URLWithString:@"https://demotiles.maplibre.org/style.json"]]; - /// This is hte same style as above but copied locally and the three instances of the metal plug-in layer added to the style /// Look for "type": "plugin-layer-metal-rendering" in the PluginLayerTestStyle.json for an example of how the layer is defined [self.styleNames addObject:@"MapLibre Basic - Local With Plugin"]; NSURL *url = [[NSBundle mainBundle] URLForResource:@"PluginLayerTestStyle.json" withExtension:nil]; [self.styleURLs addObject:url]; + + /// Style that does not require an `apiKey` nor any further configuration + [self.styleNames addObject:@"MapLibre Basic"]; + [self.styleURLs addObject:[NSURL URLWithString:@"https://demotiles.maplibre.org/style.json"]]; + + /// Add MapLibre Styles if an `apiKey` exists NSString* apiKey = [MLNSettings apiKey]; if (apiKey.length) diff --git a/src/mbgl/plugin/plugin_layer_render.cpp b/src/mbgl/plugin/plugin_layer_render.cpp index 2a3eae53e2bd..e36e6ef2208e 100644 --- a/src/mbgl/plugin/plugin_layer_render.cpp +++ b/src/mbgl/plugin/plugin_layer_render.cpp @@ -16,7 +16,7 @@ // TODO: Remove #include - +// #define C_LOG_TILES 1 #include #include @@ -97,12 +97,14 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis bool removeAllTiles = ((renderTiles == nullptr) || (renderTiles->empty())); // TODO: Remove +#ifdef C_LOG_TILES static int passCount = 0; passCount++; if (removeAllTiles) { std::cout << passCount << ": Remove All Tiles\n"; } - +#endif + // Get list of tiles to remove and then remove them for (auto currentCollection: _featureCollectionByTile) { if (removeAllTiles || !hasRenderTile(currentCollection.first)) { @@ -115,8 +117,10 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis if (pluginLayer._featureCollectionUnloadedFunction) { pluginLayer._featureCollectionUnloadedFunction(featureCollection); } +#ifdef C_LOG_TILES // TODO: Remove this logging std::cout << passCount << ": Removing Feature Collection for Tile: " << (int)tileID.canonical.z << "," << tileID.canonical.x << "," << tileID.canonical.y << "\n"; +#endif _featureCollectionByTile.erase(tileID); } } @@ -133,7 +137,9 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis const auto& tileID = tile.getOverscaledTileID(); if (!hasRenderTile(tileID)) { +#ifdef C_LOG_TILES std::cout << passCount << ": Tile was there and not anymore\n"; +#endif } // TODO: Remove @@ -167,9 +173,10 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis if (pluginLayer._featureCollectionLoadedFunction) { if (featureCollection != nullptr) { pluginLayer._featureCollectionLoadedFunction(featureCollection); - +#ifdef C_LOG_TILES // TODO: Remove logging std::cout << passCount << ": Adding Feature Collection for Tile: " << (int)tileID.canonical.z << "," << tileID.canonical.x << "," << tileID.canonical.y << "\n"; +#endif } } From 20b79859276d4585ae66369264eddbead85a0477 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 14:52:17 +0000 Subject: [PATCH 04/49] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- platform/darwin/app/PluginLayerExample.mm | 16 +- platform/darwin/src/MLNPluginLayer.h | 6 +- platform/darwin/src/MLNPluginLayer.mm | 4 +- platform/ios/app/MBXViewController.mm | 2 +- platform/ios/src/MLNMapView.mm | 60 +++---- src/mbgl/plugin/feature_collection.hpp | 21 ++- src/mbgl/plugin/feature_collection_bucket.cpp | 170 ++++++++---------- src/mbgl/plugin/feature_collection_bucket.hpp | 26 ++- src/mbgl/plugin/plugin_layer.hpp | 7 +- src/mbgl/plugin/plugin_layer_factory.cpp | 17 +- src/mbgl/plugin/plugin_layer_factory.hpp | 2 +- src/mbgl/plugin/plugin_layer_impl.hpp | 8 +- src/mbgl/plugin/plugin_layer_render.cpp | 94 ++++------ src/mbgl/plugin/plugin_layer_render.hpp | 3 +- src/mbgl/tile/geometry_tile_worker.cpp | 6 +- 15 files changed, 199 insertions(+), 243 deletions(-) diff --git a/platform/darwin/app/PluginLayerExample.mm b/platform/darwin/app/PluginLayerExample.mm index 16df1dd440da..13c40d8e3794 100644 --- a/platform/darwin/app/PluginLayerExample.mm +++ b/platform/darwin/app/PluginLayerExample.mm @@ -26,7 +26,7 @@ -(void)onUpdateLayer { } //-(void)onBucketLoaded:(MLNRawBucket *)bucket { -// +// //} -(void)onUpdateLayerProperties:(NSDictionary *)layerProperties { @@ -35,29 +35,29 @@ -(void)onUpdateLayerProperties:(NSDictionary *)layerProperties { -(void)featureLoaded:(MLNPluginLayerTileFeature *)tileFeature { NSLog(@"Tile Feature (id:%@) Properties: %@", tileFeature.featureID, tileFeature.featureProperties); - + for (NSValue *v in tileFeature.featureCoordinates) { - + // NSValue *value = [NSValue valueWithBytes:&c objCType:@encode(CLLocationCoordinate2D)]; // [featureCoordinates addObject:value]; CLLocationCoordinate2D coord; [v getValue:&coord]; - + } } -(void)featureUnloaded:(MLNPluginLayerTileFeature *)tileFeature { // NSLog(@"Tile Features Unloaded: %@", tileFeature.featureProperties); - + } - (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature { - + [self featureLoaded:tileFeature]; - + } /// Called when a set of features are loaded from the tile @@ -66,7 +66,7 @@ - (void)onFeatureCollectionLoaded:(MLNPluginLayerTileFeatureCollection *)tileFea for (MLNPluginLayerTileFeature *feature in tileFeatureCollection.features) { [self featureLoaded:feature]; } - + } /// Called when a set of features are unloaded because the tile goes out of scene/etc diff --git a/platform/darwin/src/MLNPluginLayer.h b/platform/darwin/src/MLNPluginLayer.h index 7fb38a34338c..5b3fe06f7cca 100644 --- a/platform/darwin/src/MLNPluginLayer.h +++ b/platform/darwin/src/MLNPluginLayer.h @@ -54,7 +54,7 @@ MLN_EXPORT @interface MLNPluginLayerTileFeatureCollection : NSObject @property NSArray *features; -@property NSString *tileID; // z,x,y +@property NSString *tileID; // z,x,y @end @@ -128,8 +128,8 @@ MLN_EXPORT /// Called when a set of features are loaded from the tile /* - TODO: Think about returning that this layer doesn't care about this feature collection via a bool/etc and then - the underlying layer won't have to track this collection. + TODO: Think about returning that this layer doesn't care about this feature collection via a + bool/etc and then the underlying layer won't have to track this collection. */ - (void)onFeatureCollectionLoaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection; diff --git a/platform/darwin/src/MLNPluginLayer.mm b/platform/darwin/src/MLNPluginLayer.mm index 73327779d8b2..05de4517e1ce 100644 --- a/platform/darwin/src/MLNPluginLayer.mm +++ b/platform/darwin/src/MLNPluginLayer.mm @@ -73,7 +73,7 @@ - (void)onUpdateLayer:(MLNPluginLayerDrawingContext)drawingContext { -(void)onUpdateLayerProperties:(NSDictionary *)layerProperties { // Base class does nothing } - + // If the layer properties indicate that this layer has a the ability to intercept // features, then this method will be called when a feature is loaded - (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature { @@ -97,7 +97,7 @@ - (void)didMoveToMapView:(MLNMapView *)mapView { // Base class does nothing } - + @end diff --git a/platform/ios/app/MBXViewController.mm b/platform/ios/app/MBXViewController.mm index 3e1a02568f11..b571f0202a4a 100644 --- a/platform/ios/app/MBXViewController.mm +++ b/platform/ios/app/MBXViewController.mm @@ -2338,7 +2338,7 @@ - (void)setStyles NSURL *url = [[NSBundle mainBundle] URLForResource:@"PluginLayerTestStyle.json" withExtension:nil]; [self.styleURLs addObject:url]; - + /// Style that does not require an `apiKey` nor any further configuration [self.styleNames addObject:@"MapLibre Basic"]; [self.styleURLs addObject:[NSURL URLWithString:@"https://demotiles.maplibre.org/style.json"]]; diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index 38faabadb6ba..9e7f43f411dd 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -7654,35 +7654,35 @@ - (void)triggerRepaint } -(MLNPluginLayerTileFeature *)featureFromCore:(std::shared_ptr)feature { - + MLNPluginLayerTileFeature *tempResult = [[MLNPluginLayerTileFeature alloc] init]; - + NSMutableDictionary *tileProperties = [NSMutableDictionary dictionary]; for (auto p: feature->_featureProperties) { NSString *key = [NSString stringWithUTF8String:p.first.c_str()]; NSString *value = [NSString stringWithUTF8String:p.second.c_str()]; [tileProperties setObject:value forKey:key]; } - + tempResult.featureProperties = [NSDictionary dictionaryWithDictionary:tileProperties]; - + NSMutableArray *featureCoordinates = [NSMutableArray array]; for (auto & coordinateCollection: feature->_featureCoordinates) { - + for (auto & coordinate: coordinateCollection._coordinates) { CLLocationCoordinate2D c = CLLocationCoordinate2DMake(coordinate._lat, coordinate._lon); NSValue *value = [NSValue valueWithBytes:&c objCType:@encode(CLLocationCoordinate2D)]; [featureCoordinates addObject:value]; } - + } // TODO: Need to figure out how we're going to handle multiple coordinate groups/etc if ([featureCoordinates count] > 0) { tempResult.featureCoordinates = [NSArray arrayWithArray:featureCoordinates]; } - + tempResult.featureID = [NSString stringWithUTF8String:feature->_featureID.c_str()]; - + return tempResult; } @@ -7714,8 +7714,8 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { if (capabilities.requiresPass3D) { pass3D = mbgl::style::LayerTypeInfo::Pass3D::Required; } - - + + // If we read tile features, then we need to set these things if (capabilities.supportsReadingTileFeatures) { tileKind = mbgl::style::LayerTypeInfo::TileKind::Geometry; @@ -7826,27 +7826,27 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { [weakPlugInLayer onUpdateLayerProperties:properties]; } }); - + // If this layer can read tile features, then setup that lambda if (capabilities.supportsReadingTileFeatures) { pluginLayerImpl->setFeatureLoadedFunction([weakPlugInLayer, weakMapView](const std::shared_ptr feature) { - + @autoreleasepool { MLNPluginLayerTileFeature *tileFeature = [weakMapView featureFromCore:feature]; - + [weakPlugInLayer onFeatureLoaded:tileFeature]; } - + }); - - + + pluginLayerImpl->setFeatureCollectionLoadedFunction([weakPlugInLayer, weakMapView](const std::shared_ptr featureCollection) { - + @autoreleasepool { - + MLNPluginLayerTileFeatureCollection *collection = [[MLNPluginLayerTileFeatureCollection alloc] init]; - + // Add the features NSMutableArray *featureList = [NSMutableArray arrayWithCapacity:featureCollection->_features.size()]; for (auto f: featureCollection->_features) { @@ -7855,21 +7855,21 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { collection.features = [NSArray arrayWithArray:featureList]; collection.tileID = [weakMapView tileIDToString:featureCollection->_featureCollectionTileID]; - + [weakPlugInLayer onFeatureCollectionLoaded:collection]; } - + }); - + pluginLayerImpl->setFeatureCollectionUnloadedFunction([weakPlugInLayer, weakMapView](const std::shared_ptr featureCollection) { - + @autoreleasepool { - + // TODO: Map these collections to local vars and maybe don't keep recreating it - + MLNPluginLayerTileFeatureCollection *collection = [[MLNPluginLayerTileFeatureCollection alloc] init]; - + // Add the features NSMutableArray *featureList = [NSMutableArray arrayWithCapacity:featureCollection->_features.size()]; for (auto f: featureCollection->_features) { @@ -7877,17 +7877,17 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { } collection.features = [NSArray arrayWithArray:featureList]; collection.tileID = [weakMapView tileIDToString:featureCollection->_featureCollectionTileID]; - + [weakPlugInLayer onFeatureCollectionUnloaded:collection]; } - + }); - - + + } }); diff --git a/src/mbgl/plugin/feature_collection.hpp b/src/mbgl/plugin/feature_collection.hpp index 6b170d321e09..8b75ebada98f 100644 --- a/src/mbgl/plugin/feature_collection.hpp +++ b/src/mbgl/plugin/feature_collection.hpp @@ -19,14 +19,14 @@ namespace mbgl { namespace plugin { -//using FillBinders = PaintPropertyBinders; -//using FillLayoutVertex = gfx::Vertex>; +// using FillBinders = PaintPropertyBinders; +// using FillLayoutVertex = gfx::Vertex>; class FeatureCoordinate { public: - FeatureCoordinate(double lat, double lon) : _lat(lat), _lon(lon) { - - } + FeatureCoordinate(double lat, double lon) + : _lat(lat), + _lon(lon) {} double _lat = 0; double _lon = 0; double _tileX = 0; // Tile coord @@ -53,22 +53,21 @@ class Feature { std::map _featureProperties; std::vector _featureCoordinates; std::string _featureID; // Unique id from the data source for this - }; class FeatureCollection { public: - FeatureCollection(OverscaledTileID tileID): _featureCollectionTileID(tileID) {}; + FeatureCollection(OverscaledTileID tileID) + : _featureCollectionTileID(tileID) {}; std::vector> _features; - + // TODO: Open question about this.. should feature collections be tied to tile id? // TODO: Question: Is overscaled the right thing or just canonical? OverscaledTileID _featureCollectionTileID; }; +} // namespace plugin -} - -} +} // namespace mbgl #endif /* feature_collection_hpp */ diff --git a/src/mbgl/plugin/feature_collection_bucket.cpp b/src/mbgl/plugin/feature_collection_bucket.cpp index 4028ae214e38..f4797a2b88f2 100644 --- a/src/mbgl/plugin/feature_collection_bucket.cpp +++ b/src/mbgl/plugin/feature_collection_bucket.cpp @@ -14,44 +14,43 @@ using namespace mbgl; -FeatureCollectionBucket::~FeatureCollectionBucket() { - -} +FeatureCollectionBucket::~FeatureCollectionBucket() {} FeatureCollectionBucket::FeatureCollectionBucket(const BucketParameters& bucketParameters, - const std::vector>& layers): -_tileID(bucketParameters.tileID) { + const std::vector>& layers) + : _tileID(bucketParameters.tileID) { _layers = layers; _featureCollection = std::make_shared(bucketParameters.tileID); } -void geometryToLatLon( - const GeometryCoordinate& coord, - int tileX, int tileY, int zoom, - double& lat, double& lon, - int extent = 8192, - int tileSize = 512 -) { - double px = coord.x / double(extent); - double py = coord.y / double(extent); +void geometryToLatLon(const GeometryCoordinate& coord, + int tileX, + int tileY, + int zoom, + double& lat, + double& lon, + int extent = 8192, + int tileSize = 512) { + double px = coord.x / double(extent); + double py = coord.y / double(extent); - double worldPixelX = (tileX + px) * tileSize; - double worldPixelY = (tileY + py) * tileSize; + double worldPixelX = (tileX + px) * tileSize; + double worldPixelY = (tileY + py) * tileSize; - double worldSize = tileSize * (1 << zoom); + double worldSize = tileSize * (1 << zoom); - double mercX = worldPixelX / worldSize * 2.0 - 1.0; - double mercY = 1.0 - worldPixelY / worldSize * 2.0; + double mercX = worldPixelX / worldSize * 2.0 - 1.0; + double mercY = 1.0 - worldPixelY / worldSize * 2.0; - lon = mercX * 180.0; - lat = 180.0 / M_PI * (2.0 * atan(exp(mercY * M_PI)) - M_PI / 2.0); + lon = mercX * 180.0; + lat = 180.0 / M_PI * (2.0 * atan(exp(mercY * M_PI)) - M_PI / 2.0); } -std::string toString(FeatureIdentifier & v) { - // auto v = toValue(value); - +std::string toString(FeatureIdentifier& v) { + // auto v = toValue(value); + // null_value_t, uint64_t, int64_t, double, std::string> - + std::string tempResult = ""; auto ti = v.which(); if (ti == 0) { @@ -81,49 +80,43 @@ std::string toString(FeatureIdentifier & v) { output.append(std::to_string(*d)); } */ - } void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, - const GeometryCollection& geometeryCollection, - const mbgl::ImagePositions& imagePositions, - const PatternLayerMap& patternLayerMap, - std::size_t size, - const CanonicalTileID& tileID) { - + const GeometryCollection& geometeryCollection, + const mbgl::ImagePositions& imagePositions, + const PatternLayerMap& patternLayerMap, + std::size_t size, + const CanonicalTileID& tileID) { std::shared_ptr tempFeature = std::make_shared(); - + auto featureID = tileFeature.getID(); auto featureIDString = toString(featureID); tempFeature->_featureID = featureIDString; - - + switch (tileFeature.getType()) { case FeatureType::Point: - //std::cout << "Adding Point" << "\n"; + // std::cout << "Adding Point" << "\n"; tempFeature->_featureType = plugin::Feature::FeatureType::FeatureTypePoint; break; case FeatureType::Unknown: - //std::cout << "Unknown Type Found\n"; + // std::cout << "Unknown Type Found\n"; break; case FeatureType::LineString: - //std::cout << "LineString Type Found\n"; + // std::cout << "LineString Type Found\n"; tempFeature->_featureType = plugin::Feature::FeatureType::FeatureTypeLine; break; case FeatureType::Polygon: - //std::cout << "Polygon Type Found\n"; + // std::cout << "Polygon Type Found\n"; tempFeature->_featureType = plugin::Feature::FeatureType::FeatureTypePolygon; break; - - } - + auto pm = tileFeature.getProperties(); - for (auto p: pm) { - + for (auto p : pm) { auto name = p.first; mapbox::feature::value value = p.second; - + if (auto iVal = value.getInt()) { std::cout << "Found Int: " << name << ": " << *iVal << "\n"; tempFeature->_featureProperties[name] = std::to_string(*iVal); @@ -132,84 +125,74 @@ void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, tempFeature->_featureProperties[name] = std::to_string(*uIVal); } else if (auto s = value.getString()) { - - // std::cout << "Found String: " << name << ": " << *s << "\n"; + // std::cout << "Found String: " << name << ": " << *s << "\n"; tempFeature->_featureProperties[name] = *s; } else if (auto d = value.getDouble()) { - // std::cout << "Found Double: " << name << ": " << *d << "\n"; + // std::cout << "Found Double: " << name << ": " << *d << "\n"; tempFeature->_featureProperties[name] = std::to_string(*d); } else if (auto b = value.getBool()) { - // std::cout << "Found Bool: " << name << ": " << *b << "\n"; + // std::cout << "Found Bool: " << name << ": " << *b << "\n"; tempFeature->_featureProperties[name] = std::to_string(*b); } else if (auto a = value.getArray()) { - // std::cout << "Found Array: " << name << ": " << *b << "\n"; + // std::cout << "Found Array: " << name << ": " << *b << "\n"; tempFeature->_featureProperties[name] = std::to_string(*b); } - - -// DECLARE_VALUE_TYPE_ACCESOR(Array, array_type) -// DECLARE_VALUE_TYPE_ACCESOR(Object, object_type) - + + // DECLARE_VALUE_TYPE_ACCESOR(Array, array_type) + // DECLARE_VALUE_TYPE_ACCESOR(Object, object_type) } - + LatLngBounds b(tileID); - - - + for (const auto& g : geometeryCollection) { // g is GeometryCoordinates plugin::FeatureCoordinateCollection c; for (std::size_t i = 0, len = g.size(); i < len; i++) { const GeometryCoordinate& p1 = g[i]; - + auto d = b.west(); - -// auto c = project( - - -// void geometryToLatLon( -// const GeometryCoordinate& coord, -// int tileX, int tileY, int zoom, -// double& lat, double& lon, -// int extent = 8192, -// int tileSize = 512 + + // auto c = project( + + // void geometryToLatLon( + // const GeometryCoordinate& coord, + // int tileX, int tileY, int zoom, + // double& lat, double& lon, + // int extent = 8192, + // int tileSize = 512 double lat = 0; double lon = 0; geometryToLatLon(p1, tileID.x, tileID.y, tileID.z, lat, lon); - + c._coordinates.push_back(plugin::FeatureCoordinate(lat, lon)); } tempFeature->_featureCoordinates.push_back(c); - } - - for (auto l: _layers) { + + for (auto l : _layers) { auto bi = l->baseImpl; auto bip = bi.get(); - auto pluginLayer = static_cast(bip); + auto pluginLayer = static_cast(bip); if (pluginLayer != nullptr) { if (pluginLayer->_featureLoadedFunction != nullptr) { pluginLayer->_featureLoadedFunction(tempFeature); } - } - // auto pluginLayer = std::dynamic_pointer_cast>(bi); - -// auto pluginLayer = std::dynamic_pointer_cast(l->baseImpl); -// if (pluginLayer != nullptr) { -// if (pluginLayer->_featureLoadedFunction != nullptr) { -// pluginLayer->_featureLoadedFunction(tempFeature); -// } -// } + // auto pluginLayer = std::dynamic_pointer_cast>(bi); + + // auto pluginLayer = std::dynamic_pointer_cast(l->baseImpl); + // if (pluginLayer != nullptr) { + // if (pluginLayer->_featureLoadedFunction != nullptr) { + // pluginLayer->_featureLoadedFunction(tempFeature); + // } + // } } - - + _featureCollection->_features.push_back(tempFeature); - // _features.push_back(tempFeature); - -// std::cout << "Adding Feature Type: " << tileFeature.getType() << "\n"; - + // _features.push_back(tempFeature); + + // std::cout << "Adding Feature Type: " << tileFeature.getType() << "\n"; } bool FeatureCollectionBucket::hasData() const { @@ -225,8 +208,9 @@ float FeatureCollectionBucket::getQueryRadius(const RenderLayer&) const { return 0; } -void FeatureCollectionBucket::update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) { +void FeatureCollectionBucket::update(const FeatureStates&, + const GeometryTileLayer&, + const std::string&, + const ImagePositions&) { std::cout << "FeatureCollectionBucket::update\n"; - } - diff --git a/src/mbgl/plugin/feature_collection_bucket.hpp b/src/mbgl/plugin/feature_collection_bucket.hpp index c78a5a811a39..ec5ae03e7a0a 100644 --- a/src/mbgl/plugin/feature_collection_bucket.hpp +++ b/src/mbgl/plugin/feature_collection_bucket.hpp @@ -12,32 +12,30 @@ #include /* - + Open Questions - - + + * Should we load up a vector of these RawFeatures by tile? * How does that interop with the render layer's update flow * Should the call back from render layer be more of a batch thing at that update stage? * Should there be a callback when a tile or collection of these features go out of scope? * Should the concept of managing arrays of features be something done by the core or just hand off the features to the plug-in layer and let it do it's thing or have the option for both? - + * How do we get to the osm id of features in the stream? Is that tileFeature.getID()? * Is there already a set of classes or a paradigm out there that could be used to represent the feature / feature geometry? * What are the "binders"? - - + + Thoughts * Possibly have ability to keep tile coordinates using some kind flag - - - - */ + */ + namespace mbgl { class BucketParameters; @@ -46,7 +44,7 @@ class RenderFillLayer; class FeatureCollectionBucket final : public Bucket { public: ~FeatureCollectionBucket() override; - //using PossiblyEvaluatedLayoutProperties = style::FillLayoutProperties::PossiblyEvaluated; + // using PossiblyEvaluatedLayoutProperties = style::FillLayoutProperties::PossiblyEvaluated; FeatureCollectionBucket(const BucketParameters&, const std::vector>&); @@ -70,10 +68,10 @@ class FeatureCollectionBucket final : public Bucket { // Array of features std::shared_ptr _featureCollection = nullptr; - //std::vector> _features; - + // std::vector> _features; + std::vector> _layers; - + /* static FillLayoutVertex layoutVertex(Point p) { return FillLayoutVertex{{{p.x, p.y}}}; } diff --git a/src/mbgl/plugin/plugin_layer.hpp b/src/mbgl/plugin/plugin_layer.hpp index 0767491022c5..5e6bb9adb06d 100644 --- a/src/mbgl/plugin/plugin_layer.hpp +++ b/src/mbgl/plugin/plugin_layer.hpp @@ -11,7 +11,6 @@ class RawBucketFeature; namespace style { - class PluginLayer final : public Layer { public: PluginLayer(const std::string& layerID, @@ -33,8 +32,10 @@ class PluginLayer final : public Layer { using OnUpdateLayer = std::function; using OnUpdateLayerProperties = std::function; using OnFeatureLoaded = std::function feature)>; - using OnFeatureCollectionLoaded = std::function featureCollection)>; - using OnFeatureCollectionUnloaded = std::function featureCollection)>; + using OnFeatureCollectionLoaded = + std::function featureCollection)>; + using OnFeatureCollectionUnloaded = + std::function featureCollection)>; void* _platformReference = nullptr; diff --git a/src/mbgl/plugin/plugin_layer_factory.cpp b/src/mbgl/plugin/plugin_layer_factory.cpp index 1354113065e8..a30db5105ee8 100644 --- a/src/mbgl/plugin/plugin_layer_factory.cpp +++ b/src/mbgl/plugin/plugin_layer_factory.cpp @@ -157,12 +157,11 @@ std::unique_ptr PluginLayerFactory::createLayer(const std::string& sourceStr = source.value(); } } - - auto tempResult = std::unique_ptr(new (std::nothrow) - style::PluginLayer(id, sourceStr, _layerTypeInfo, layerProperties - //,*customProperties - )); + auto tempResult = std::unique_ptr(new (std::nothrow) style::PluginLayer( + id, sourceStr, _layerTypeInfo, layerProperties + //,*customProperties + )); if (_onLayerCreated != nullptr) { auto layerRaw = tempResult.get(); @@ -180,10 +179,10 @@ std::unique_ptr PluginLayerFactory::createLayer(const std::string& std::unique_ptr PluginLayerFactory::createBucket( [[maybe_unused]] const BucketParameters& parameters, [[maybe_unused]] const std::vector>& layers) noexcept { - if (_supportsFeatureCollectionBuckets) { - return std::make_unique(parameters, layers); - } - return nullptr; + if (_supportsFeatureCollectionBuckets) { + return std::make_unique(parameters, layers); + } + return nullptr; } std::unique_ptr PluginLayerFactory::createRenderLayer(Immutable impl) noexcept { diff --git a/src/mbgl/plugin/plugin_layer_factory.hpp b/src/mbgl/plugin/plugin_layer_factory.hpp index 7d75b7681c45..e2d3aa4e392b 100644 --- a/src/mbgl/plugin/plugin_layer_factory.hpp +++ b/src/mbgl/plugin/plugin_layer_factory.hpp @@ -25,7 +25,7 @@ class PluginLayerFactory : public LayerFactory { // Set to false, but if the caller wants to support on features loaded, then set this to true bool _supportsFeatureCollectionBuckets = false; - + using OnLayerCreatedEvent = std::function; void setOnLayerCreatedEvent(OnLayerCreatedEvent onLayerCreated) { _onLayerCreated = onLayerCreated; } diff --git a/src/mbgl/plugin/plugin_layer_impl.hpp b/src/mbgl/plugin/plugin_layer_impl.hpp index ee4d3982230f..7b79399ee07b 100644 --- a/src/mbgl/plugin/plugin_layer_impl.hpp +++ b/src/mbgl/plugin/plugin_layer_impl.hpp @@ -102,7 +102,7 @@ class PluginLayer::Impl : public Layer::Impl { void setFeatureLoadedFunction(OnFeatureLoaded featureLoadedFunction) { _featureLoadedFunction = featureLoadedFunction; } - + void setFeatureCollectionLoadedFunction(OnFeatureCollectionLoaded featureCollectionLoadedFunction) { _featureCollectionLoadedFunction = featureCollectionLoadedFunction; } @@ -127,13 +127,13 @@ class PluginLayer::Impl : public Layer::Impl { //! Optional: Called when feature is loaded OnFeatureLoaded _featureLoadedFunction; - + //! Optional: Called when a feature collection is loaded OnFeatureCollectionLoaded _featureCollectionLoadedFunction; - + //! Optional: Called when a feature colleciton is unloaded from the scene (tile goes out of scene/etc) OnFeatureCollectionUnloaded _featureCollectionUnloadedFunction; - + private: LayerTypeInfo _layerTypeInfo; std::string _layerProperties; diff --git a/src/mbgl/plugin/plugin_layer_render.cpp b/src/mbgl/plugin/plugin_layer_render.cpp index e36e6ef2208e..64cd64f547d7 100644 --- a/src/mbgl/plugin/plugin_layer_render.cpp +++ b/src/mbgl/plugin/plugin_layer_render.cpp @@ -90,12 +90,11 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis [[maybe_unused]] const std::shared_ptr& updateParameters, [[maybe_unused]] const RenderTree& renderTree, [[maybe_unused]] UniqueChangeRequestVec& changes) { - - auto pluginLayer = static_cast(*baseImpl); + auto pluginLayer = static_cast(*baseImpl); std::vector removedTiles; bool removeAllTiles = ((renderTiles == nullptr) || (renderTiles->empty())); - + // TODO: Remove #ifdef C_LOG_TILES static int passCount = 0; @@ -104,33 +103,32 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis std::cout << passCount << ": Remove All Tiles\n"; } #endif - + // Get list of tiles to remove and then remove them - for (auto currentCollection: _featureCollectionByTile) { + for (auto currentCollection : _featureCollectionByTile) { if (removeAllTiles || !hasRenderTile(currentCollection.first)) { removedTiles.push_back(currentCollection.first); } } if (removedTiles.size() > 0) { - for (auto tileID: removedTiles) { + for (auto tileID : removedTiles) { auto featureCollection = _featureCollectionByTile[tileID]; if (pluginLayer._featureCollectionUnloadedFunction) { pluginLayer._featureCollectionUnloadedFunction(featureCollection); } #ifdef C_LOG_TILES // TODO: Remove this logging - std::cout << passCount << ": Removing Feature Collection for Tile: " << (int)tileID.canonical.z << "," << tileID.canonical.x << "," << tileID.canonical.y << "\n"; + std::cout << passCount << ": Removing Feature Collection for Tile: " << (int)tileID.canonical.z << "," + << tileID.canonical.x << "," << tileID.canonical.y << "\n"; #endif _featureCollectionByTile.erase(tileID); } } - if (renderTiles) { if (!renderTiles->empty()) { - auto drawPass = RenderPass::Pass3D; - + // If we're reading feature collections, go through // and notify the plugin of any new feature collections for (const RenderTile& tile : *renderTiles) { @@ -141,12 +139,12 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis std::cout << passCount << ": Tile was there and not anymore\n"; #endif } - + // TODO: Remove -// if ((tileID.canonical.x == 1289) && (tileID.canonical.y == 879)) { -// std::cout << "Found tile\n"; -// } - + // if ((tileID.canonical.x == 1289) && (tileID.canonical.y == 879)) { + // std::cout << "Found tile\n"; + // } + const auto* optRenderData = getRenderDataForPass(tile, drawPass); if (!optRenderData || !optRenderData->bucket || !optRenderData->bucket->hasData()) { removeTile(drawPass, tileID); @@ -155,34 +153,35 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis const auto& renderData = *optRenderData; auto& bucket = static_cast(*renderData.bucket); // TODO: Remove - //std::cout << "Found Bucket\n"; + // std::cout << "Found Bucket\n"; auto featureCollection = bucket._featureCollection; if (featureCollection == nullptr) { continue; } - + // See if we already have this tile'a feature collection if (_featureCollectionByTile.contains(tileID)) { continue; } - + _featureCollectionByTile[tileID] = featureCollection; -// static_cast(*baseImpl); -// auto layer = static_cast(*renderData.layerProperties->baseImpl); + // static_cast(*baseImpl); + // auto layer = static_cast(*renderData.layerProperties->baseImpl); if (pluginLayer._featureCollectionLoadedFunction) { if (featureCollection != nullptr) { pluginLayer._featureCollectionLoadedFunction(featureCollection); #ifdef C_LOG_TILES // TODO: Remove logging - std::cout << passCount << ": Adding Feature Collection for Tile: " << (int)tileID.canonical.z << "," << tileID.canonical.x << "," << tileID.canonical.y << "\n"; + std::cout << passCount << ": Adding Feature Collection for Tile: " << (int)tileID.canonical.z + << "," << tileID.canonical.x << "," << tileID.canonical.y << "\n"; #endif - } } - + /* - + 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. @@ -190,11 +189,8 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis } setRenderTileBucketID(tileID, bucket.getID()); */ - } - } - } /* @@ -222,16 +218,16 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); - + const auto* optRenderData = getRenderDataForPass(tile, drawPass); if (!optRenderData || !optRenderData->bucket || !optRenderData->bucket->hasData()) { removeTile(drawPass, tileID); continue; } - + const auto& renderData = *optRenderData; auto& bucket = static_cast(*renderData.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. @@ -241,22 +237,7 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis } */ - - - - - - - - - - - - - - - - + // create layer group if (!layerGroup) { if (auto layerGroup_ = context.createLayerGroup(layerIndex, /*initialCapacity=*/1, getID())) { @@ -300,7 +281,6 @@ void RenderPluginLayer::render(PaintParameters& paintParameters) { } void RenderPluginLayer::prepare(const LayerPrepareParameters& layerParameters) { - // This check is here because base prepare will assert on these and crash if (layerParameters.source != nullptr) { if (layerParameters.source->isEnabled()) { @@ -308,7 +288,6 @@ void RenderPluginLayer::prepare(const LayerPrepareParameters& layerParameters) { } } - if (_updateFunction) { _updateFunction(layerParameters); } @@ -344,20 +323,17 @@ void RenderPluginLayer::evaluate(const PropertyEvaluationParameters& parameters) std::string jsonProperties = pm.propertiesAsJSON(); i->_updateLayerPropertiesFunction(jsonProperties); - - - auto properties = makeMutable(staticImmutableCast(baseImpl)); + + auto properties = makeMutable( + staticImmutableCast(baseImpl)); passes = RenderPass::Pass3D; -// passes = RenderPass::Pass3D; (evaluated.get().constantOr(1.0) > 0 && -// evaluated.get().constantOr(Color::black()).a > 0 && -// evaluated.get().constantOr(1.0) > 0) -// ? RenderPass::Translucent -// : RenderPass::None; + // passes = RenderPass::Pass3D; (evaluated.get().constantOr(1.0) > 0 && + // evaluated.get().constantOr(Color::black()).a > 0 && + // evaluated.get().constantOr(1.0) > 0) + // ? RenderPass::Translucent + // : RenderPass::None; properties->renderPasses = mbgl::underlying_type(passes); evaluatedProperties = std::move(properties); - - - } bool RenderPluginLayer::hasTransition() const { diff --git a/src/mbgl/plugin/plugin_layer_render.hpp b/src/mbgl/plugin/plugin_layer_render.hpp index 847aea6003f8..f7ccdc70d8c8 100644 --- a/src/mbgl/plugin/plugin_layer_render.hpp +++ b/src/mbgl/plugin/plugin_layer_render.hpp @@ -68,9 +68,8 @@ class RenderPluginLayer final : public RenderLayer { style::PluginLayer::OnUpdateLayer _updateFunction = nullptr; style::PluginLayer::OnUpdateLayerProperties _updateLayerPropertiesFunction = nullptr; - + std::map> _featureCollectionByTile; - }; } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index 874494cd94a5..5ea111730f0f 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -398,11 +398,11 @@ void GeometryTileWorker::parse() { for (auto layer : *layers) { auto lk = layoutKey(*layer->baseImpl); - //std::cout << "LK: " << lk << "\n"; + // std::cout << "LK: " << lk << "\n"; if (lk.find("parking_space1") != std::string::npos) { - // std::cout << " Found PLugin\n"; + // std::cout << " Found PLugin\n"; } else { - // continue; + // continue; } groupMap[lk].push_back(std::move(layer)); } From de3897a98299bc7f1e9a69907aefbb2aa27127f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Fri, 25 Jul 2025 10:57:30 -0400 Subject: [PATCH 05/49] Reverting some logging --- src/mbgl/tile/geometry_tile_worker.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index 874494cd94a5..73353873630d 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -397,14 +397,7 @@ void GeometryTileWorker::parse() { groupMap.reserve(layers->size()); for (auto layer : *layers) { - auto lk = layoutKey(*layer->baseImpl); - //std::cout << "LK: " << lk << "\n"; - if (lk.find("parking_space1") != std::string::npos) { - // std::cout << " Found PLugin\n"; - } else { - // continue; - } - groupMap[lk].push_back(std::move(layer)); + groupMap[layoutKey(*layer->baseImpl)].push_back(std::move(layer)); } for (auto& pair : groupMap) { From 7f3ab5f2a6cd26ef3c241623095c68ad61b38b19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Fri, 25 Jul 2025 10:59:10 -0400 Subject: [PATCH 06/49] Removed unused include --- src/mbgl/tile/geometry_tile_worker.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index 73353873630d..4935bc5f3382 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -24,7 +24,6 @@ #include #include -#include namespace mbgl { From c8cc54474cf78b9db1ae3fe75d157ebe153d1c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Fri, 25 Jul 2025 10:59:49 -0400 Subject: [PATCH 07/49] Removed unused header --- src/mbgl/renderer/render_orchestrator.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 9805979f524a..8f6e3abf0419 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -29,8 +29,6 @@ #include #include -#include - namespace mbgl { using namespace style; From 345861445fde7c2fa5000ef12c3cf89765db9bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Fri, 25 Jul 2025 13:31:40 -0400 Subject: [PATCH 08/49] Initial commit of style filters --- bazel/core.bzl | 2 + include/mbgl/style/style.hpp | 4 ++ platform/BUILD.bazel | 2 + platform/darwin/BUILD.bazel | 2 + platform/darwin/app/StyleFilterExample.h | 16 ++++++ platform/darwin/app/StyleFilterExample.mm | 60 ++++++++++++++++++++ platform/darwin/bazel/files.bzl | 6 +- platform/darwin/src/MLNStyleFilter.h | 12 ++++ platform/darwin/src/MLNStyleFilter.mm | 23 ++++++++ platform/darwin/src/MLNStyleFilter_Private.h | 14 +++++ platform/ios/app/MBXViewController.mm | 2 + platform/ios/src/MLNMapView.h | 6 ++ platform/ios/src/MLNMapView.mm | 55 ++++++++++++++++++ src/mbgl/plugin/plugin_style_filter.cpp | 14 +++++ src/mbgl/plugin/plugin_style_filter.hpp | 23 ++++++++ src/mbgl/style/style.cpp | 8 +++ src/mbgl/style/style_impl.cpp | 22 ++++++- src/mbgl/style/style_impl.hpp | 7 +++ 18 files changed, 275 insertions(+), 3 deletions(-) create mode 100644 platform/darwin/app/StyleFilterExample.h create mode 100644 platform/darwin/app/StyleFilterExample.mm create mode 100644 platform/darwin/src/MLNStyleFilter.h create mode 100644 platform/darwin/src/MLNStyleFilter.mm create mode 100644 platform/darwin/src/MLNStyleFilter_Private.h create mode 100644 src/mbgl/plugin/plugin_style_filter.cpp create mode 100644 src/mbgl/plugin/plugin_style_filter.hpp diff --git a/bazel/core.bzl b/bazel/core.bzl index b27bbd8d925b..f79b5e36f6da 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -4,6 +4,7 @@ MLN_LAYER_PLUGIN_HEADERS = [ "src/mbgl/plugin/plugin_layer_impl.hpp", "src/mbgl/plugin/plugin_layer_render.hpp", "src/mbgl/plugin/plugin_layer_properties.hpp", + "src/mbgl/plugin/plugin_style_filter.hpp", ] MLN_LAYER_PLUGIN_SOURCE = [ @@ -12,6 +13,7 @@ MLN_LAYER_PLUGIN_SOURCE = [ "src/mbgl/plugin/plugin_layer_impl.cpp", "src/mbgl/plugin/plugin_layer_render.cpp", "src/mbgl/plugin/plugin_layer_properties.cpp", + "src/mbgl/plugin/plugin_style_filter.cpp", ] MLN_PUBLIC_GENERATED_STYLE_HEADERS = [ diff --git a/include/mbgl/style/style.hpp b/include/mbgl/style/style.hpp index 0d2d45719158..b143c5738c8d 100644 --- a/include/mbgl/style/style.hpp +++ b/include/mbgl/style/style.hpp @@ -20,6 +20,7 @@ namespace style { class Light; class Source; class Layer; +class PluginStyleFilter; class Style { public: @@ -71,6 +72,9 @@ class Style { void addLayer(std::unique_ptr, const std::optional& beforeLayerID = std::nullopt); std::unique_ptr removeLayer(const std::string& layerID); + // Add style parsing filter + void addStyleFilter(std::shared_ptr); + // Private implementation class Impl; const std::unique_ptr impl; diff --git a/platform/BUILD.bazel b/platform/BUILD.bazel index f39d31d1ee8e..bb89fd40fd6a 100644 --- a/platform/BUILD.bazel +++ b/platform/BUILD.bazel @@ -268,6 +268,8 @@ objc_library( srcs = [ "//platform/darwin:app/PluginLayerExample.h", "//platform/darwin:app/PluginLayerExample.mm", + "//platform/darwin:app/StyleFilterExample.h", + "//platform/darwin:app/StyleFilterExample.mm", "//platform/darwin:app/PluginLayerExampleMetalRendering.h", "//platform/darwin:app/PluginLayerExampleMetalRendering.mm", "//platform/darwin:app/CustomStyleLayerExample.h", diff --git a/platform/darwin/BUILD.bazel b/platform/darwin/BUILD.bazel index dcc0a8bcbac4..641f94f0aca1 100644 --- a/platform/darwin/BUILD.bazel +++ b/platform/darwin/BUILD.bazel @@ -301,6 +301,8 @@ exports_files( "app/PluginLayerTestStyle.json", "app/PluginLayerExample.h", "app/PluginLayerExample.mm", + "app/StyleFilterExample.h", + "app/StyleFilterExample.mm", "app/PluginLayerExampleMetalRendering.h", "app/PluginLayerExampleMetalRendering.mm", "test/amsterdam.geojson", diff --git a/platform/darwin/app/StyleFilterExample.h b/platform/darwin/app/StyleFilterExample.h new file mode 100644 index 000000000000..47cfe9f6c4e2 --- /dev/null +++ b/platform/darwin/app/StyleFilterExample.h @@ -0,0 +1,16 @@ +// +// StyleFilterExample.h +// MapLibre +// +// Created by Malcolm Toon on 7/25/25. +// + +#import "MLNStyleFilter.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface StyleFilterExample : MLNStyleFilter + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/app/StyleFilterExample.mm b/platform/darwin/app/StyleFilterExample.mm new file mode 100644 index 000000000000..ab6955136775 --- /dev/null +++ b/platform/darwin/app/StyleFilterExample.mm @@ -0,0 +1,60 @@ +#import "StyleFilterExample.h" + +@implementation StyleFilterExample + +// This will filter the data passed in +-(NSData *)filterData:(NSData *)data { + // Don't call super + + // This example will remove any layer that has "metal-rendering-layer" in the id + + // Parse the JSON: Make the containers mutable + NSError *error = nil; + NSMutableDictionary *styleDictionary = [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableContainers + error:&error]; + + NSData *tempResult = data; + if (styleDictionary) { + + // Get the layer array + NSMutableArray *layerArray = [styleDictionary objectForKey:@"layers"]; + + // Create an array to hold which objects to remove since we can't remove them in the loop + NSMutableArray *removedLayers = [NSMutableArray array]; + + // Loop the layers and look for any layers that have the search string in them + for (NSMutableDictionary *layer in layerArray) { + NSString *layerID = [layer objectForKey:@"id"]; + + // If we find the layers we're looking for, add them to the list of layers to remove + if ([layerID containsString:@"metal-rendering-layer"]) { + [removedLayers addObject:layer]; + } + } + + // Go through and remove any layers that were found + for (NSMutableDictionary *l in removedLayers) { + [layerArray removeObject:l]; + } + + // Re-create the JSON, this time the layers we filtered out won't be there + NSData *filteredStyleJSON = [NSJSONSerialization dataWithJSONObject:styleDictionary + options:0 + error:&error]; + + // If the JSON write is successful, then set the output to the new json style + if (filteredStyleJSON) { + tempResult = filteredStyleJSON; + } + + } + + // Return the data + return tempResult; + +} + + + +@end diff --git a/platform/darwin/bazel/files.bzl b/platform/darwin/bazel/files.bzl index 560189cd69c0..da71263cf5d5 100644 --- a/platform/darwin/bazel/files.bzl +++ b/platform/darwin/bazel/files.bzl @@ -108,6 +108,8 @@ MLN_DARWIN_OBJC_HEADERS = [ "src/NSValue+MLNAdditions.h", "src/MLNPluginLayer.h", "src/MLNPluginStyleLayer.h", + "src/MLNStyleFilter.h", + "src/MLNStyleFilter_Private.h", ] MLN_DARWIN_OBJCPP_HEADERS = [ @@ -222,8 +224,8 @@ MLN_DARWIN_PUBLIC_OBJCPP_SOURCE = [ "src/NSPredicate+MLNAdditions.mm", "src/NSValue+MLNStyleAttributeAdditions.mm", "src/MLNPluginLayer.mm", - "src/MLNPluginStyleLayer.mm" - + "src/MLNPluginStyleLayer.mm", + "src/MLNStyleFilter.mm", ] MLN_DARWIN_PUBLIC_OBJCPP_CUSTOM_DRAWABLE_SOURCE = [ "src/MLNCustomDrawableStyleLayer_Private.h", diff --git a/platform/darwin/src/MLNStyleFilter.h b/platform/darwin/src/MLNStyleFilter.h new file mode 100644 index 000000000000..066d329c8469 --- /dev/null +++ b/platform/darwin/src/MLNStyleFilter.h @@ -0,0 +1,12 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MLNStyleFilter : NSObject + +// This will filter the data passed in +-(NSData *)filterData:(NSData *)data; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MLNStyleFilter.mm b/platform/darwin/src/MLNStyleFilter.mm new file mode 100644 index 000000000000..31c6b0f6e937 --- /dev/null +++ b/platform/darwin/src/MLNStyleFilter.mm @@ -0,0 +1,23 @@ +#import "MLNStyleFilter.h" +#include + +@interface MLNStyleFilter () { + std::shared_ptr _coreFilter; +} + +@end + +@implementation MLNStyleFilter + +-(NSData *)filterData:(NSData *)data { + // Base class does nothing but return the same data passed in + return data; +} + +// Private +-(void)setFilter:(std::shared_ptr)filter { + _coreFilter = filter; +} + + +@end diff --git a/platform/darwin/src/MLNStyleFilter_Private.h b/platform/darwin/src/MLNStyleFilter_Private.h new file mode 100644 index 000000000000..f27864868d55 --- /dev/null +++ b/platform/darwin/src/MLNStyleFilter_Private.h @@ -0,0 +1,14 @@ + +#ifndef MLNStyleFilter_Private_h +#define MLNStyleFilter_Private_h + +#import "MLNStyleFilter.h" +#include + +@interface MLNStyleFilter(Private) + +-(void)setFilter:(std::shared_ptr)filter; + +@end + +#endif /* MLNStyleFilter_Private_h */ diff --git a/platform/ios/app/MBXViewController.mm b/platform/ios/app/MBXViewController.mm index 4c13a767ea51..6b68eb906bd4 100644 --- a/platform/ios/app/MBXViewController.mm +++ b/platform/ios/app/MBXViewController.mm @@ -27,6 +27,7 @@ #import "PluginLayerExample.h" #import "PluginLayerExampleMetalRendering.h" #import "MLNPluginStyleLayer.h" +#import "StyleFilterExample.h" static const CLLocationCoordinate2D WorldTourDestinations[] = { { .latitude = 38.8999418, .longitude = -77.033996 }, @@ -281,6 +282,7 @@ -(void)addPluginLayers { [self.mapView addPluginLayerType:[PluginLayerExample class]]; [self.mapView addPluginLayerType:[PluginLayerExampleMetalRendering class]]; + [self.mapView addStyleFilter:[[StyleFilterExample alloc] init]]; } diff --git a/platform/ios/src/MLNMapView.h b/platform/ios/src/MLNMapView.h index 1e800fafe188..decd8f9c12be 100644 --- a/platform/ios/src/MLNMapView.h +++ b/platform/ios/src/MLNMapView.h @@ -20,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN @class MLNScaleBar; @class MLNShape; @class MLNPluginLayer; +@class MLNStyleFilter; @protocol MLNMapViewDelegate; @protocol MLNAnnotation; @@ -2276,6 +2277,11 @@ vertically on the map. */ - (void)addPluginLayerType:(Class)pluginLayerClass; +/** + Adds a style filter to the map view + */ +-(void)addStyleFilter:(MLNStyleFilter *)styleFilter; + @end NS_ASSUME_NONNULL_END diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index 23313088fa14..0c1d1753c264 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +83,8 @@ #import "MLNPluginLayer.h" #import "MLNStyleLayerManager.h" #include "MLNPluginStyleLayer_Private.h" +#include "MLNStyleFilter.h" +#include "MLNStyleFilter_Private.h" #include #include @@ -455,6 +458,9 @@ @interface MLNMapView () (); + coreStyleFilter->_filterStyleFunction = [styleFilter](const mbgl::Response &response) -> const mbgl::Response { + + mbgl::Response tempResult; + + @autoreleasepool { + NSData *sourceData = [NSData dataWithBytesNoCopy:(void *)response.data->data() + length:response.data->size() + freeWhenDone:NO]; + NSData *filteredData = [styleFilter filterData:sourceData]; + if (response.error) { + tempResult.error = std::make_unique(response.error->reason, + response.error->message, + response.error->retryAfter); + } + tempResult.noContent = response.noContent; + tempResult.notModified = response.notModified; + tempResult.mustRevalidate = response.mustRevalidate; + tempResult.modified = response.modified; + tempResult.expires = response.expires; + tempResult.etag = response.etag; + + // Set the response data + tempResult.data = + std::make_shared((const char*)[filteredData bytes], [filteredData length]); + + + } + return tempResult; + }; + + // Set the ivar + [styleFilter setFilter:coreStyleFilter]; + + _mbglMap->getStyle().addStyleFilter(coreStyleFilter); + +} + + - (NSArray*)getActionJournalLogFiles { const auto& actionJournal = _mbglMap->getActionJournal(); diff --git a/src/mbgl/plugin/plugin_style_filter.cpp b/src/mbgl/plugin/plugin_style_filter.cpp new file mode 100644 index 000000000000..f30f7697fee2 --- /dev/null +++ b/src/mbgl/plugin/plugin_style_filter.cpp @@ -0,0 +1,14 @@ +#include + +using namespace mbgl::style; + +// This method +const mbgl::Response PluginStyleFilter::FilterResponse(const Response& res) { + + if (_filterStyleFunction) { + auto tempResult = _filterStyleFunction(res); + return tempResult; + } + return res; + +} diff --git a/src/mbgl/plugin/plugin_style_filter.hpp b/src/mbgl/plugin/plugin_style_filter.hpp new file mode 100644 index 000000000000..2cfd8ab26b6c --- /dev/null +++ b/src/mbgl/plugin/plugin_style_filter.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include + + +namespace mbgl { + +namespace style { + +class PluginStyleFilter { +public: + + using OnFilterStyle = std::function; + + OnFilterStyle _filterStyleFunction; + + // This method + const Response FilterResponse(const Response& res); +}; + + +} +} diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 4f8723ead10a..bba0362b5704 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -177,5 +177,13 @@ std::unique_ptr Style::removeLayer(const std::string& id) { return impl->removeLayer(id); } +// Add style parsing filter +void Style::addStyleFilter(std::shared_ptr filter) { + impl->mutated = true; + return impl->addStyleFilter(filter); + +} + + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index b42deb21c152..850774a1e9cb 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include namespace mbgl { @@ -74,11 +75,24 @@ void Style::Impl::loadURL(const std::string& url_) { } else if (res.notModified || res.noContent) { return; } else { - parse(*res.data); + filterThenParse(res); } }); } +void Style::Impl::filterThenParse(const Response& res) { + + Response tempResult = res; + if (_styleFilters.size() > 0) { + for (auto filter: _styleFilters) { + tempResult = filter->FilterResponse(tempResult); + } + } + parse(*tempResult.data); +// parse(*res.data); + +} + void Style::Impl::parse(const std::string& json_) { Parser parser; @@ -233,6 +247,12 @@ std::unique_ptr Style::Impl::removeLayer(const std::string& id) { return layer; } +// Add style parsing filter +void Style::Impl::addStyleFilter(std::shared_ptr filter) { + _styleFilters.push_back(filter); +} + + void Style::Impl::setLight(std::unique_ptr light_) { light = std::move(light_); light->setObserver(this); diff --git a/src/mbgl/style/style_impl.hpp b/src/mbgl/style/style_impl.hpp index e9ab3abc5654..9effde9d926b 100644 --- a/src/mbgl/style/style_impl.hpp +++ b/src/mbgl/style/style_impl.hpp @@ -28,6 +28,7 @@ namespace mbgl { class FileSource; class AsyncRequest; class SpriteLoader; +class Response; namespace style { @@ -66,6 +67,10 @@ class Style::Impl : public SpriteLoaderObserver, Layer* addLayer(std::unique_ptr, const std::optional& beforeLayerID = std::nullopt); std::unique_ptr removeLayer(const std::string& layerID); + // Add style parsing filter + void addStyleFilter(std::shared_ptr); + void filterThenParse(const Response& res); + std::string getName() const; CameraOptions getDefaultCamera() const; @@ -95,6 +100,8 @@ class Style::Impl : public SpriteLoaderObserver, private: void parse(const std::string&); + std::vector> _styleFilters; + std::shared_ptr fileSource; std::string url; From f4d1ef4112c329a2cb536cf4ffaba3b8dcabbad5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 17:33:50 +0000 Subject: [PATCH 09/49] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- include/mbgl/style/style.hpp | 2 +- platform/darwin/app/StyleFilterExample.mm | 26 ++++++++++---------- platform/darwin/src/MLNStyleFilter.h | 2 +- platform/darwin/src/MLNStyleFilter_Private.h | 6 ++--- platform/ios/src/MLNMapView.h | 2 +- platform/ios/src/MLNMapView.mm | 12 ++++----- src/mbgl/plugin/plugin_style_filter.cpp | 2 -- src/mbgl/plugin/plugin_style_filter.hpp | 11 +++------ src/mbgl/style/style.cpp | 2 -- src/mbgl/style/style_impl.cpp | 7 ++---- src/mbgl/style/style_impl.hpp | 2 +- 11 files changed, 32 insertions(+), 42 deletions(-) diff --git a/include/mbgl/style/style.hpp b/include/mbgl/style/style.hpp index b143c5738c8d..f3e359c1b8b5 100644 --- a/include/mbgl/style/style.hpp +++ b/include/mbgl/style/style.hpp @@ -74,7 +74,7 @@ class Style { // Add style parsing filter void addStyleFilter(std::shared_ptr); - + // Private implementation class Impl; const std::unique_ptr impl; diff --git a/platform/darwin/app/StyleFilterExample.mm b/platform/darwin/app/StyleFilterExample.mm index ab6955136775..730e36b75f3d 100644 --- a/platform/darwin/app/StyleFilterExample.mm +++ b/platform/darwin/app/StyleFilterExample.mm @@ -5,54 +5,54 @@ @implementation StyleFilterExample // This will filter the data passed in -(NSData *)filterData:(NSData *)data { // Don't call super - + // This example will remove any layer that has "metal-rendering-layer" in the id - + // Parse the JSON: Make the containers mutable NSError *error = nil; NSMutableDictionary *styleDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error]; - + NSData *tempResult = data; if (styleDictionary) { - + // Get the layer array NSMutableArray *layerArray = [styleDictionary objectForKey:@"layers"]; - + // Create an array to hold which objects to remove since we can't remove them in the loop NSMutableArray *removedLayers = [NSMutableArray array]; - + // Loop the layers and look for any layers that have the search string in them for (NSMutableDictionary *layer in layerArray) { NSString *layerID = [layer objectForKey:@"id"]; - + // If we find the layers we're looking for, add them to the list of layers to remove if ([layerID containsString:@"metal-rendering-layer"]) { [removedLayers addObject:layer]; } } - + // Go through and remove any layers that were found for (NSMutableDictionary *l in removedLayers) { [layerArray removeObject:l]; } - + // Re-create the JSON, this time the layers we filtered out won't be there NSData *filteredStyleJSON = [NSJSONSerialization dataWithJSONObject:styleDictionary options:0 error:&error]; - + // If the JSON write is successful, then set the output to the new json style if (filteredStyleJSON) { tempResult = filteredStyleJSON; } - + } - + // Return the data return tempResult; - + } diff --git a/platform/darwin/src/MLNStyleFilter.h b/platform/darwin/src/MLNStyleFilter.h index 066d329c8469..d9a242ed6394 100644 --- a/platform/darwin/src/MLNStyleFilter.h +++ b/platform/darwin/src/MLNStyleFilter.h @@ -5,7 +5,7 @@ NS_ASSUME_NONNULL_BEGIN @interface MLNStyleFilter : NSObject // This will filter the data passed in --(NSData *)filterData:(NSData *)data; +- (NSData *)filterData:(NSData *)data; @end diff --git a/platform/darwin/src/MLNStyleFilter_Private.h b/platform/darwin/src/MLNStyleFilter_Private.h index f27864868d55..749cefcc7fd9 100644 --- a/platform/darwin/src/MLNStyleFilter_Private.h +++ b/platform/darwin/src/MLNStyleFilter_Private.h @@ -2,12 +2,12 @@ #ifndef MLNStyleFilter_Private_h #define MLNStyleFilter_Private_h -#import "MLNStyleFilter.h" #include +#import "MLNStyleFilter.h" -@interface MLNStyleFilter(Private) +@interface MLNStyleFilter (Private) --(void)setFilter:(std::shared_ptr)filter; +- (void)setFilter:(std::shared_ptr)filter; @end diff --git a/platform/ios/src/MLNMapView.h b/platform/ios/src/MLNMapView.h index decd8f9c12be..1e33c471fd93 100644 --- a/platform/ios/src/MLNMapView.h +++ b/platform/ios/src/MLNMapView.h @@ -2280,7 +2280,7 @@ vertically on the map. /** Adds a style filter to the map view */ --(void)addStyleFilter:(MLNStyleFilter *)styleFilter; +- (void)addStyleFilter:(MLNStyleFilter *)styleFilter; @end diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index 0c1d1753c264..925e29f2a2f6 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -7811,15 +7811,15 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { Adds a style filter to the map view */ -(void)addStyleFilter:(MLNStyleFilter *)styleFilter { - + if (!self.styleFilters) { self.styleFilters = [NSMutableArray array]; } [self.styleFilters addObject:styleFilter]; - + auto coreStyleFilter = std::make_shared(); coreStyleFilter->_filterStyleFunction = [styleFilter](const mbgl::Response &response) -> const mbgl::Response { - + mbgl::Response tempResult; @autoreleasepool { @@ -7847,12 +7847,12 @@ -(void)addStyleFilter:(MLNStyleFilter *)styleFilter { } return tempResult; }; - + // Set the ivar [styleFilter setFilter:coreStyleFilter]; - + _mbglMap->getStyle().addStyleFilter(coreStyleFilter); - + } diff --git a/src/mbgl/plugin/plugin_style_filter.cpp b/src/mbgl/plugin/plugin_style_filter.cpp index f30f7697fee2..a0908f492f72 100644 --- a/src/mbgl/plugin/plugin_style_filter.cpp +++ b/src/mbgl/plugin/plugin_style_filter.cpp @@ -4,11 +4,9 @@ using namespace mbgl::style; // This method const mbgl::Response PluginStyleFilter::FilterResponse(const Response& res) { - if (_filterStyleFunction) { auto tempResult = _filterStyleFunction(res); return tempResult; } return res; - } diff --git a/src/mbgl/plugin/plugin_style_filter.hpp b/src/mbgl/plugin/plugin_style_filter.hpp index 2cfd8ab26b6c..3527f64cbba8 100644 --- a/src/mbgl/plugin/plugin_style_filter.hpp +++ b/src/mbgl/plugin/plugin_style_filter.hpp @@ -2,22 +2,19 @@ #include - namespace mbgl { namespace style { class PluginStyleFilter { public: - - using OnFilterStyle = std::function; + using OnFilterStyle = std::function; OnFilterStyle _filterStyleFunction; - + // This method const Response FilterResponse(const Response& res); }; - -} -} +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index bba0362b5704..0caa94860549 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -181,9 +181,7 @@ std::unique_ptr Style::removeLayer(const std::string& id) { void Style::addStyleFilter(std::shared_ptr filter) { impl->mutated = true; return impl->addStyleFilter(filter); - } - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index 850774a1e9cb..64082cf84cbb 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -81,16 +81,14 @@ void Style::Impl::loadURL(const std::string& url_) { } void Style::Impl::filterThenParse(const Response& res) { - Response tempResult = res; if (_styleFilters.size() > 0) { - for (auto filter: _styleFilters) { + for (auto filter : _styleFilters) { tempResult = filter->FilterResponse(tempResult); } } parse(*tempResult.data); -// parse(*res.data); - + // parse(*res.data); } void Style::Impl::parse(const std::string& json_) { @@ -252,7 +250,6 @@ void Style::Impl::addStyleFilter(std::shared_ptr _styleFilters.push_back(filter); } - void Style::Impl::setLight(std::unique_ptr light_) { light = std::move(light_); light->setObserver(this); diff --git a/src/mbgl/style/style_impl.hpp b/src/mbgl/style/style_impl.hpp index 9effde9d926b..3a518ce866ce 100644 --- a/src/mbgl/style/style_impl.hpp +++ b/src/mbgl/style/style_impl.hpp @@ -101,7 +101,7 @@ class Style::Impl : public SpriteLoaderObserver, void parse(const std::string&); std::vector> _styleFilters; - + std::shared_ptr fileSource; std::string url; From 58f352e0b548f89b3a39a7e4609bb8be14309687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Fri, 25 Jul 2025 13:38:50 -0400 Subject: [PATCH 10/49] Little bit of cleanup --- platform/darwin/app/StyleFilterExample.h | 7 ------- src/mbgl/style/style_impl.cpp | 15 +++++++++------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/platform/darwin/app/StyleFilterExample.h b/platform/darwin/app/StyleFilterExample.h index 47cfe9f6c4e2..ea694e6d4c3e 100644 --- a/platform/darwin/app/StyleFilterExample.h +++ b/platform/darwin/app/StyleFilterExample.h @@ -1,10 +1,3 @@ -// -// StyleFilterExample.h -// MapLibre -// -// Created by Malcolm Toon on 7/25/25. -// - #import "MLNStyleFilter.h" NS_ASSUME_NONNULL_BEGIN diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index 850774a1e9cb..e5571dda17ab 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -82,15 +82,18 @@ void Style::Impl::loadURL(const std::string& url_) { void Style::Impl::filterThenParse(const Response& res) { + if (_styleFilters.size() == 0) { + parse(*res.data); + return; + } + + // Otherwise, go through the chain of filters Response tempResult = res; - if (_styleFilters.size() > 0) { - for (auto filter: _styleFilters) { - tempResult = filter->FilterResponse(tempResult); - } + for (auto filter: _styleFilters) { + tempResult = filter->FilterResponse(tempResult); } parse(*tempResult.data); -// parse(*res.data); - + } void Style::Impl::parse(const std::string& json_) { From c817bff64f417426c685dba381206b4345997a51 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 17:41:51 +0000 Subject: [PATCH 11/49] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/mbgl/style/style_impl.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index e6432eeba6b5..16c699e4ece6 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -81,19 +81,17 @@ void Style::Impl::loadURL(const std::string& url_) { } void Style::Impl::filterThenParse(const Response& res) { - if (_styleFilters.size() == 0) { parse(*res.data); return; } - + // Otherwise, go through the chain of filters Response tempResult = res; - for (auto filter: _styleFilters) { + for (auto filter : _styleFilters) { tempResult = filter->FilterResponse(tempResult); } parse(*tempResult.data); - } void Style::Impl::parse(const std::string& json_) { From 4a540217e8e1c9ad65b97508f5e52109daf3597e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Fri, 25 Jul 2025 13:47:23 -0400 Subject: [PATCH 12/49] Added feature collections to cmake --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f24a62dc5d4..0713f3c78bb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -977,6 +977,10 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_properties.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_impl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_factory.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/feature_collection.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/feature_collection.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/feature_collection_bucket.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/feature_collection_bucket.cpp ) From 987a384a2c7ccc145b505d929f69c199c7959edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Fri, 25 Jul 2025 13:58:13 -0400 Subject: [PATCH 13/49] Removing array type for now --- src/mbgl/plugin/feature_collection_bucket.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mbgl/plugin/feature_collection_bucket.cpp b/src/mbgl/plugin/feature_collection_bucket.cpp index f4797a2b88f2..eb002d98f9c0 100644 --- a/src/mbgl/plugin/feature_collection_bucket.cpp +++ b/src/mbgl/plugin/feature_collection_bucket.cpp @@ -134,9 +134,9 @@ void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, } else if (auto b = value.getBool()) { // std::cout << "Found Bool: " << name << ": " << *b << "\n"; tempFeature->_featureProperties[name] = std::to_string(*b); - } else if (auto a = value.getArray()) { - // std::cout << "Found Array: " << name << ": " << *b << "\n"; - tempFeature->_featureProperties[name] = std::to_string(*b); +// } else if (auto a = value.getArray()) { +// // std::cout << "Found Array: " << name << ": " << *b << "\n"; +// tempFeature->_featureProperties[name] = std::to_string(*b); } // DECLARE_VALUE_TYPE_ACCESOR(Array, array_type) From 37f8e673c105b2853652a994fbb601d1265cb708 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 17:58:44 +0000 Subject: [PATCH 14/49] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/mbgl/plugin/feature_collection_bucket.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mbgl/plugin/feature_collection_bucket.cpp b/src/mbgl/plugin/feature_collection_bucket.cpp index eb002d98f9c0..4abc7a1d5e6d 100644 --- a/src/mbgl/plugin/feature_collection_bucket.cpp +++ b/src/mbgl/plugin/feature_collection_bucket.cpp @@ -134,9 +134,9 @@ void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, } else if (auto b = value.getBool()) { // std::cout << "Found Bool: " << name << ": " << *b << "\n"; tempFeature->_featureProperties[name] = std::to_string(*b); -// } else if (auto a = value.getArray()) { -// // std::cout << "Found Array: " << name << ": " << *b << "\n"; -// tempFeature->_featureProperties[name] = std::to_string(*b); + // } else if (auto a = value.getArray()) { + // // std::cout << "Found Array: " << name << ": " << *b << "\n"; + // tempFeature->_featureProperties[name] = std::to_string(*b); } // DECLARE_VALUE_TYPE_ACCESOR(Array, array_type) From 8654fc28fead118c4d09934754289e911a37929f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sat, 26 Jul 2025 00:07:32 -0400 Subject: [PATCH 15/49] Cleanp --- platform/darwin/app/PluginLayerExample.mm | 33 ++++++--- platform/darwin/app/PluginLayerTestStyle.json | 2 +- src/mbgl/plugin/feature_collection.cpp | 7 -- src/mbgl/plugin/feature_collection.hpp | 14 +--- src/mbgl/plugin/feature_collection_bucket.cpp | 69 +------------------ src/mbgl/plugin/feature_collection_bucket.hpp | 62 +---------------- 6 files changed, 28 insertions(+), 159 deletions(-) diff --git a/platform/darwin/app/PluginLayerExample.mm b/platform/darwin/app/PluginLayerExample.mm index 13c40d8e3794..18ab587bf03b 100644 --- a/platform/darwin/app/PluginLayerExample.mm +++ b/platform/darwin/app/PluginLayerExample.mm @@ -1,5 +1,14 @@ #import "PluginLayerExample.h" +@interface PluginLayerExample () { + +} + +@property BOOL logFeatures; + +@end + + @implementation PluginLayerExample @@ -14,6 +23,13 @@ +(MLNPluginLayerCapabilities *)layerCapabilities { } +-(id)init { + if (self = [super init]) { + self.logFeatures = NO; + } + return self; +} + // The overrides -(void)onRenderLayer:(MLNMapView *)mapView renderEncoder:(id)renderEncoder { @@ -25,27 +41,26 @@ -(void)onUpdateLayer { } -//-(void)onBucketLoaded:(MLNRawBucket *)bucket { -// -//} - -(void)onUpdateLayerProperties:(NSDictionary *)layerProperties { // NSLog(@"Layer Properties: %@", layerProperties); } -(void)featureLoaded:(MLNPluginLayerTileFeature *)tileFeature { - NSLog(@"Tile Feature (id:%@) Properties: %@", tileFeature.featureID, tileFeature.featureProperties); + + // Writing a single string since the tile loading is multithreaded and the output can get interwoven + NSMutableString *outputStr = [NSMutableString string]; + [outputStr appendFormat:@"Tile Feature (id:%@) Properties: %@\n", tileFeature.featureID, tileFeature.featureProperties]; for (NSValue *v in tileFeature.featureCoordinates) { - -// NSValue *value = [NSValue valueWithBytes:&c objCType:@encode(CLLocationCoordinate2D)]; -// [featureCoordinates addObject:value]; - CLLocationCoordinate2D coord; [v getValue:&coord]; + + [outputStr appendFormat:@" -> (%f, %f) \n", coord.latitude, coord.longitude]; } + + NSLog(@"Feature: %@", outputStr); } -(void)featureUnloaded:(MLNPluginLayerTileFeature *)tileFeature { diff --git a/platform/darwin/app/PluginLayerTestStyle.json b/platform/darwin/app/PluginLayerTestStyle.json index 826236d2a135..b650177ef0f7 100644 --- a/platform/darwin/app/PluginLayerTestStyle.json +++ b/platform/darwin/app/PluginLayerTestStyle.json @@ -586,7 +586,7 @@ { "id": "centroid-features", "type": "maplibre::filter_features", "source": "maplibre", - "source-layer": "centroids", + "source-layer": "countries", "maxzoom": 24, "minzoom": 1 }, diff --git a/src/mbgl/plugin/feature_collection.cpp b/src/mbgl/plugin/feature_collection.cpp index c5d067494a8a..46d2cdf7e994 100644 --- a/src/mbgl/plugin/feature_collection.cpp +++ b/src/mbgl/plugin/feature_collection.cpp @@ -1,8 +1 @@ -// -// feature_collection.cpp -// App -// -// Created by Malcolm Toon on 7/15/25. -// - #include "feature_collection.hpp" diff --git a/src/mbgl/plugin/feature_collection.hpp b/src/mbgl/plugin/feature_collection.hpp index 8b75ebada98f..bf3b4382d1de 100644 --- a/src/mbgl/plugin/feature_collection.hpp +++ b/src/mbgl/plugin/feature_collection.hpp @@ -1,12 +1,4 @@ -// -// feature_collection.hpp -// App -// -// Created by Malcolm Toon on 7/15/25. -// - -#ifndef feature_collection_hpp -#define feature_collection_hpp +#pragma once #include @@ -19,9 +11,6 @@ namespace mbgl { namespace plugin { -// using FillBinders = PaintPropertyBinders; -// using FillLayoutVertex = gfx::Vertex>; - class FeatureCoordinate { public: FeatureCoordinate(double lat, double lon) @@ -70,4 +59,3 @@ class FeatureCollection { } // namespace mbgl -#endif /* feature_collection_hpp */ diff --git a/src/mbgl/plugin/feature_collection_bucket.cpp b/src/mbgl/plugin/feature_collection_bucket.cpp index 4abc7a1d5e6d..eec24af37c63 100644 --- a/src/mbgl/plugin/feature_collection_bucket.cpp +++ b/src/mbgl/plugin/feature_collection_bucket.cpp @@ -1,17 +1,8 @@ -// -// raw_bucket.cpp -// App -// -// Created by Malcolm Toon on 7/3/25. -// - #include #include #include #include -#include - using namespace mbgl; FeatureCollectionBucket::~FeatureCollectionBucket() {} @@ -47,10 +38,6 @@ void geometryToLatLon(const GeometryCoordinate& coord, } std::string toString(FeatureIdentifier& v) { - // auto v = toValue(value); - - // null_value_t, uint64_t, int64_t, double, std::string> - std::string tempResult = ""; auto ti = v.which(); if (ti == 0) { @@ -63,23 +50,6 @@ std::string toString(FeatureIdentifier& v) { tempResult = v.get(); } return tempResult; - /* - if (auto iVal = v.value().getInt()) { - std::string tempResult = std::to_string(*iVal); - output.append(tempResult); - } else if (auto uIVal = v.value().getUint()) { - std::string tempResult = std::to_string(*uIVal); - output.append(tempResult); - - } else if (auto s = v.value().getString()) { - output.append("\""); - output.append(s->c_str()); - output.append("\""); - - } else if (auto d = v.value().getDouble()) { - output.append(std::to_string(*d)); - } - */ } void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, @@ -96,18 +66,14 @@ void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, switch (tileFeature.getType()) { case FeatureType::Point: - // std::cout << "Adding Point" << "\n"; tempFeature->_featureType = plugin::Feature::FeatureType::FeatureTypePoint; break; case FeatureType::Unknown: - // std::cout << "Unknown Type Found\n"; break; case FeatureType::LineString: - // std::cout << "LineString Type Found\n"; tempFeature->_featureType = plugin::Feature::FeatureType::FeatureTypeLine; break; case FeatureType::Polygon: - // std::cout << "Polygon Type Found\n"; tempFeature->_featureType = plugin::Feature::FeatureType::FeatureTypePolygon; break; } @@ -118,29 +84,20 @@ void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, mapbox::feature::value value = p.second; if (auto iVal = value.getInt()) { - std::cout << "Found Int: " << name << ": " << *iVal << "\n"; tempFeature->_featureProperties[name] = std::to_string(*iVal); } else if (auto uIVal = value.getUint()) { - std::cout << "Found UInt: " << name << ": " << *uIVal << "\n"; tempFeature->_featureProperties[name] = std::to_string(*uIVal); - } else if (auto s = value.getString()) { - // std::cout << "Found String: " << name << ": " << *s << "\n"; tempFeature->_featureProperties[name] = *s; - } else if (auto d = value.getDouble()) { - // std::cout << "Found Double: " << name << ": " << *d << "\n"; tempFeature->_featureProperties[name] = std::to_string(*d); } else if (auto b = value.getBool()) { - // std::cout << "Found Bool: " << name << ": " << *b << "\n"; tempFeature->_featureProperties[name] = std::to_string(*b); + // TODO: Add array type // } else if (auto a = value.getArray()) { - // // std::cout << "Found Array: " << name << ": " << *b << "\n"; // tempFeature->_featureProperties[name] = std::to_string(*b); } - // DECLARE_VALUE_TYPE_ACCESOR(Array, array_type) - // DECLARE_VALUE_TYPE_ACCESOR(Object, object_type) } LatLngBounds b(tileID); @@ -150,21 +107,10 @@ void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, plugin::FeatureCoordinateCollection c; for (std::size_t i = 0, len = g.size(); i < len; i++) { const GeometryCoordinate& p1 = g[i]; - auto d = b.west(); - - // auto c = project( - - // void geometryToLatLon( - // const GeometryCoordinate& coord, - // int tileX, int tileY, int zoom, - // double& lat, double& lon, - // int extent = 8192, - // int tileSize = 512 double lat = 0; double lon = 0; geometryToLatLon(p1, tileID.x, tileID.y, tileID.z, lat, lon); - c._coordinates.push_back(plugin::FeatureCoordinate(lat, lon)); } tempFeature->_featureCoordinates.push_back(c); @@ -179,20 +125,9 @@ void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, pluginLayer->_featureLoadedFunction(tempFeature); } } - // auto pluginLayer = std::dynamic_pointer_cast>(bi); - - // auto pluginLayer = std::dynamic_pointer_cast(l->baseImpl); - // if (pluginLayer != nullptr) { - // if (pluginLayer->_featureLoadedFunction != nullptr) { - // pluginLayer->_featureLoadedFunction(tempFeature); - // } - // } } _featureCollection->_features.push_back(tempFeature); - // _features.push_back(tempFeature); - - // std::cout << "Adding Feature Type: " << tileFeature.getType() << "\n"; } bool FeatureCollectionBucket::hasData() const { @@ -200,7 +135,6 @@ bool FeatureCollectionBucket::hasData() const { } void FeatureCollectionBucket::upload(gfx::UploadPass&) { - std::cout << "FeatureCollectionBucket::upload\n"; uploaded = true; } @@ -212,5 +146,4 @@ void FeatureCollectionBucket::update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) { - std::cout << "FeatureCollectionBucket::update\n"; } diff --git a/src/mbgl/plugin/feature_collection_bucket.hpp b/src/mbgl/plugin/feature_collection_bucket.hpp index ec5ae03e7a0a..4f6c6768ba81 100644 --- a/src/mbgl/plugin/feature_collection_bucket.hpp +++ b/src/mbgl/plugin/feature_collection_bucket.hpp @@ -11,31 +11,6 @@ #include -/* - - Open Questions - - - * Should we load up a vector of these RawFeatures by tile? - * How does that interop with the render layer's update flow - * Should the call back from render layer be more of a batch thing at that update stage? - * Should there be a callback when a tile or collection of these features go out of scope? - * Should the concept of managing arrays of features be something done by the core or just - hand off the features to the plug-in layer and let it do it's thing or have the option for both? - - * How do we get to the osm id of features in the stream? Is that tileFeature.getID()? - * Is there already a set of classes or a paradigm out there that could be used to represent the - feature / feature geometry? - * What are the "binders"? - - - Thoughts - * Possibly have ability to keep tile coordinates using some kind flag - - - - */ - namespace mbgl { class BucketParameters; @@ -66,45 +41,10 @@ class FeatureCollectionBucket final : public Bucket { // The tile ID OverscaledTileID _tileID; - // Array of features + // Feature collection is an list of features std::shared_ptr _featureCollection = nullptr; - // std::vector> _features; - std::vector> _layers; - /* - static FillLayoutVertex layoutVertex(Point p) { return FillLayoutVertex{{{p.x, p.y}}}; } - -#if MLN_TRIANGULATE_FILL_OUTLINES - using LineVertexVector = gfx::VertexVector; - const std::shared_ptr sharedLineVertices = std::make_shared(); - LineVertexVector& lineVertices = *sharedLineVertices; - - using LineIndexVector = gfx::IndexVector; - const std::shared_ptr sharedLineIndexes = std::make_shared(); - LineIndexVector& lineIndexes = *sharedLineIndexes; - - SegmentVector lineSegments; -#endif // MLN_TRIANGULATE_FILL_OUTLINES - - using BasicLineIndexVector = gfx::IndexVector; - const std::shared_ptr sharedBasicLineIndexes = std::make_shared(); - BasicLineIndexVector& basicLines = *sharedBasicLineIndexes; - - SegmentVector basicLineSegments; - - using VertexVector = gfx::VertexVector; - const std::shared_ptr sharedVertices = std::make_shared(); - VertexVector& vertices = *sharedVertices; - - using TriangleIndexVector = gfx::IndexVector; - const std::shared_ptr sharedTriangles = std::make_shared(); - TriangleIndexVector& triangles = *sharedTriangles; - - SegmentVector triangleSegments; - - std::map paintPropertyBinders; - */ }; } // namespace mbgl From 535927b1bac2eff3abb786acc34749790aa9a3ad Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 26 Jul 2025 04:08:38 +0000 Subject: [PATCH 16/49] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- platform/darwin/app/PluginLayerExample.mm | 8 ++++---- src/mbgl/plugin/feature_collection.hpp | 1 - src/mbgl/plugin/feature_collection_bucket.cpp | 6 ++---- src/mbgl/plugin/feature_collection_bucket.hpp | 1 - 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/platform/darwin/app/PluginLayerExample.mm b/platform/darwin/app/PluginLayerExample.mm index 18ab587bf03b..92d7056a0f19 100644 --- a/platform/darwin/app/PluginLayerExample.mm +++ b/platform/darwin/app/PluginLayerExample.mm @@ -1,7 +1,7 @@ #import "PluginLayerExample.h" @interface PluginLayerExample () { - + } @property BOOL logFeatures; @@ -46,7 +46,7 @@ -(void)onUpdateLayerProperties:(NSDictionary *)layerProperties { } -(void)featureLoaded:(MLNPluginLayerTileFeature *)tileFeature { - + // Writing a single string since the tile loading is multithreaded and the output can get interwoven NSMutableString *outputStr = [NSMutableString string]; [outputStr appendFormat:@"Tile Feature (id:%@) Properties: %@\n", tileFeature.featureID, tileFeature.featureProperties]; @@ -55,11 +55,11 @@ -(void)featureLoaded:(MLNPluginLayerTileFeature *)tileFeature { CLLocationCoordinate2D coord; [v getValue:&coord]; - + [outputStr appendFormat:@" -> (%f, %f) \n", coord.latitude, coord.longitude]; } - + NSLog(@"Feature: %@", outputStr); } diff --git a/src/mbgl/plugin/feature_collection.hpp b/src/mbgl/plugin/feature_collection.hpp index bf3b4382d1de..5ea0c639e571 100644 --- a/src/mbgl/plugin/feature_collection.hpp +++ b/src/mbgl/plugin/feature_collection.hpp @@ -58,4 +58,3 @@ class FeatureCollection { } // namespace plugin } // namespace mbgl - diff --git a/src/mbgl/plugin/feature_collection_bucket.cpp b/src/mbgl/plugin/feature_collection_bucket.cpp index eec24af37c63..9ef46fd84df8 100644 --- a/src/mbgl/plugin/feature_collection_bucket.cpp +++ b/src/mbgl/plugin/feature_collection_bucket.cpp @@ -93,11 +93,10 @@ void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, tempFeature->_featureProperties[name] = std::to_string(*d); } else if (auto b = value.getBool()) { tempFeature->_featureProperties[name] = std::to_string(*b); - // TODO: Add array type + // TODO: Add array type // } else if (auto a = value.getArray()) { // tempFeature->_featureProperties[name] = std::to_string(*b); } - } LatLngBounds b(tileID); @@ -145,5 +144,4 @@ float FeatureCollectionBucket::getQueryRadius(const RenderLayer&) const { void FeatureCollectionBucket::update(const FeatureStates&, const GeometryTileLayer&, const std::string&, - const ImagePositions&) { -} + const ImagePositions&) {} diff --git a/src/mbgl/plugin/feature_collection_bucket.hpp b/src/mbgl/plugin/feature_collection_bucket.hpp index 4f6c6768ba81..ccb28d35d018 100644 --- a/src/mbgl/plugin/feature_collection_bucket.hpp +++ b/src/mbgl/plugin/feature_collection_bucket.hpp @@ -44,7 +44,6 @@ class FeatureCollectionBucket final : public Bucket { // Feature collection is an list of features std::shared_ptr _featureCollection = nullptr; std::vector> _layers; - }; } // namespace mbgl From faeb360db26d6995a8c50fa0d2c657df86f97f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sat, 26 Jul 2025 00:29:59 -0400 Subject: [PATCH 17/49] Changed to filter the loadJSON path as well --- platform/ios/src/MLNMapView.mm | 25 +++++-------------------- src/mbgl/plugin/plugin_style_filter.cpp | 4 ++-- src/mbgl/plugin/plugin_style_filter.hpp | 4 ++-- src/mbgl/style/style_impl.cpp | 16 +++++++++------- src/mbgl/style/style_impl.hpp | 2 +- 5 files changed, 19 insertions(+), 32 deletions(-) diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index 925e29f2a2f6..fa072faec42e 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -7818,31 +7818,16 @@ -(void)addStyleFilter:(MLNStyleFilter *)styleFilter { [self.styleFilters addObject:styleFilter]; auto coreStyleFilter = std::make_shared(); - coreStyleFilter->_filterStyleFunction = [styleFilter](const mbgl::Response &response) -> const mbgl::Response { + coreStyleFilter->_filterStyleFunction = [styleFilter](const std::string &filterData) -> const std::string { - mbgl::Response tempResult; + std::string tempResult; @autoreleasepool { - NSData *sourceData = [NSData dataWithBytesNoCopy:(void *)response.data->data() - length:response.data->size() + NSData *sourceData = [NSData dataWithBytesNoCopy:(void *)filterData.data() + length:filterData.size() freeWhenDone:NO]; NSData *filteredData = [styleFilter filterData:sourceData]; - if (response.error) { - tempResult.error = std::make_unique(response.error->reason, - response.error->message, - response.error->retryAfter); - } - tempResult.noContent = response.noContent; - tempResult.notModified = response.notModified; - tempResult.mustRevalidate = response.mustRevalidate; - tempResult.modified = response.modified; - tempResult.expires = response.expires; - tempResult.etag = response.etag; - - // Set the response data - tempResult.data = - std::make_shared((const char*)[filteredData bytes], [filteredData length]); - + tempResult = std::string((const char*)[filteredData bytes], [filteredData length]); } return tempResult; diff --git a/src/mbgl/plugin/plugin_style_filter.cpp b/src/mbgl/plugin/plugin_style_filter.cpp index a0908f492f72..546de4f2c7aa 100644 --- a/src/mbgl/plugin/plugin_style_filter.cpp +++ b/src/mbgl/plugin/plugin_style_filter.cpp @@ -2,8 +2,8 @@ using namespace mbgl::style; -// This method -const mbgl::Response PluginStyleFilter::FilterResponse(const Response& res) { +// This method will call the lambda if it exists +const std::string PluginStyleFilter::filterResponse(const std::string& res) { if (_filterStyleFunction) { auto tempResult = _filterStyleFunction(res); return tempResult; diff --git a/src/mbgl/plugin/plugin_style_filter.hpp b/src/mbgl/plugin/plugin_style_filter.hpp index 3527f64cbba8..9d12703fbf99 100644 --- a/src/mbgl/plugin/plugin_style_filter.hpp +++ b/src/mbgl/plugin/plugin_style_filter.hpp @@ -8,12 +8,12 @@ namespace style { class PluginStyleFilter { public: - using OnFilterStyle = std::function; + using OnFilterStyle = std::function; OnFilterStyle _filterStyleFunction; // This method - const Response FilterResponse(const Response& res); + const std::string filterResponse(const std::string& styleData); }; } // namespace style diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index 16c699e4ece6..b42eaa9a5d49 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -45,7 +45,7 @@ void Style::Impl::loadJSON(const std::string& json_) { observer->onStyleLoading(); url.clear(); - parse(json_); + filterThenParse(json_); } void Style::Impl::loadURL(const std::string& url_) { @@ -75,25 +75,27 @@ void Style::Impl::loadURL(const std::string& url_) { } else if (res.notModified || res.noContent) { return; } else { - filterThenParse(res); + filterThenParse(*res.data); } }); } -void Style::Impl::filterThenParse(const Response& res) { + +void Style::Impl::filterThenParse(const std::string& styleData) { if (_styleFilters.size() == 0) { - parse(*res.data); + parse(styleData); return; } // Otherwise, go through the chain of filters - Response tempResult = res; + std::string filteredStyle = styleData; for (auto filter : _styleFilters) { - tempResult = filter->FilterResponse(tempResult); + filteredStyle = filter->filterResponse(filteredStyle); } - parse(*tempResult.data); + parse(filteredStyle); } + void Style::Impl::parse(const std::string& json_) { Parser parser; diff --git a/src/mbgl/style/style_impl.hpp b/src/mbgl/style/style_impl.hpp index 3a518ce866ce..ef4877a4f6c4 100644 --- a/src/mbgl/style/style_impl.hpp +++ b/src/mbgl/style/style_impl.hpp @@ -69,7 +69,7 @@ class Style::Impl : public SpriteLoaderObserver, // Add style parsing filter void addStyleFilter(std::shared_ptr); - void filterThenParse(const Response& res); + void filterThenParse(const std::string& styleData); std::string getName() const; CameraOptions getDefaultCamera() const; From 9337cf1de85fe32c017a01830a35c0ffdf7b9075 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 26 Jul 2025 04:30:30 +0000 Subject: [PATCH 18/49] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/mbgl/style/style_impl.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index b42eaa9a5d49..fb09eb396315 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -80,7 +80,6 @@ void Style::Impl::loadURL(const std::string& url_) { }); } - void Style::Impl::filterThenParse(const std::string& styleData) { if (_styleFilters.size() == 0) { parse(styleData); @@ -95,7 +94,6 @@ void Style::Impl::filterThenParse(const std::string& styleData) { parse(filteredStyle); } - void Style::Impl::parse(const std::string& json_) { Parser parser; From b10ecb07b9061ac86a27414692c61cb8d4b407d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sat, 26 Jul 2025 00:35:04 -0400 Subject: [PATCH 19/49] Minor cleanup --- src/mbgl/style/style_impl.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mbgl/style/style_impl.hpp b/src/mbgl/style/style_impl.hpp index ef4877a4f6c4..7a203b7074d7 100644 --- a/src/mbgl/style/style_impl.hpp +++ b/src/mbgl/style/style_impl.hpp @@ -28,7 +28,6 @@ namespace mbgl { class FileSource; class AsyncRequest; class SpriteLoader; -class Response; namespace style { @@ -69,7 +68,6 @@ class Style::Impl : public SpriteLoaderObserver, // Add style parsing filter void addStyleFilter(std::shared_ptr); - void filterThenParse(const std::string& styleData); std::string getName() const; CameraOptions getDefaultCamera() const; @@ -98,6 +96,7 @@ class Style::Impl : public SpriteLoaderObserver, bool loaded = false; private: + void filterThenParse(const std::string& styleData); void parse(const std::string&); std::vector> _styleFilters; From 432f16f4f42471123dd99825e9e424c22b6ded3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sat, 26 Jul 2025 00:44:50 -0400 Subject: [PATCH 20/49] Cleanup cruft --- src/mbgl/plugin/feature_collection.hpp | 3 - src/mbgl/plugin/plugin_layer_render.cpp | 95 ------------------------- 2 files changed, 98 deletions(-) diff --git a/src/mbgl/plugin/feature_collection.hpp b/src/mbgl/plugin/feature_collection.hpp index 5ea0c639e571..a4199a110747 100644 --- a/src/mbgl/plugin/feature_collection.hpp +++ b/src/mbgl/plugin/feature_collection.hpp @@ -49,9 +49,6 @@ class FeatureCollection { FeatureCollection(OverscaledTileID tileID) : _featureCollectionTileID(tileID) {}; std::vector> _features; - - // TODO: Open question about this.. should feature collections be tied to tile id? - // TODO: Question: Is overscaled the right thing or just canonical? OverscaledTileID _featureCollectionTileID; }; diff --git a/src/mbgl/plugin/plugin_layer_render.cpp b/src/mbgl/plugin/plugin_layer_render.cpp index 64cd64f547d7..8b57e8d071eb 100644 --- a/src/mbgl/plugin/plugin_layer_render.cpp +++ b/src/mbgl/plugin/plugin_layer_render.cpp @@ -13,11 +13,6 @@ #include #include #include - -// TODO: Remove -#include -// #define C_LOG_TILES 1 - #include #include @@ -95,15 +90,6 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis std::vector removedTiles; bool removeAllTiles = ((renderTiles == nullptr) || (renderTiles->empty())); - // TODO: Remove -#ifdef C_LOG_TILES - static int passCount = 0; - passCount++; - if (removeAllTiles) { - std::cout << passCount << ": Remove All Tiles\n"; - } -#endif - // Get list of tiles to remove and then remove them for (auto currentCollection : _featureCollectionByTile) { if (removeAllTiles || !hasRenderTile(currentCollection.first)) { @@ -116,11 +102,6 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis if (pluginLayer._featureCollectionUnloadedFunction) { pluginLayer._featureCollectionUnloadedFunction(featureCollection); } -#ifdef C_LOG_TILES - // TODO: Remove this logging - std::cout << passCount << ": Removing Feature Collection for Tile: " << (int)tileID.canonical.z << "," - << tileID.canonical.x << "," << tileID.canonical.y << "\n"; -#endif _featureCollectionByTile.erase(tileID); } } @@ -135,16 +116,8 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis const auto& tileID = tile.getOverscaledTileID(); if (!hasRenderTile(tileID)) { -#ifdef C_LOG_TILES - std::cout << passCount << ": Tile was there and not anymore\n"; -#endif } - // TODO: Remove - // if ((tileID.canonical.x == 1289) && (tileID.canonical.y == 879)) { - // std::cout << "Found tile\n"; - // } - const auto* optRenderData = getRenderDataForPass(tile, drawPass); if (!optRenderData || !optRenderData->bucket || !optRenderData->bucket->hasData()) { removeTile(drawPass, tileID); @@ -152,8 +125,6 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis } const auto& renderData = *optRenderData; auto& bucket = static_cast(*renderData.bucket); - // TODO: Remove - // std::cout << "Found Bucket\n"; auto featureCollection = bucket._featureCollection; if (featureCollection == nullptr) { continue; @@ -172,72 +143,12 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis if (pluginLayer._featureCollectionLoadedFunction) { if (featureCollection != nullptr) { pluginLayer._featureCollectionLoadedFunction(featureCollection); -#ifdef C_LOG_TILES - // TODO: Remove logging - std::cout << passCount << ": Adding Feature Collection for Tile: " << (int)tileID.canonical.z - << "," << tileID.canonical.x << "," << tileID.canonical.y << "\n"; -#endif } } - - /* - - 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(drawPass, tileID); - } - setRenderTileBucketID(tileID, bucket.getID()); - */ } } } - /* - if (!renderTiles || renderTiles->empty() || passes == RenderPass::None) { -// removeAllDrawables(); - return; - } - - // Set up a layer group - if (!layerGroup) { - if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, - 64, // initialCapacity= - getID())) { - setLayerGroup(std::move(layerGroup_), changes); - } else { - return; - } - } - - auto* tileLayerGroup = static_cast(layerGroup.get()); - -// const auto& evaluated = static_cast(*evaluatedProperties).evaluated; - - constexpr auto drawPass = RenderPass::Translucent; - - for (const RenderTile& tile : *renderTiles) { - const auto& tileID = tile.getOverscaledTileID(); - - const auto* optRenderData = getRenderDataForPass(tile, drawPass); - if (!optRenderData || !optRenderData->bucket || !optRenderData->bucket->hasData()) { - removeTile(drawPass, tileID); - continue; - } - - const auto& renderData = *optRenderData; - auto& bucket = static_cast(*renderData.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(drawPass, tileID); - } - setRenderTileBucketID(tileID, bucket.getID()); - } - - */ - // create layer group if (!layerGroup) { if (auto layerGroup_ = context.createLayerGroup(layerIndex, /*initialCapacity=*/1, getID())) { @@ -321,17 +232,11 @@ void RenderPluginLayer::evaluate(const PropertyEvaluationParameters& parameters) } std::string jsonProperties = pm.propertiesAsJSON(); - i->_updateLayerPropertiesFunction(jsonProperties); auto properties = makeMutable( staticImmutableCast(baseImpl)); passes = RenderPass::Pass3D; - // passes = RenderPass::Pass3D; (evaluated.get().constantOr(1.0) > 0 && - // evaluated.get().constantOr(Color::black()).a > 0 && - // evaluated.get().constantOr(1.0) > 0) - // ? RenderPass::Translucent - // : RenderPass::None; properties->renderPasses = mbgl::underlying_type(passes); evaluatedProperties = std::move(properties); } From 4413910bc629454efd2b900aa606653616f1ff47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sat, 26 Jul 2025 00:52:42 -0400 Subject: [PATCH 21/49] Added style filter to cmake list --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f24a62dc5d4..6b5235795c08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -972,11 +972,13 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_properties.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_impl.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_factory.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_style_filter.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_render.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_properties.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_impl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_factory.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_style_filter.cpp ) From 2c0c768602d35fc6ca091c1992e8afaeddd9c8d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sat, 26 Jul 2025 00:58:50 -0400 Subject: [PATCH 22/49] Added header to fix build error --- src/mbgl/plugin/plugin_style_filter.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mbgl/plugin/plugin_style_filter.hpp b/src/mbgl/plugin/plugin_style_filter.hpp index 9d12703fbf99..985c0ea59fe9 100644 --- a/src/mbgl/plugin/plugin_style_filter.hpp +++ b/src/mbgl/plugin/plugin_style_filter.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace mbgl { From b6a59e3a6307fc5a4340bf452792920c9d3899e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sat, 26 Jul 2025 13:14:10 -0400 Subject: [PATCH 23/49] Initial commit of adding support for custom protocols --- bazel/core.bzl | 1 + include/mbgl/storage/file_source.hpp | 3 +- include/mbgl/storage/file_source_manager.hpp | 6 + platform/BUILD.bazel | 2 + platform/darwin/BUILD.bazel | 2 + platform/darwin/app/PluginProtocolExample.h | 9 ++ platform/darwin/app/PluginProtocolExample.mm | 23 +++ platform/darwin/bazel/files.bzl | 4 +- .../darwin/src/MLNPluginProtocolHandler.h | 25 +++ .../darwin/src/MLNPluginProtocolHandler.mm | 23 +++ platform/default/BUILD.bazel | 1 + .../src/mbgl/storage/main_resource_loader.cpp | 114 +++++++------ .../src/mbgl/storage/plugin_file_source.cpp | 153 ++++++++++++++++++ platform/ios/app/MBXViewController.mm | 9 +- platform/ios/src/MLNMapView.h | 5 + platform/ios/src/MLNMapView.mm | 71 +++++++- src/mbgl/plugin/plugin_file_source.hpp | 52 ++++++ src/mbgl/storage/file_source_manager.cpp | 35 ++-- 18 files changed, 477 insertions(+), 61 deletions(-) create mode 100644 platform/darwin/app/PluginProtocolExample.h create mode 100644 platform/darwin/app/PluginProtocolExample.mm create mode 100644 platform/darwin/src/MLNPluginProtocolHandler.h create mode 100644 platform/darwin/src/MLNPluginProtocolHandler.mm create mode 100644 platform/default/src/mbgl/storage/plugin_file_source.cpp create mode 100644 src/mbgl/plugin/plugin_file_source.hpp diff --git a/bazel/core.bzl b/bazel/core.bzl index b27bbd8d925b..58b35f7aa3ee 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -4,6 +4,7 @@ MLN_LAYER_PLUGIN_HEADERS = [ "src/mbgl/plugin/plugin_layer_impl.hpp", "src/mbgl/plugin/plugin_layer_render.hpp", "src/mbgl/plugin/plugin_layer_properties.hpp", + "src/mbgl/plugin/plugin_file_source.hpp", ] MLN_LAYER_PLUGIN_SOURCE = [ diff --git a/include/mbgl/storage/file_source.hpp b/include/mbgl/storage/file_source.hpp index 6a70154df417..13626bf13103 100644 --- a/include/mbgl/storage/file_source.hpp +++ b/include/mbgl/storage/file_source.hpp @@ -26,9 +26,10 @@ enum FileSourceType : uint8_t { Network, Mbtiles, Pmtiles, - ResourceLoader ///< %Resource loader acts as a proxy and has logic + ResourceLoader, ///< %Resource loader acts as a proxy and has logic /// for request delegation to Asset, Cache, and other /// file sources. + Custom // These are the plugin file resource types }; // TODO: Rename to ResourceProvider to avoid confusion with diff --git a/include/mbgl/storage/file_source_manager.hpp b/include/mbgl/storage/file_source_manager.hpp index b6ef59c09b35..78d80464768f 100644 --- a/include/mbgl/storage/file_source_manager.hpp +++ b/include/mbgl/storage/file_source_manager.hpp @@ -43,6 +43,12 @@ class FileSourceManager { // a FileSourceType invocation has no effect. virtual FileSourceFactory unRegisterFileSourceFactory(FileSourceType) noexcept; + // Registers a custom file source + virtual void registerCustomFileSource(std::shared_ptr) noexcept; + + // Returns an array of custom file sources + virtual std::vector> getCustomFileSources() noexcept; + protected: FileSourceManager(); class Impl; diff --git a/platform/BUILD.bazel b/platform/BUILD.bazel index f39d31d1ee8e..ff7ccb6c5f68 100644 --- a/platform/BUILD.bazel +++ b/platform/BUILD.bazel @@ -268,6 +268,8 @@ objc_library( srcs = [ "//platform/darwin:app/PluginLayerExample.h", "//platform/darwin:app/PluginLayerExample.mm", + "//platform/darwin:app/PluginProtocolExample.h", + "//platform/darwin:app/PluginProtocolExample.mm", "//platform/darwin:app/PluginLayerExampleMetalRendering.h", "//platform/darwin:app/PluginLayerExampleMetalRendering.mm", "//platform/darwin:app/CustomStyleLayerExample.h", diff --git a/platform/darwin/BUILD.bazel b/platform/darwin/BUILD.bazel index dcc0a8bcbac4..4b28e1e0994e 100644 --- a/platform/darwin/BUILD.bazel +++ b/platform/darwin/BUILD.bazel @@ -303,6 +303,8 @@ exports_files( "app/PluginLayerExample.mm", "app/PluginLayerExampleMetalRendering.h", "app/PluginLayerExampleMetalRendering.mm", + "app/PluginProtocolExample.h", + "app/PluginProtocolExample.mm", "test/amsterdam.geojson", "test/MLNSDKTestHelpers.swift", "app/CustomStyleLayerExample.h", diff --git a/platform/darwin/app/PluginProtocolExample.h b/platform/darwin/app/PluginProtocolExample.h new file mode 100644 index 000000000000..63cf0fee0d99 --- /dev/null +++ b/platform/darwin/app/PluginProtocolExample.h @@ -0,0 +1,9 @@ +#import "MLNPluginProtocolHandler.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PluginProtocolExample : MLNPluginProtocolHandler + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/app/PluginProtocolExample.mm b/platform/darwin/app/PluginProtocolExample.mm new file mode 100644 index 000000000000..676b21ffb77b --- /dev/null +++ b/platform/darwin/app/PluginProtocolExample.mm @@ -0,0 +1,23 @@ +#import "PluginProtocolExample.h" + +@implementation PluginProtocolExample + +-(BOOL)canRequestResource:(MLNPluginProtocolHandlerResource *)resource { + if ([resource.resourceURL containsString:@"pluginProtocol"]) { + return YES; + } + return NO; +} + +-(MLNPluginProtocolHandlerResponse *)requestResource:(MLNPluginProtocolHandlerResource *)resource { + + NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"PluginLayerTestStyle.json" ofType:nil]]; + + MLNPluginProtocolHandlerResponse *response = [[MLNPluginProtocolHandlerResponse alloc] init]; + response.data = data; + return response; + +} + + +@end diff --git a/platform/darwin/bazel/files.bzl b/platform/darwin/bazel/files.bzl index 560189cd69c0..7af769a63ab1 100644 --- a/platform/darwin/bazel/files.bzl +++ b/platform/darwin/bazel/files.bzl @@ -108,6 +108,7 @@ MLN_DARWIN_OBJC_HEADERS = [ "src/NSValue+MLNAdditions.h", "src/MLNPluginLayer.h", "src/MLNPluginStyleLayer.h", + "src/MLNPluginProtocolHandler.h" ] MLN_DARWIN_OBJCPP_HEADERS = [ @@ -222,7 +223,8 @@ MLN_DARWIN_PUBLIC_OBJCPP_SOURCE = [ "src/NSPredicate+MLNAdditions.mm", "src/NSValue+MLNStyleAttributeAdditions.mm", "src/MLNPluginLayer.mm", - "src/MLNPluginStyleLayer.mm" + "src/MLNPluginStyleLayer.mm", + "src/MLNPluginProtocolHandler.mm" ] MLN_DARWIN_PUBLIC_OBJCPP_CUSTOM_DRAWABLE_SOURCE = [ diff --git a/platform/darwin/src/MLNPluginProtocolHandler.h b/platform/darwin/src/MLNPluginProtocolHandler.h new file mode 100644 index 000000000000..469076e15c1c --- /dev/null +++ b/platform/darwin/src/MLNPluginProtocolHandler.h @@ -0,0 +1,25 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MLNPluginProtocolHandlerResource : NSObject + +@property NSString *resourceURL; + +@end + +@interface MLNPluginProtocolHandlerResponse : NSObject + +@property NSData *data; + +@end + +@interface MLNPluginProtocolHandler : NSObject + +-(BOOL)canRequestResource:(MLNPluginProtocolHandlerResource *)resource; + +-(MLNPluginProtocolHandlerResponse *)requestResource:(MLNPluginProtocolHandlerResource *)resource; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MLNPluginProtocolHandler.mm b/platform/darwin/src/MLNPluginProtocolHandler.mm new file mode 100644 index 000000000000..0f7700a5bba2 --- /dev/null +++ b/platform/darwin/src/MLNPluginProtocolHandler.mm @@ -0,0 +1,23 @@ +#import "MLNPluginProtocolHandler.h" + +@implementation MLNPluginProtocolHandler + +-(BOOL)canRequestResource:(MLNPluginProtocolHandlerResource *)resource { + // Base class returns false + return NO; +} + +-(MLNPluginProtocolHandlerResponse *)requestResource:(MLNPluginProtocolHandlerResource *)resource { + // Base class does nothing + return nil; +} + + +@end + +@implementation MLNPluginProtocolHandlerResource +@end + + +@implementation MLNPluginProtocolHandlerResponse +@end diff --git a/platform/default/BUILD.bazel b/platform/default/BUILD.bazel index e22c12db9526..7dbb1bb097ef 100644 --- a/platform/default/BUILD.bazel +++ b/platform/default/BUILD.bazel @@ -58,6 +58,7 @@ cc_library( "src/mbgl/storage/offline_database.cpp", "src/mbgl/storage/offline_download.cpp", "src/mbgl/storage/online_file_source.cpp", + "src/mbgl/storage/plugin_file_source.cpp", "src/mbgl/storage/pmtiles_file_source.cpp", "src/mbgl/storage/sqlite3.cpp", "src/mbgl/text/bidi.cpp", diff --git a/platform/default/src/mbgl/storage/main_resource_loader.cpp b/platform/default/src/mbgl/storage/main_resource_loader.cpp index 2f523f1e8d2e..a477c815718c 100644 --- a/platform/default/src/mbgl/storage/main_resource_loader.cpp +++ b/platform/default/src/mbgl/storage/main_resource_loader.cpp @@ -65,54 +65,67 @@ class MainResourceLoaderThread { // the sources were able to request a resource. const std::size_t tasksSize = tasks.size(); - // Waterfall resource request processing and return early once resource was requested. - if (assetFileSource && assetFileSource->canRequest(resource)) { - // Asset request - tasks[req] = assetFileSource->request(resource, callback); - } else if (mbtilesFileSource && mbtilesFileSource->canRequest(resource)) { - // Local file request - tasks[req] = mbtilesFileSource->request(resource, callback); - } else if (pmtilesFileSource && pmtilesFileSource->canRequest(resource)) { - // Local file request - tasks[req] = pmtilesFileSource->request(resource, callback); - } else if (localFileSource && localFileSource->canRequest(resource)) { - // Local file request - tasks[req] = localFileSource->request(resource, callback); - } else if (databaseFileSource && databaseFileSource->canRequest(resource)) { - // Try cache only request if needed. - if (resource.loadingMethod == Resource::LoadingMethod::CacheOnly) { - tasks[req] = databaseFileSource->request(resource, callback); - } else { - // Cache request with fallback to network with cache control - tasks[req] = databaseFileSource->request(resource, [=, this](const Response& response) { - Resource res = resource; - - // Resource is in the cache - if (!response.noContent) { - if (response.isUsable()) { - callback(response); - // Set the priority of existing resource to low if it's expired but usable. - res.setPriority(Resource::Priority::Low); - } else { - // Set prior data only if it was not returned to - // the requester. Once we get 304 response from - // the network, we will forward response to the - // requester. - res.priorData = response.data; - } - - // Copy response fields for cache control request - res.priorModified = response.modified; - res.priorExpires = response.expires; - res.priorEtag = response.etag; - } + // Go through custom handlers + bool requestHandledByCustomHandler = false; + auto fm = FileSourceManager::get(); + for (auto customFileSource: fm->getCustomFileSources()) { + if (customFileSource->canRequest(resource)) { + tasks[req] = customFileSource->request(resource, callback); + requestHandledByCustomHandler = true; + break; + } + } - tasks[req] = requestFromNetwork(res, std::move(tasks[req])); - }); + if (!requestHandledByCustomHandler) { + // Waterfall resource request processing and return early once resource was requested. + if (assetFileSource && assetFileSource->canRequest(resource)) { + // Asset request + tasks[req] = assetFileSource->request(resource, callback); + } else if (mbtilesFileSource && mbtilesFileSource->canRequest(resource)) { + // Local file request + tasks[req] = mbtilesFileSource->request(resource, callback); + } else if (pmtilesFileSource && pmtilesFileSource->canRequest(resource)) { + // Local file request + tasks[req] = pmtilesFileSource->request(resource, callback); + } else if (localFileSource && localFileSource->canRequest(resource)) { + // Local file request + tasks[req] = localFileSource->request(resource, callback); + } else if (databaseFileSource && databaseFileSource->canRequest(resource)) { + // Try cache only request if needed. + if (resource.loadingMethod == Resource::LoadingMethod::CacheOnly) { + tasks[req] = databaseFileSource->request(resource, callback); + } else { + // Cache request with fallback to network with cache control + tasks[req] = databaseFileSource->request(resource, [=, this](const Response& response) { + Resource res = resource; + + // Resource is in the cache + if (!response.noContent) { + if (response.isUsable()) { + callback(response); + // Set the priority of existing resource to low if it's expired but usable. + res.setPriority(Resource::Priority::Low); + } else { + // Set prior data only if it was not returned to + // the requester. Once we get 304 response from + // the network, we will forward response to the + // requester. + res.priorData = response.data; + } + + // Copy response fields for cache control request + res.priorModified = response.modified; + res.priorExpires = response.expires; + res.priorEtag = response.etag; + } + + tasks[req] = requestFromNetwork(res, std::move(tasks[req])); + }); + } + } else if (auto networkReq = requestFromNetwork(resource, nullptr)) { + // Get from the online file source + tasks[req] = std::move(networkReq); } - } else if (auto networkReq = requestFromNetwork(resource, nullptr)) { - // Get from the online file source - tasks[req] = std::move(networkReq); } // If no new tasks were added, notify client that request cannot be processed. @@ -180,6 +193,15 @@ class MainResourceLoader::Impl { } bool canRequest(const Resource& resource) const { + + // Check the custom file sources + auto fm = FileSourceManager::get(); + for (auto customFileSource: fm->getCustomFileSources()) { + if (customFileSource->canRequest(resource)) { + return true; + } + } + return (assetFileSource && assetFileSource->canRequest(resource)) || (localFileSource && localFileSource->canRequest(resource)) || (databaseFileSource && databaseFileSource->canRequest(resource)) || diff --git a/platform/default/src/mbgl/storage/plugin_file_source.cpp b/platform/default/src/mbgl/storage/plugin_file_source.cpp new file mode 100644 index 000000000000..74cd141e8f23 --- /dev/null +++ b/platform/default/src/mbgl/storage/plugin_file_source.cpp @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mbgl { + +void PluginFileSource::setProtocolPrefix(const std::string &protocolPrefix) { + +} + + + +class PluginFileSource::Impl { +public: + explicit Impl(const ActorRef&, const ResourceOptions& resourceOptions_, const ClientOptions& clientOptions_) + : resourceOptions(resourceOptions_.clone()), + clientOptions(clientOptions_.clone()) {} + + OnRequestResource _requestFunction; + void setOnRequestResourceFunction(OnRequestResource requestFunction) { + _requestFunction = requestFunction; + } + + void request(const Resource& resource, const ActorRef& req) { + +// if (_onCanRequestResourceFunction) { +// if (!_onCanRequestResourceFunction(resource)) { +// Response response; +// response.error = std::make_unique(Response::Error::Reason::Other, "This plugin protocol handler cannot service this resource"); +// req.invoke(&FileSourceRequest::setResponse, response); +// return; +// } +// } + +// if (!acceptsURL(resource.url)) { +// Response response; +// response.error = std::make_unique(Response::Error::Reason::Other, "Invalid file URL"); +// req.invoke(&FileSourceRequest::setResponse, response); +// return; +// } + +// void requestLocalFile(const std::string& path, +// const ActorRef& req, +// const std::optional>& dataRange) { + + Response response; + if (_requestFunction) { + response = _requestFunction(resource); + } else { + response.error = std::make_unique(Response::Error::Reason::Other, + std::string("Custom Protocol Handler Not Configured Correctly")); + } + req.invoke(&FileSourceRequest::setResponse, response); + + } + + void setResourceOptions(ResourceOptions options) { + std::lock_guard lock(resourceOptionsMutex); + resourceOptions = options; + } + + ResourceOptions getResourceOptions() { + std::lock_guard lock(resourceOptionsMutex); + return resourceOptions.clone(); + } + + void setClientOptions(ClientOptions options) { + std::lock_guard lock(clientOptionsMutex); + clientOptions = options; + } + + ClientOptions getClientOptions() { + std::lock_guard lock(clientOptionsMutex); + return clientOptions.clone(); + } + +private: + mutable std::mutex resourceOptionsMutex; + mutable std::mutex clientOptionsMutex; + ResourceOptions resourceOptions; + ClientOptions clientOptions; +}; + +void PluginFileSource::setOnCanRequestFunction(OnCanRequestResource requestFunction) { + _onCanRequestResourceFunction = requestFunction; +// impl.get()->actor().invoke(&Impl::setOnCanRequestFunction, requestFunction); +} + +void PluginFileSource::setOnRequestResourceFunction(OnRequestResource requestFunction) { + impl.get()->actor().invoke(&Impl::setOnRequestResourceFunction, requestFunction); +} + + +PluginFileSource::PluginFileSource(const ResourceOptions& resourceOptions, const ClientOptions& clientOptions) + : impl(std::make_unique>( + util::makeThreadPrioritySetter(platform::EXPERIMENTAL_THREAD_PRIORITY_FILE), + "LocalFileSource", + resourceOptions.clone(), + clientOptions.clone())) {} + +PluginFileSource::~PluginFileSource() = default; + +std::unique_ptr PluginFileSource::request(const Resource& resource, Callback callback) { + auto req = std::make_unique(std::move(callback)); + + impl->actor().invoke(&Impl::request, resource, req->actor()); + + return req; +} + +bool PluginFileSource::canRequest(const Resource& resource) const { + if (_onCanRequestResourceFunction) { + return _onCanRequestResourceFunction(resource); + } + return false; +} + +void PluginFileSource::pause() { + impl->pause(); +} + +void PluginFileSource::resume() { + impl->resume(); +} + +void PluginFileSource::setResourceOptions(ResourceOptions options) { + impl->actor().invoke(&Impl::setResourceOptions, options.clone()); +} + +ResourceOptions PluginFileSource::getResourceOptions() { + return impl->actor().ask(&Impl::getResourceOptions).get(); +} + +void PluginFileSource::setClientOptions(ClientOptions options) { + impl->actor().invoke(&Impl::setClientOptions, options.clone()); +} + +ClientOptions PluginFileSource::getClientOptions() { + return impl->actor().ask(&Impl::getClientOptions).get(); +} + +} // namespace mbgl diff --git a/platform/ios/app/MBXViewController.mm b/platform/ios/app/MBXViewController.mm index 4c13a767ea51..7093c19c65d2 100644 --- a/platform/ios/app/MBXViewController.mm +++ b/platform/ios/app/MBXViewController.mm @@ -27,6 +27,7 @@ #import "PluginLayerExample.h" #import "PluginLayerExampleMetalRendering.h" #import "MLNPluginStyleLayer.h" +#import "PluginProtocolExample.h" static const CLLocationCoordinate2D WorldTourDestinations[] = { { .latitude = 38.8999418, .longitude = -77.033996 }, @@ -281,7 +282,8 @@ -(void)addPluginLayers { [self.mapView addPluginLayerType:[PluginLayerExample class]]; [self.mapView addPluginLayerType:[PluginLayerExampleMetalRendering class]]; - + [self.mapView addPluginProtocolHandler:[PluginProtocolExample class]]; + } - (void)viewDidLoad @@ -2331,6 +2333,11 @@ - (void)setStyles self.styleURLs = [NSMutableArray array]; + /// This is hte same style as above but copied locally and the three instances of the metal plug-in layer added to the style + /// Look for "type": "plugin-layer-metal-rendering" in the PluginLayerTestStyle.json for an example of how the layer is defined + [self.styleNames addObject:@"MapLibre Basic - Local With Plugin Loader"]; + NSURL *pluginstyleurl = [NSURL URLWithString:@"pluginProtocol://PluginLayerTestStyle.json"]; + [self.styleURLs addObject:pluginstyleurl]; /// Style that does not require an `apiKey` nor any further configuration diff --git a/platform/ios/src/MLNMapView.h b/platform/ios/src/MLNMapView.h index 1e800fafe188..e308ba4964ba 100644 --- a/platform/ios/src/MLNMapView.h +++ b/platform/ios/src/MLNMapView.h @@ -2276,6 +2276,11 @@ vertically on the map. */ - (void)addPluginLayerType:(Class)pluginLayerClass; +/** + Adds a plug-in protocol handler that is external to this library + */ +- (void)addPluginProtocolHandler:(Class)pluginProtocolHandlerClass; + @end NS_ASSUME_NONNULL_END diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index 23313088fa14..6ad9a3582041 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -30,9 +30,11 @@ #include #include #include +#include #include #include #include +#include #import "Mapbox.h" #import "MLNShape_Private.h" @@ -80,6 +82,7 @@ #import "MLNActionJournalOptions_Private.h" #import "MLNMapProjection.h" #import "MLNPluginLayer.h" +#import "MLNPluginProtocolHandler.h" #import "MLNStyleLayerManager.h" #include "MLNPluginStyleLayer_Private.h" @@ -452,8 +455,9 @@ @interface MLNMapView () pluginSource = std::make_shared(resourceOptions, clientOptions); + pluginSource->setOnRequestResourceFunction([weakHandler, weakSelf](const mbgl::Resource &resource) -> mbgl::Response { + mbgl::Response tempResult; + + __strong MLNPluginProtocolHandler *strongHandler = weakHandler; + if (strongHandler) { + + MLNPluginProtocolHandlerResource *res = [weakSelf resourceFromCoreResource:resource]; + MLNPluginProtocolHandlerResponse *response = [strongHandler requestResource:res]; + if (response.data) { + tempResult.data = std::make_shared((const char*)[response.data bytes], + [response.data length]); + } + } + + return tempResult; + + }); + + pluginSource->setOnCanRequestFunction([weakHandler, weakSelf](const mbgl::Resource &resource) -> bool{ + @autoreleasepool { + __strong MLNPluginProtocolHandler *strongHandler = weakHandler; + if (!strongHandler) { + return false; + } + + MLNPluginProtocolHandlerResource *res = [weakSelf resourceFromCoreResource:resource]; + BOOL tempResult = [strongHandler canRequestResource:res]; + + return tempResult; + + } + }); + + auto fileSourceManager = mbgl::FileSourceManager::get(); + fileSourceManager->registerCustomFileSource(pluginSource); + +} + + + - (NSArray*)getActionJournalLogFiles { const auto& actionJournal = _mbglMap->getActionJournal(); diff --git a/src/mbgl/plugin/plugin_file_source.hpp b/src/mbgl/plugin/plugin_file_source.hpp new file mode 100644 index 000000000000..6e78175257cb --- /dev/null +++ b/src/mbgl/plugin/plugin_file_source.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include + +namespace mbgl { + +namespace util { +template +class Thread; +} // namespace util + +class PluginFileSourceRequest { + +}; + +class PluginFileSourceResponse { + +}; + +class PluginFileSource : public FileSource { +public: + PluginFileSource(const ResourceOptions& resourceOptions, const ClientOptions& clientOptions); + ~PluginFileSource() override; + + using OnCanRequestResource = std::function; + using OnRequestResource = std::function; + + void setOnCanRequestFunction(OnCanRequestResource requestFunction); + void setOnRequestResourceFunction(OnRequestResource requestFunction); + + std::unique_ptr request(const Resource&, Callback) override; + bool canRequest(const Resource&) const override; + void pause() override; + void resume() override; + + void setProtocolPrefix(const std::string &); + + void setResourceOptions(ResourceOptions) override; + ResourceOptions getResourceOptions() override; + + void setClientOptions(ClientOptions) override; + ClientOptions getClientOptions() override; + +private: + OnCanRequestResource _onCanRequestResourceFunction; + class Impl; + std::unique_ptr> impl; +}; + +} // namespace mbgl diff --git a/src/mbgl/storage/file_source_manager.cpp b/src/mbgl/storage/file_source_manager.cpp index 2e21443b82a6..3f97de6d65cd 100644 --- a/src/mbgl/storage/file_source_manager.cpp +++ b/src/mbgl/storage/file_source_manager.cpp @@ -13,10 +13,10 @@ namespace mbgl { struct FileSourceInfo { FileSourceInfo(FileSourceType type_, std::string id_, std::weak_ptr fileSource_) - : type(type_), - id(std::move(id_)), - fileSource(std::move(fileSource_)) {} - + : type(type_), + id(std::move(id_)), + fileSource(std::move(fileSource_)) {} + FileSourceType type; std::string id; std::weak_ptr fileSource; @@ -27,10 +27,11 @@ class FileSourceManager::Impl { std::list fileSources; std::map fileSourceFactories; std::recursive_mutex mutex; + std::vector> customFileSources; }; FileSourceManager::FileSourceManager() - : impl(std::make_unique()) {} +: impl(std::make_unique()) {} FileSourceManager::~FileSourceManager() = default; @@ -38,17 +39,17 @@ std::shared_ptr FileSourceManager::getFileSource(FileSourceType type const ResourceOptions& resourceOptions, const ClientOptions& clientOptions) noexcept { std::lock_guard lock(impl->mutex); - + // Remove released file sources. for (auto it = impl->fileSources.begin(); it != impl->fileSources.end();) { it = it->fileSource.expired() ? impl->fileSources.erase(it) : ++it; } - + const auto context = reinterpret_cast(resourceOptions.platformContext()); std::string baseURL = resourceOptions.tileServerOptions().baseURL(); std::string id = baseURL + '|' + resourceOptions.apiKey() + '|' + resourceOptions.cachePath() + '|' + - util::toString(context); - + util::toString(context); + std::shared_ptr fileSource; auto fileSourceIt = std::find_if(impl->fileSources.begin(), impl->fileSources.end(), [type, &id](const auto& info) { return info.type == type && info.id == id; @@ -56,7 +57,7 @@ std::shared_ptr FileSourceManager::getFileSource(FileSourceType type if (fileSourceIt != impl->fileSources.end()) { fileSource = fileSourceIt->fileSource.lock(); } - + if (!fileSource) { auto it = impl->fileSourceFactories.find(type); if (it != impl->fileSourceFactories.end()) { @@ -65,7 +66,7 @@ std::shared_ptr FileSourceManager::getFileSource(FileSourceType type impl->fileSources.emplace_back(type, std::move(id), fileSource); } } - + return fileSource; } @@ -86,4 +87,16 @@ FileSourceManager::FileSourceFactory FileSourceManager::unRegisterFileSourceFact return factory; } +// Registers a custom file source factory +void FileSourceManager::registerCustomFileSource(std::shared_ptr fileSource) noexcept { + impl->customFileSources.push_back(fileSource); +} + +// Returns an array of custom file sources +std::vector> FileSourceManager::getCustomFileSources() noexcept { + return impl->customFileSources; +} + + + } // namespace mbgl From 73ca452bc8a89116c8089aa61508016656d8b9b3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 26 Jul 2025 17:22:03 +0000 Subject: [PATCH 24/49] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- include/mbgl/storage/file_source_manager.hpp | 2 +- platform/darwin/app/PluginProtocolExample.mm | 6 +- .../darwin/src/MLNPluginProtocolHandler.h | 4 +- .../src/mbgl/storage/main_resource_loader.cpp | 13 ++-- .../src/mbgl/storage/plugin_file_source.cpp | 75 ++++++++----------- platform/ios/app/MBXViewController.mm | 2 +- platform/ios/src/MLNMapView.mm | 30 ++++---- src/mbgl/plugin/plugin_file_source.hpp | 18 ++--- src/mbgl/storage/file_source_manager.cpp | 24 +++--- 9 files changed, 79 insertions(+), 95 deletions(-) diff --git a/include/mbgl/storage/file_source_manager.hpp b/include/mbgl/storage/file_source_manager.hpp index 78d80464768f..f6fe523e4260 100644 --- a/include/mbgl/storage/file_source_manager.hpp +++ b/include/mbgl/storage/file_source_manager.hpp @@ -48,7 +48,7 @@ class FileSourceManager { // Returns an array of custom file sources virtual std::vector> getCustomFileSources() noexcept; - + protected: FileSourceManager(); class Impl; diff --git a/platform/darwin/app/PluginProtocolExample.mm b/platform/darwin/app/PluginProtocolExample.mm index 676b21ffb77b..8915f9b514a6 100644 --- a/platform/darwin/app/PluginProtocolExample.mm +++ b/platform/darwin/app/PluginProtocolExample.mm @@ -10,13 +10,13 @@ -(BOOL)canRequestResource:(MLNPluginProtocolHandlerResource *)resource { } -(MLNPluginProtocolHandlerResponse *)requestResource:(MLNPluginProtocolHandlerResource *)resource { - + NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"PluginLayerTestStyle.json" ofType:nil]]; - + MLNPluginProtocolHandlerResponse *response = [[MLNPluginProtocolHandlerResponse alloc] init]; response.data = data; return response; - + } diff --git a/platform/darwin/src/MLNPluginProtocolHandler.h b/platform/darwin/src/MLNPluginProtocolHandler.h index 469076e15c1c..2d1714f31193 100644 --- a/platform/darwin/src/MLNPluginProtocolHandler.h +++ b/platform/darwin/src/MLNPluginProtocolHandler.h @@ -16,9 +16,9 @@ NS_ASSUME_NONNULL_BEGIN @interface MLNPluginProtocolHandler : NSObject --(BOOL)canRequestResource:(MLNPluginProtocolHandlerResource *)resource; +- (BOOL)canRequestResource:(MLNPluginProtocolHandlerResource *)resource; --(MLNPluginProtocolHandlerResponse *)requestResource:(MLNPluginProtocolHandlerResource *)resource; +- (MLNPluginProtocolHandlerResponse *)requestResource:(MLNPluginProtocolHandlerResource *)resource; @end diff --git a/platform/default/src/mbgl/storage/main_resource_loader.cpp b/platform/default/src/mbgl/storage/main_resource_loader.cpp index a477c815718c..208c109e5fe8 100644 --- a/platform/default/src/mbgl/storage/main_resource_loader.cpp +++ b/platform/default/src/mbgl/storage/main_resource_loader.cpp @@ -68,7 +68,7 @@ class MainResourceLoaderThread { // Go through custom handlers bool requestHandledByCustomHandler = false; auto fm = FileSourceManager::get(); - for (auto customFileSource: fm->getCustomFileSources()) { + for (auto customFileSource : fm->getCustomFileSources()) { if (customFileSource->canRequest(resource)) { tasks[req] = customFileSource->request(resource, callback); requestHandledByCustomHandler = true; @@ -98,7 +98,7 @@ class MainResourceLoaderThread { // Cache request with fallback to network with cache control tasks[req] = databaseFileSource->request(resource, [=, this](const Response& response) { Resource res = resource; - + // Resource is in the cache if (!response.noContent) { if (response.isUsable()) { @@ -112,13 +112,13 @@ class MainResourceLoaderThread { // requester. res.priorData = response.data; } - + // Copy response fields for cache control request res.priorModified = response.modified; res.priorExpires = response.expires; res.priorEtag = response.etag; } - + tasks[req] = requestFromNetwork(res, std::move(tasks[req])); }); } @@ -193,15 +193,14 @@ class MainResourceLoader::Impl { } bool canRequest(const Resource& resource) const { - // Check the custom file sources auto fm = FileSourceManager::get(); - for (auto customFileSource: fm->getCustomFileSources()) { + for (auto customFileSource : fm->getCustomFileSources()) { if (customFileSource->canRequest(resource)) { return true; } } - + return (assetFileSource && assetFileSource->canRequest(resource)) || (localFileSource && localFileSource->canRequest(resource)) || (databaseFileSource && databaseFileSource->canRequest(resource)) || diff --git a/platform/default/src/mbgl/storage/plugin_file_source.cpp b/platform/default/src/mbgl/storage/plugin_file_source.cpp index 74cd141e8f23..ca93611f3e49 100644 --- a/platform/default/src/mbgl/storage/plugin_file_source.cpp +++ b/platform/default/src/mbgl/storage/plugin_file_source.cpp @@ -15,54 +15,46 @@ namespace mbgl { -void PluginFileSource::setProtocolPrefix(const std::string &protocolPrefix) { - -} - - +void PluginFileSource::setProtocolPrefix(const std::string& protocolPrefix) {} class PluginFileSource::Impl { public: explicit Impl(const ActorRef&, const ResourceOptions& resourceOptions_, const ClientOptions& clientOptions_) : resourceOptions(resourceOptions_.clone()), clientOptions(clientOptions_.clone()) {} - + OnRequestResource _requestFunction; - void setOnRequestResourceFunction(OnRequestResource requestFunction) { - _requestFunction = requestFunction; - } - - void request(const Resource& resource, const ActorRef& req) { - -// if (_onCanRequestResourceFunction) { -// if (!_onCanRequestResourceFunction(resource)) { -// Response response; -// response.error = std::make_unique(Response::Error::Reason::Other, "This plugin protocol handler cannot service this resource"); -// req.invoke(&FileSourceRequest::setResponse, response); -// return; -// } -// } - -// if (!acceptsURL(resource.url)) { -// Response response; -// response.error = std::make_unique(Response::Error::Reason::Other, "Invalid file URL"); -// req.invoke(&FileSourceRequest::setResponse, response); -// return; -// } - -// void requestLocalFile(const std::string& path, -// const ActorRef& req, -// const std::optional>& dataRange) { - - Response response; - if (_requestFunction) { - response = _requestFunction(resource); - } else { - response.error = std::make_unique(Response::Error::Reason::Other, - std::string("Custom Protocol Handler Not Configured Correctly")); - } - req.invoke(&FileSourceRequest::setResponse, response); + void setOnRequestResourceFunction(OnRequestResource requestFunction) { _requestFunction = requestFunction; } + void request(const Resource& resource, const ActorRef& req) { + // if (_onCanRequestResourceFunction) { + // if (!_onCanRequestResourceFunction(resource)) { + // Response response; + // response.error = std::make_unique(Response::Error::Reason::Other, "This + // plugin protocol handler cannot service this resource"); + // req.invoke(&FileSourceRequest::setResponse, response); + // return; + // } + // } + + // if (!acceptsURL(resource.url)) { + // Response response; + // response.error = std::make_unique(Response::Error::Reason::Other, "Invalid file + // URL"); req.invoke(&FileSourceRequest::setResponse, response); return; + // } + + // void requestLocalFile(const std::string& path, + // const ActorRef& req, + // const std::optional>& dataRange) { + + Response response; + if (_requestFunction) { + response = _requestFunction(resource); + } else { + response.error = std::make_unique( + Response::Error::Reason::Other, std::string("Custom Protocol Handler Not Configured Correctly")); + } + req.invoke(&FileSourceRequest::setResponse, response); } void setResourceOptions(ResourceOptions options) { @@ -94,14 +86,13 @@ class PluginFileSource::Impl { void PluginFileSource::setOnCanRequestFunction(OnCanRequestResource requestFunction) { _onCanRequestResourceFunction = requestFunction; -// impl.get()->actor().invoke(&Impl::setOnCanRequestFunction, requestFunction); + // impl.get()->actor().invoke(&Impl::setOnCanRequestFunction, requestFunction); } void PluginFileSource::setOnRequestResourceFunction(OnRequestResource requestFunction) { impl.get()->actor().invoke(&Impl::setOnRequestResourceFunction, requestFunction); } - PluginFileSource::PluginFileSource(const ResourceOptions& resourceOptions, const ClientOptions& clientOptions) : impl(std::make_unique>( util::makeThreadPrioritySetter(platform::EXPERIMENTAL_THREAD_PRIORITY_FILE), diff --git a/platform/ios/app/MBXViewController.mm b/platform/ios/app/MBXViewController.mm index 7093c19c65d2..c42f066b1614 100644 --- a/platform/ios/app/MBXViewController.mm +++ b/platform/ios/app/MBXViewController.mm @@ -283,7 +283,7 @@ -(void)addPluginLayers { [self.mapView addPluginLayerType:[PluginLayerExample class]]; [self.mapView addPluginLayerType:[PluginLayerExampleMetalRendering class]]; [self.mapView addPluginProtocolHandler:[PluginProtocolExample class]]; - + } - (void)viewDidLoad diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index 6ad9a3582041..569312dc3ece 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -7806,16 +7806,16 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { } - (MLNPluginProtocolHandlerResource *)resourceFromCoreResource:(const mbgl::Resource &)resource { - + MLNPluginProtocolHandlerResource *tempResult = [[MLNPluginProtocolHandlerResource alloc] init]; tempResult.resourceURL = [NSString stringWithUTF8String:resource.url.c_str()]; return tempResult; - + } - (void)addPluginProtocolHandler:(Class)pluginProtocolHandlerClass { - - + + MLNPluginProtocolHandler *handler = [[pluginProtocolHandlerClass alloc] init]; if (!self.pluginProtocols) { self.pluginProtocols = [NSMutableArray array]; @@ -7824,18 +7824,18 @@ - (void)addPluginProtocolHandler:(Class)pluginProtocolHandlerClass { mbgl::ResourceOptions resourceOptions; mbgl::ClientOptions clientOptions; - + // Use weak here so there isn't a retain cycle __weak MLNPluginProtocolHandler *weakHandler = handler; __weak MLNMapView *weakSelf = self; - + std::shared_ptr pluginSource = std::make_shared(resourceOptions, clientOptions); pluginSource->setOnRequestResourceFunction([weakHandler, weakSelf](const mbgl::Resource &resource) -> mbgl::Response { mbgl::Response tempResult; - + __strong MLNPluginProtocolHandler *strongHandler = weakHandler; if (strongHandler) { - + MLNPluginProtocolHandlerResource *res = [weakSelf resourceFromCoreResource:resource]; MLNPluginProtocolHandlerResponse *response = [strongHandler requestResource:res]; if (response.data) { @@ -7843,29 +7843,29 @@ - (void)addPluginProtocolHandler:(Class)pluginProtocolHandlerClass { [response.data length]); } } - + return tempResult; - + }); - + pluginSource->setOnCanRequestFunction([weakHandler, weakSelf](const mbgl::Resource &resource) -> bool{ @autoreleasepool { __strong MLNPluginProtocolHandler *strongHandler = weakHandler; if (!strongHandler) { return false; } - + MLNPluginProtocolHandlerResource *res = [weakSelf resourceFromCoreResource:resource]; BOOL tempResult = [strongHandler canRequestResource:res]; return tempResult; - + } }); - + auto fileSourceManager = mbgl::FileSourceManager::get(); fileSourceManager->registerCustomFileSource(pluginSource); - + } diff --git a/src/mbgl/plugin/plugin_file_source.hpp b/src/mbgl/plugin/plugin_file_source.hpp index 6e78175257cb..7f6acc686156 100644 --- a/src/mbgl/plugin/plugin_file_source.hpp +++ b/src/mbgl/plugin/plugin_file_source.hpp @@ -11,32 +11,28 @@ template class Thread; } // namespace util -class PluginFileSourceRequest { - -}; +class PluginFileSourceRequest {}; -class PluginFileSourceResponse { - -}; +class PluginFileSourceResponse {}; class PluginFileSource : public FileSource { public: - PluginFileSource(const ResourceOptions& resourceOptions, const ClientOptions& clientOptions); + PluginFileSource(const ResourceOptions &resourceOptions, const ClientOptions &clientOptions); ~PluginFileSource() override; using OnCanRequestResource = std::function; - using OnRequestResource = std::function; + using OnRequestResource = std::function; void setOnCanRequestFunction(OnCanRequestResource requestFunction); void setOnRequestResourceFunction(OnRequestResource requestFunction); - std::unique_ptr request(const Resource&, Callback) override; - bool canRequest(const Resource&) const override; + std::unique_ptr request(const Resource &, Callback) override; + bool canRequest(const Resource &) const override; void pause() override; void resume() override; void setProtocolPrefix(const std::string &); - + void setResourceOptions(ResourceOptions) override; ResourceOptions getResourceOptions() override; diff --git a/src/mbgl/storage/file_source_manager.cpp b/src/mbgl/storage/file_source_manager.cpp index 3f97de6d65cd..f9876b156753 100644 --- a/src/mbgl/storage/file_source_manager.cpp +++ b/src/mbgl/storage/file_source_manager.cpp @@ -13,10 +13,10 @@ namespace mbgl { struct FileSourceInfo { FileSourceInfo(FileSourceType type_, std::string id_, std::weak_ptr fileSource_) - : type(type_), - id(std::move(id_)), - fileSource(std::move(fileSource_)) {} - + : type(type_), + id(std::move(id_)), + fileSource(std::move(fileSource_)) {} + FileSourceType type; std::string id; std::weak_ptr fileSource; @@ -31,7 +31,7 @@ class FileSourceManager::Impl { }; FileSourceManager::FileSourceManager() -: impl(std::make_unique()) {} + : impl(std::make_unique()) {} FileSourceManager::~FileSourceManager() = default; @@ -39,17 +39,17 @@ std::shared_ptr FileSourceManager::getFileSource(FileSourceType type const ResourceOptions& resourceOptions, const ClientOptions& clientOptions) noexcept { std::lock_guard lock(impl->mutex); - + // Remove released file sources. for (auto it = impl->fileSources.begin(); it != impl->fileSources.end();) { it = it->fileSource.expired() ? impl->fileSources.erase(it) : ++it; } - + const auto context = reinterpret_cast(resourceOptions.platformContext()); std::string baseURL = resourceOptions.tileServerOptions().baseURL(); std::string id = baseURL + '|' + resourceOptions.apiKey() + '|' + resourceOptions.cachePath() + '|' + - util::toString(context); - + util::toString(context); + std::shared_ptr fileSource; auto fileSourceIt = std::find_if(impl->fileSources.begin(), impl->fileSources.end(), [type, &id](const auto& info) { return info.type == type && info.id == id; @@ -57,7 +57,7 @@ std::shared_ptr FileSourceManager::getFileSource(FileSourceType type if (fileSourceIt != impl->fileSources.end()) { fileSource = fileSourceIt->fileSource.lock(); } - + if (!fileSource) { auto it = impl->fileSourceFactories.find(type); if (it != impl->fileSourceFactories.end()) { @@ -66,7 +66,7 @@ std::shared_ptr FileSourceManager::getFileSource(FileSourceType type impl->fileSources.emplace_back(type, std::move(id), fileSource); } } - + return fileSource; } @@ -97,6 +97,4 @@ std::vector> FileSourceManager::getCustomFileSources return impl->customFileSources; } - - } // namespace mbgl From 9f9f84c1c7a6b15e22655d22eca811bb2335f9c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sun, 27 Jul 2025 14:59:48 -0400 Subject: [PATCH 25/49] Cleanup --- .../src/mbgl/storage/plugin_file_source.cpp | 21 ------------------- platform/ios/app/MBXViewController.mm | 15 ++++++------- platform/ios/src/MLNMapView.mm | 3 +++ 3 files changed, 9 insertions(+), 30 deletions(-) diff --git a/platform/default/src/mbgl/storage/plugin_file_source.cpp b/platform/default/src/mbgl/storage/plugin_file_source.cpp index ca93611f3e49..0e0fa0b79b1c 100644 --- a/platform/default/src/mbgl/storage/plugin_file_source.cpp +++ b/platform/default/src/mbgl/storage/plugin_file_source.cpp @@ -27,26 +27,6 @@ class PluginFileSource::Impl { void setOnRequestResourceFunction(OnRequestResource requestFunction) { _requestFunction = requestFunction; } void request(const Resource& resource, const ActorRef& req) { - // if (_onCanRequestResourceFunction) { - // if (!_onCanRequestResourceFunction(resource)) { - // Response response; - // response.error = std::make_unique(Response::Error::Reason::Other, "This - // plugin protocol handler cannot service this resource"); - // req.invoke(&FileSourceRequest::setResponse, response); - // return; - // } - // } - - // if (!acceptsURL(resource.url)) { - // Response response; - // response.error = std::make_unique(Response::Error::Reason::Other, "Invalid file - // URL"); req.invoke(&FileSourceRequest::setResponse, response); return; - // } - - // void requestLocalFile(const std::string& path, - // const ActorRef& req, - // const std::optional>& dataRange) { - Response response; if (_requestFunction) { response = _requestFunction(resource); @@ -86,7 +66,6 @@ class PluginFileSource::Impl { void PluginFileSource::setOnCanRequestFunction(OnCanRequestResource requestFunction) { _onCanRequestResourceFunction = requestFunction; - // impl.get()->actor().invoke(&Impl::setOnCanRequestFunction, requestFunction); } void PluginFileSource::setOnRequestResourceFunction(OnRequestResource requestFunction) { diff --git a/platform/ios/app/MBXViewController.mm b/platform/ios/app/MBXViewController.mm index c42f066b1614..0bda8caffa1d 100644 --- a/platform/ios/app/MBXViewController.mm +++ b/platform/ios/app/MBXViewController.mm @@ -2332,24 +2332,21 @@ - (void)setStyles self.styleNames = [NSMutableArray array]; self.styleURLs = [NSMutableArray array]; - - /// This is hte same style as above but copied locally and the three instances of the metal plug-in layer added to the style - /// Look for "type": "plugin-layer-metal-rendering" in the PluginLayerTestStyle.json for an example of how the layer is defined - [self.styleNames addObject:@"MapLibre Basic - Local With Plugin Loader"]; - NSURL *pluginstyleurl = [NSURL URLWithString:@"pluginProtocol://PluginLayerTestStyle.json"]; - [self.styleURLs addObject:pluginstyleurl]; - - /// Style that does not require an `apiKey` nor any further configuration [self.styleNames addObject:@"MapLibre Basic"]; [self.styleURLs addObject:[NSURL URLWithString:@"https://demotiles.maplibre.org/style.json"]]; - /// This is hte same style as above but copied locally and the three instances of the metal plug-in layer added to the style + /// This is the same style as above but copied locally and the three instances of the metal plug-in layer added to the style /// Look for "type": "plugin-layer-metal-rendering" in the PluginLayerTestStyle.json for an example of how the layer is defined [self.styleNames addObject:@"MapLibre Basic - Local With Plugin"]; NSURL *url = [[NSBundle mainBundle] URLForResource:@"PluginLayerTestStyle.json" withExtension:nil]; [self.styleURLs addObject:url]; + /// This is the same style as above, but using the plugin protocol to actually load the style + [self.styleNames addObject:@"MapLibre Basic - Local With Plugin Loader"]; + NSURL *pluginstyleurl = [NSURL URLWithString:@"pluginProtocol://PluginLayerTestStyle.json"]; + [self.styleURLs addObject:pluginstyleurl]; + /// Add MapLibre Styles if an `apiKey` exists NSString* apiKey = [MLNSettings apiKey]; if (apiKey.length) diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index 569312dc3ece..8516639a94a6 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -7822,7 +7822,10 @@ - (void)addPluginProtocolHandler:(Class)pluginProtocolHandlerClass { } [self.pluginProtocols addObject:handler]; + // TODO: Unclear if any of these options are needed for plugins mbgl::ResourceOptions resourceOptions; + + // TODO: Unclear if any of the properties on clientOptions need to be set mbgl::ClientOptions clientOptions; // Use weak here so there isn't a retain cycle From b7f85bbf67d3428093cd4d4de6f7c8dee1c1bf23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sun, 27 Jul 2025 15:18:56 -0400 Subject: [PATCH 26/49] Adding more properties to the platform request --- .../darwin/src/MLNPluginProtocolHandler.h | 37 +++++++++++ .../darwin/src/MLNPluginProtocolHandler.mm | 3 + platform/ios/src/MLNMapView.mm | 66 +++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/platform/darwin/src/MLNPluginProtocolHandler.h b/platform/darwin/src/MLNPluginProtocolHandler.h index 2d1714f31193..dcdee5ee7af7 100644 --- a/platform/darwin/src/MLNPluginProtocolHandler.h +++ b/platform/darwin/src/MLNPluginProtocolHandler.h @@ -2,10 +2,47 @@ NS_ASSUME_NONNULL_BEGIN +typedef enum { + MLNPluginProtocolHandlerResourceKindUnknown, + MLNPluginProtocolHandlerResourceKindStyle, + MLNPluginProtocolHandlerResourceKindSource, + MLNPluginProtocolHandlerResourceKindTile, + MLNPluginProtocolHandlerResourceKindGlyphs, + MLNPluginProtocolHandlerResourceKindSpriteImage, + MLNPluginProtocolHandlerResourceKindSpriteJSON, + MLNPluginProtocolHandlerResourceKindImage +} MLNPluginProtocolHandlerResourceKind; + +typedef enum { + MLNPluginProtocolHandlerResourceLoadingMethodUnknown, + MLNPluginProtocolHandlerResourceLoadingMethodCacheOnly, + MLNPluginProtocolHandlerResourceLoadingMethodNetworkOnly, + MLNPluginProtocolHandlerResourceLoadingMethodAll +} MLNPluginProtocolHandlerResourceLoadingMethod; + +// TODO: Might make sense to add this to it's own file +@interface MLNTileData : NSObject + +// Optional Tile Data +@property NSString *tileURLTemplate; +@property int tilePixelRatio; +@property int tileX; +@property int tileY; +@property int tileZoom; + +@end + @interface MLNPluginProtocolHandlerResource : NSObject +@property MLNPluginProtocolHandlerResourceKind resourceKind; + +@property MLNPluginProtocolHandlerResourceLoadingMethod loadingMethod; + @property NSString *resourceURL; +// This is optional +@property MLNTileData * __nullable tileData; + @end @interface MLNPluginProtocolHandlerResponse : NSObject diff --git a/platform/darwin/src/MLNPluginProtocolHandler.mm b/platform/darwin/src/MLNPluginProtocolHandler.mm index 0f7700a5bba2..a68409d104dc 100644 --- a/platform/darwin/src/MLNPluginProtocolHandler.mm +++ b/platform/darwin/src/MLNPluginProtocolHandler.mm @@ -21,3 +21,6 @@ @implementation MLNPluginProtocolHandlerResource @implementation MLNPluginProtocolHandlerResponse @end + +@implementation MLNTileData +@end diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index 8516639a94a6..bf82becdf56d 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -7808,7 +7808,71 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { - (MLNPluginProtocolHandlerResource *)resourceFromCoreResource:(const mbgl::Resource &)resource { MLNPluginProtocolHandlerResource *tempResult = [[MLNPluginProtocolHandlerResource alloc] init]; + + // The URL of the request tempResult.resourceURL = [NSString stringWithUTF8String:resource.url.c_str()]; + + // The kind of request + switch (resource.kind) { + case mbgl::Resource::Kind::Style: + tempResult.resourceKind = MLNPluginProtocolHandlerResourceKindStyle; + break; + case mbgl::Resource::Kind::Source: + tempResult.resourceKind = MLNPluginProtocolHandlerResourceKindSource; + break; + case mbgl::Resource::Kind::Tile: + tempResult.resourceKind = MLNPluginProtocolHandlerResourceKindTile; + break; + case mbgl::Resource::Kind::Glyphs: + tempResult.resourceKind = MLNPluginProtocolHandlerResourceKindGlyphs; + break; + case mbgl::Resource::Kind::SpriteImage: + tempResult.resourceKind = MLNPluginProtocolHandlerResourceKindSpriteImage; + break; + case mbgl::Resource::Kind::Image: + tempResult.resourceKind = MLNPluginProtocolHandlerResourceKindImage; + break; + case mbgl::Resource::Kind::SpriteJSON: + tempResult.resourceKind = MLNPluginProtocolHandlerResourceKindSpriteJSON; + break; + default: + tempResult.resourceKind = MLNPluginProtocolHandlerResourceKindUnknown; + break; + } + + // The loading method + if (resource.loadingMethod == mbgl::Resource::LoadingMethod::CacheOnly) { + tempResult.loadingMethod = MLNPluginProtocolHandlerResourceLoadingMethodCacheOnly; + } else if (resource.loadingMethod == mbgl::Resource::LoadingMethod::NetworkOnly) { + tempResult.loadingMethod = MLNPluginProtocolHandlerResourceLoadingMethodNetworkOnly; + } else if (resource.loadingMethod == mbgl::Resource::LoadingMethod::All) { + tempResult.loadingMethod = MLNPluginProtocolHandlerResourceLoadingMethodAll; + } + + if (resource.tileData) { + auto td = *resource.tileData; + MLNTileData *tileData = [[MLNTileData alloc] init]; + tileData.tileURLTemplate = [NSString stringWithUTF8String:td.urlTemplate.c_str()]; + tileData.tilePixelRatio = td.pixelRatio; + tileData.tileX = td.x; + tileData.tileY = td.y; + tileData.tileZoom = td.z; + tempResult.tileData = tileData; + } + + // TODO: Figure out which other properties from resource should be passed along here +/* + Usage usage{Usage::Online}; + Priority priority{Priority::Regular}; + std::optional> dataRange = std::nullopt; + std::optional priorModified = std::nullopt; + std::optional priorExpires = std::nullopt; + std::optional priorEtag = std::nullopt; + std::shared_ptr priorData; + Duration minimumUpdateInterval{Duration::zero()}; + StoragePolicy storagePolicy{StoragePolicy::Permanent}; + */ + return tempResult; } @@ -7840,6 +7904,8 @@ - (void)addPluginProtocolHandler:(Class)pluginProtocolHandlerClass { if (strongHandler) { MLNPluginProtocolHandlerResource *res = [weakSelf resourceFromCoreResource:resource]; + + // TODO: Figure out what other fields in response need to be passed back from requestResource MLNPluginProtocolHandlerResponse *response = [strongHandler requestResource:res]; if (response.data) { tempResult.data = std::make_shared((const char*)[response.data bytes], From 1ab94b51347ed46ae9c65de374feed94fadefa40 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 27 Jul 2025 19:19:59 +0000 Subject: [PATCH 27/49] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../darwin/src/MLNPluginProtocolHandler.h | 26 +++++++++---------- platform/ios/src/MLNMapView.mm | 16 ++++++------ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/platform/darwin/src/MLNPluginProtocolHandler.h b/platform/darwin/src/MLNPluginProtocolHandler.h index dcdee5ee7af7..ef88a9889b35 100644 --- a/platform/darwin/src/MLNPluginProtocolHandler.h +++ b/platform/darwin/src/MLNPluginProtocolHandler.h @@ -3,21 +3,21 @@ NS_ASSUME_NONNULL_BEGIN typedef enum { - MLNPluginProtocolHandlerResourceKindUnknown, - MLNPluginProtocolHandlerResourceKindStyle, - MLNPluginProtocolHandlerResourceKindSource, - MLNPluginProtocolHandlerResourceKindTile, - MLNPluginProtocolHandlerResourceKindGlyphs, - MLNPluginProtocolHandlerResourceKindSpriteImage, - MLNPluginProtocolHandlerResourceKindSpriteJSON, - MLNPluginProtocolHandlerResourceKindImage + MLNPluginProtocolHandlerResourceKindUnknown, + MLNPluginProtocolHandlerResourceKindStyle, + MLNPluginProtocolHandlerResourceKindSource, + MLNPluginProtocolHandlerResourceKindTile, + MLNPluginProtocolHandlerResourceKindGlyphs, + MLNPluginProtocolHandlerResourceKindSpriteImage, + MLNPluginProtocolHandlerResourceKindSpriteJSON, + MLNPluginProtocolHandlerResourceKindImage } MLNPluginProtocolHandlerResourceKind; typedef enum { - MLNPluginProtocolHandlerResourceLoadingMethodUnknown, - MLNPluginProtocolHandlerResourceLoadingMethodCacheOnly, - MLNPluginProtocolHandlerResourceLoadingMethodNetworkOnly, - MLNPluginProtocolHandlerResourceLoadingMethodAll + MLNPluginProtocolHandlerResourceLoadingMethodUnknown, + MLNPluginProtocolHandlerResourceLoadingMethodCacheOnly, + MLNPluginProtocolHandlerResourceLoadingMethodNetworkOnly, + MLNPluginProtocolHandlerResourceLoadingMethodAll } MLNPluginProtocolHandlerResourceLoadingMethod; // TODO: Might make sense to add this to it's own file @@ -41,7 +41,7 @@ typedef enum { @property NSString *resourceURL; // This is optional -@property MLNTileData * __nullable tileData; +@property MLNTileData *__nullable tileData; @end diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index bf82becdf56d..d104dac69d48 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -7808,10 +7808,10 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { - (MLNPluginProtocolHandlerResource *)resourceFromCoreResource:(const mbgl::Resource &)resource { MLNPluginProtocolHandlerResource *tempResult = [[MLNPluginProtocolHandlerResource alloc] init]; - + // The URL of the request tempResult.resourceURL = [NSString stringWithUTF8String:resource.url.c_str()]; - + // The kind of request switch (resource.kind) { case mbgl::Resource::Kind::Style: @@ -7839,7 +7839,7 @@ - (MLNPluginProtocolHandlerResource *)resourceFromCoreResource:(const mbgl::Reso tempResult.resourceKind = MLNPluginProtocolHandlerResourceKindUnknown; break; } - + // The loading method if (resource.loadingMethod == mbgl::Resource::LoadingMethod::CacheOnly) { tempResult.loadingMethod = MLNPluginProtocolHandlerResourceLoadingMethodCacheOnly; @@ -7848,7 +7848,7 @@ - (MLNPluginProtocolHandlerResource *)resourceFromCoreResource:(const mbgl::Reso } else if (resource.loadingMethod == mbgl::Resource::LoadingMethod::All) { tempResult.loadingMethod = MLNPluginProtocolHandlerResourceLoadingMethodAll; } - + if (resource.tileData) { auto td = *resource.tileData; MLNTileData *tileData = [[MLNTileData alloc] init]; @@ -7859,7 +7859,7 @@ - (MLNPluginProtocolHandlerResource *)resourceFromCoreResource:(const mbgl::Reso tileData.tileZoom = td.z; tempResult.tileData = tileData; } - + // TODO: Figure out which other properties from resource should be passed along here /* Usage usage{Usage::Online}; @@ -7872,7 +7872,7 @@ - (MLNPluginProtocolHandlerResource *)resourceFromCoreResource:(const mbgl::Reso Duration minimumUpdateInterval{Duration::zero()}; StoragePolicy storagePolicy{StoragePolicy::Permanent}; */ - + return tempResult; } @@ -7888,7 +7888,7 @@ - (void)addPluginProtocolHandler:(Class)pluginProtocolHandlerClass { // TODO: Unclear if any of these options are needed for plugins mbgl::ResourceOptions resourceOptions; - + // TODO: Unclear if any of the properties on clientOptions need to be set mbgl::ClientOptions clientOptions; @@ -7904,7 +7904,7 @@ - (void)addPluginProtocolHandler:(Class)pluginProtocolHandlerClass { if (strongHandler) { MLNPluginProtocolHandlerResource *res = [weakSelf resourceFromCoreResource:resource]; - + // TODO: Figure out what other fields in response need to be passed back from requestResource MLNPluginProtocolHandlerResponse *response = [strongHandler requestResource:res]; if (response.data) { From bd0ced973387d9d42848cd3d1a3016f37b2e525c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sun, 27 Jul 2025 15:32:56 -0400 Subject: [PATCH 28/49] Cmake update --- platform/darwin/darwin.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/darwin/darwin.cmake b/platform/darwin/darwin.cmake index 4217aa752bd5..3b959cbbea64 100644 --- a/platform/darwin/darwin.cmake +++ b/platform/darwin/darwin.cmake @@ -164,6 +164,7 @@ add_library( "${CMAKE_CURRENT_LIST_DIR}/app/CustomStyleLayerExample.m" "${CMAKE_CURRENT_LIST_DIR}/app/PluginLayerExample.mm" "${CMAKE_CURRENT_LIST_DIR}/app/PluginLayerExampleMetalRendering.mm" + "${CMAKE_CURRENT_LIST_DIR}/app/StyleFilterExample.mm" ) target_link_libraries( From fb99190e12e93e5ec0529c123a0f6fdfdb83aa0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sun, 27 Jul 2025 16:16:10 -0400 Subject: [PATCH 29/49] Fix for swift app compile --- platform/darwin/bazel/files.bzl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/darwin/bazel/files.bzl b/platform/darwin/bazel/files.bzl index da71263cf5d5..2ce988a44ce7 100644 --- a/platform/darwin/bazel/files.bzl +++ b/platform/darwin/bazel/files.bzl @@ -108,8 +108,7 @@ MLN_DARWIN_OBJC_HEADERS = [ "src/NSValue+MLNAdditions.h", "src/MLNPluginLayer.h", "src/MLNPluginStyleLayer.h", - "src/MLNStyleFilter.h", - "src/MLNStyleFilter_Private.h", + "src/MLNStyleFilter.h" ] MLN_DARWIN_OBJCPP_HEADERS = [ From e126973cc58bc39a1de6d7a4fb7f1987fb15689e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sun, 27 Jul 2025 16:22:10 -0400 Subject: [PATCH 30/49] Updates for cmake --- CMakeLists.txt | 1 + platform/darwin/darwin.cmake | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f24a62dc5d4..c4ee1164e549 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -977,6 +977,7 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_properties.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_impl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_factory.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_file_source.hpp ) diff --git a/platform/darwin/darwin.cmake b/platform/darwin/darwin.cmake index 4217aa752bd5..656fecb9bf3a 100644 --- a/platform/darwin/darwin.cmake +++ b/platform/darwin/darwin.cmake @@ -63,6 +63,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/offline_database.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/offline_download.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/online_file_source.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/plugin_file_source.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/$,pmtiles_file_source.cpp,pmtiles_file_source_stub.cpp> ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/sqlite3.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/text/bidi.cpp @@ -164,6 +165,7 @@ add_library( "${CMAKE_CURRENT_LIST_DIR}/app/CustomStyleLayerExample.m" "${CMAKE_CURRENT_LIST_DIR}/app/PluginLayerExample.mm" "${CMAKE_CURRENT_LIST_DIR}/app/PluginLayerExampleMetalRendering.mm" + "${CMAKE_CURRENT_LIST_DIR}/app/PluginProtocolExample.mm" ) target_link_libraries( From 1fa1a0e5bd77833a65c02b359f1585d3bd9f3a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sun, 27 Jul 2025 16:25:42 -0400 Subject: [PATCH 31/49] Added header back in the right place this time --- platform/darwin/bazel/files.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/darwin/bazel/files.bzl b/platform/darwin/bazel/files.bzl index 2ce988a44ce7..d069ef97f8a3 100644 --- a/platform/darwin/bazel/files.bzl +++ b/platform/darwin/bazel/files.bzl @@ -166,8 +166,8 @@ MLN_DARWIN_PRIVATE_HEADERS = [ "src/MLNVectorTileSource_Private.h", "src/NSExpression+MLNPrivateAdditions.h", "src/NSPredicate+MLNPrivateAdditions.h", - "src/MLNPluginStyleLayer_Private.h" - + "src/MLNPluginStyleLayer_Private.h", + "src/MLNStyleFilter_Private.h" ] MLN_DARWIN_PUBLIC_OBJCPP_SOURCE = [ From 10c8c0df979a3115aa7e076937e9ed45f6d4e30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Mon, 28 Jul 2025 00:06:19 -0400 Subject: [PATCH 32/49] Fix compiler error --- src/mbgl/plugin/feature_collection_bucket.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/mbgl/plugin/feature_collection_bucket.cpp b/src/mbgl/plugin/feature_collection_bucket.cpp index 9ef46fd84df8..0cd7eabc218a 100644 --- a/src/mbgl/plugin/feature_collection_bucket.cpp +++ b/src/mbgl/plugin/feature_collection_bucket.cpp @@ -54,9 +54,9 @@ std::string toString(FeatureIdentifier& v) { void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, const GeometryCollection& geometeryCollection, - const mbgl::ImagePositions& imagePositions, - const PatternLayerMap& patternLayerMap, - std::size_t size, + [[maybe_unused]] const mbgl::ImagePositions& imagePositions, + [[maybe_unused]] const PatternLayerMap& patternLayerMap, + [[maybe_unused]] std::size_t size, const CanonicalTileID& tileID) { std::shared_ptr tempFeature = std::make_shared(); @@ -106,7 +106,6 @@ void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, plugin::FeatureCoordinateCollection c; for (std::size_t i = 0, len = g.size(); i < len; i++) { const GeometryCoordinate& p1 = g[i]; - auto d = b.west(); double lat = 0; double lon = 0; geometryToLatLon(p1, tileID.x, tileID.y, tileID.z, lat, lon); From 87b27bce975800adfb93f0e09a4c6681c3d57de7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Mon, 28 Jul 2025 00:13:36 -0400 Subject: [PATCH 33/49] More compiler errors --- src/mbgl/plugin/feature_collection.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mbgl/plugin/feature_collection.hpp b/src/mbgl/plugin/feature_collection.hpp index a4199a110747..1653ff512f99 100644 --- a/src/mbgl/plugin/feature_collection.hpp +++ b/src/mbgl/plugin/feature_collection.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace mbgl { From d6a7000b4516c9f9dbe4e3e75cf5ed2e74cec34f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Mon, 28 Jul 2025 00:15:37 -0400 Subject: [PATCH 34/49] Re-ordered headers --- src/mbgl/plugin/feature_collection.hpp | 5 ++--- src/mbgl/plugin/feature_collection_bucket.cpp | 4 ++-- src/mbgl/plugin/feature_collection_bucket.hpp | 8 ++++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/mbgl/plugin/feature_collection.hpp b/src/mbgl/plugin/feature_collection.hpp index 1653ff512f99..3ea9b5c70b5a 100644 --- a/src/mbgl/plugin/feature_collection.hpp +++ b/src/mbgl/plugin/feature_collection.hpp @@ -2,11 +2,10 @@ #include -#include -#include -#include #include #include +#include +#include namespace mbgl { diff --git a/src/mbgl/plugin/feature_collection_bucket.cpp b/src/mbgl/plugin/feature_collection_bucket.cpp index 0cd7eabc218a..05cdf268c4b6 100644 --- a/src/mbgl/plugin/feature_collection_bucket.cpp +++ b/src/mbgl/plugin/feature_collection_bucket.cpp @@ -1,7 +1,7 @@ -#include +#include #include #include -#include +#include using namespace mbgl; diff --git a/src/mbgl/plugin/feature_collection_bucket.hpp b/src/mbgl/plugin/feature_collection_bucket.hpp index ccb28d35d018..fc5499488822 100644 --- a/src/mbgl/plugin/feature_collection_bucket.hpp +++ b/src/mbgl/plugin/feature_collection_bucket.hpp @@ -1,13 +1,13 @@ #pragma once -#include -#include -#include #include #include +#include +#include +#include #include #include -#include +#include #include From eae8078055fd7e20fbd040b02f63494b9d8d1146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Tue, 29 Jul 2025 11:44:45 -0400 Subject: [PATCH 35/49] Starting to add android implementation --- .../MapLibreAndroid/src/cpp/jni_native.cpp | 5 + .../src/cpp/native_map_view.cpp | 94 ++++++++++++++++++- .../src/cpp/native_map_view.hpp | 11 ++- .../src/cpp/plugin/plugin_file_source.cpp | 59 ++++++++++++ .../src/cpp/plugin/plugin_file_source.hpp | 38 ++++++++ .../maplibre/android/maps/MapLibreMap.java | 16 ++++ .../org/maplibre/android/maps/MapView.java | 11 +++ .../org/maplibre/android/maps/NativeMap.java | 3 + .../maplibre/android/maps/NativeMapView.java | 16 ++++ .../android/plugin/PluginFileSource.java | 28 ++++++ .../android/plugin/PluginProtocolHandler.kt | 18 ++++ .../plugin/PluginProtocolHandlerResource.kt | 33 +++++++ .../plugin/PluginProtocolHandlerResponse.kt | 7 ++ .../org/maplibre/android/plugin/TileData.kt | 15 +++ .../activity/maplayout/SimpleMapActivity.kt | 3 + .../activity/plugin/PluginProtocolExample.kt | 34 +++++++ platform/android/android.cmake | 2 + .../src/mbgl/storage/plugin_file_source.cpp | 2 +- 18 files changed, 391 insertions(+), 4 deletions(-) create mode 100644 platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp create mode 100644 platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.hpp create mode 100644 platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginFileSource.java create mode 100644 platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandler.kt create mode 100644 platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResource.kt create mode 100644 platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt create mode 100644 platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/TileData.kt create mode 100644 platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt diff --git a/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp b/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp index b0a29b677d3d..55071f20bf42 100644 --- a/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp @@ -37,6 +37,7 @@ #include "native_map_options.hpp" #include "rendering_stats.hpp" #include "util/tile_server_options.hpp" +#include "plugin/plugin_file_source.hpp" #ifndef MBGL_MODULE_OFFLINE_DISABLE #include "offline/offline_manager.hpp" #include "offline/offline_region.hpp" @@ -107,6 +108,10 @@ void registerNatives(JavaVM* vm) { Polygon::registerNative(env); Polyline::registerNative(env); + // Plugins + PluginProtocolHandlerResource::registerNative(env); + PluginFileSource::registerNative(env); + // Map MapRenderer::registerNative(env); MapRendererRunnable::registerNative(env); diff --git a/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp b/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp index e7a48ac3c31f..588dcd67a080 100644 --- a/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include // Java -> C++ conversion #include "style/android_conversion.hpp" @@ -1320,6 +1322,94 @@ void NativeMapView::enableRenderingStatsView(JNIEnv&, jni::jboolean value) { map->enableRenderingStatsView(value); } +// Plugins +void NativeMapView::addPluginFileSource(JNIEnv &jniEnv, + const jni::Object& pluginFileSource) { + + // TODO: Unclear if any of these options are needed for plugins + mbgl::ResourceOptions resourceOptions; + + // TODO: Unclear if any of the properties on clientOptions need to be set + mbgl::ClientOptions clientOptions; + + android::UniqueEnv _env = android::AttachEnv(); + + // Set when the source is added to a map. + jni::Global> pluginPeer = jni::NewGlobal(*_env, pluginFileSource); + std::shared_ptr fileSourceContainer = std::make_shared(); + fileSourceContainer->_fileSource = std::move(pluginPeer); + _pluginFileSources.push_back(fileSourceContainer); + + std::shared_ptr pluginSource = std::make_shared(resourceOptions, clientOptions); + pluginSource->setOnRequestResourceFunction([fileSourceContainer](const mbgl::Resource &resource) -> mbgl::Response { + mbgl::Response tempResult; + + return tempResult; + }); + pluginSource->setOnCanRequestFunction([fileSourceContainer](const mbgl::Resource &resource) -> bool { + android::UniqueEnv env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*env); + static auto canRequestResource = javaClass.GetMethod)>(*env, "canRequestResource"); + auto javaResource = PluginFileSource::createJavaResource(*env, resource); + auto tempResult = fileSourceContainer->_fileSource.Call(*env, canRequestResource, javaResource); + return tempResult; + + + /* + if (!renderingStats) { + renderingStats = jni::NewGlobal(*_env, RenderingStats::Create(*_env)); + } + + RenderingStats::Update(*_env, renderingStats, status.renderingStats); + + weakReference.Call(*_env, + onDidFinishRenderingFrame, + (jboolean)(status.mode != MapObserver::RenderMode::Partial), + renderingStats); + */ +/* + static auto resourceURLField = javaClass.GetField>(env, "resource"); + auto str = jni::Make(env, resource.url); // wrap the jstring + javaObject.Set(env, resourceURLField, str); + + fileSourceContainer->_fileSource.Set(env, ) +*/ + + + + + }); + auto fileSourceManager = mbgl::FileSourceManager::get(); + fileSourceManager->registerCustomFileSource(pluginSource); + + +/* + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFinishRenderingFrame = javaClass.GetMethod)>( + *_env, "onDidFinishRenderingFrame"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + if (!renderingStats) { + renderingStats = jni::NewGlobal(*_env, RenderingStats::Create(*_env)); + } + + RenderingStats::Update(*_env, renderingStats, status.renderingStats); + + weakReference.Call(*_env, + onDidFinishRenderingFrame, + (jboolean)(status.mode != MapObserver::RenderMode::Partial), + renderingStats); + } + + */ + + + +} + + + // Static methods // void NativeMapView::registerNative(jni::JNIEnv& env) { @@ -1442,7 +1532,9 @@ void NativeMapView::registerNative(jni::JNIEnv& env) { METHOD(&NativeMapView::getTileLodZoomShift, "nativeGetTileLodZoomShift"), METHOD(&NativeMapView::triggerRepaint, "nativeTriggerRepaint"), METHOD(&NativeMapView::isRenderingStatsViewEnabled, "nativeIsRenderingStatsViewEnabled"), - METHOD(&NativeMapView::enableRenderingStatsView, "nativeEnableRenderingStatsView")); + METHOD(&NativeMapView::enableRenderingStatsView, "nativeEnableRenderingStatsView"), + METHOD(&NativeMapView::addPluginFileSource, "nativeAddPluginFileSource")); + } void NativeMapView::onRegisterShaders(gfx::ShaderRegistry&) {}; diff --git a/platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp b/platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp index f9a0c7a3e136..2eec8461c909 100644 --- a/platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp +++ b/platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp @@ -25,7 +25,7 @@ #include "style/light.hpp" #include "native_map_options.hpp" #include "bitmap.hpp" - +#include "plugin/plugin_file_source.hpp" #include #include #include @@ -325,7 +325,11 @@ class NativeMapView : public MapObserver { jni::jboolean isRenderingStatsViewEnabled(JNIEnv&); void enableRenderingStatsView(JNIEnv&, jni::jboolean); - // Shader compilation + // Plugins + void addPluginFileSource(JNIEnv &, + const jni::Object& ); + + // Shader compilation void onRegisterShaders(mbgl::gfx::ShaderRegistry&) override; void onPreCompileShader(mbgl::shaders::BuiltIn, mbgl::gfx::Backend::Type, const std::string&) override; void onPostCompileShader(mbgl::shaders::BuiltIn, mbgl::gfx::Backend::Type, const std::string&) override; @@ -364,6 +368,9 @@ class NativeMapView : public MapObserver { // Ensure these are initialised last std::unique_ptr map; + + // List of plugin file source + std::vector> _pluginFileSources; }; } // namespace android diff --git a/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp b/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp new file mode 100644 index 000000000000..425142d21a18 --- /dev/null +++ b/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp @@ -0,0 +1,59 @@ + +#include "plugin_file_source.hpp" + +using namespace mbgl::android; + +void PluginFileSource::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Global> PluginFileSource::createJavaResource(jni::JNIEnv& env, + const mbgl::Resource &resource) { + jni::Global> tempResult = jni::NewGlobal(env, PluginProtocolHandlerResource::Create(env)); + PluginProtocolHandlerResource::Update(env, tempResult, resource); + return tempResult; +} + +void PluginProtocolHandlerResource::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> PluginProtocolHandlerResource::Create(jni::JNIEnv& env) { + auto& javaClass = jni::Class::Singleton(env); + auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor); +} + +void PluginProtocolHandlerResource::Update(jni::JNIEnv& env, + jni::Object& javaObject, + const mbgl::Resource &resource) { + + static auto &javaClass = jni::Class::Singleton(env); + + static auto resourceKindField = javaClass.GetField(env, "kind"); + javaObject.Set(env, resourceKindField, static_cast(resource.kind)); + + static auto resourceURLField = javaClass.GetField(env, "resourceURL"); + auto str = jni::Make(env, resource.url); // wrap the jstring + javaObject.Set(env, resourceURLField, str); + +} + + + + + + + +/* +mbgl::PluginFileSource PluginFileSource::getFileSource(jni::JNIEnv&, + const jni::Object&) { + + ResourceOptions resourceOptions; + ClientOptions clientOptions; + mbgl::PluginFileSource tempResult(resourceOptions, clientOptions); + + return tempResult; + +} +*/ \ No newline at end of file diff --git a/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.hpp b/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.hpp new file mode 100644 index 000000000000..a98c0bcc9b45 --- /dev/null +++ b/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +namespace mbgl { + namespace android { + + class PluginProtocolHandlerResource { + public: + static constexpr auto Name() { return "org/maplibre/android/plugin/PluginProtocolHandlerResource"; }; + static void registerNative(jni::JNIEnv&); + + static jni::Local> Create(jni::JNIEnv&); + static void Update(jni::JNIEnv&, jni::Object&, const mbgl::Resource &); + }; + + class PluginFileSource { + public: + static constexpr auto Name() { return "org/maplibre/android/plugin/PluginFileSource"; }; + + //static mbgl::PluginFileSource getFileSource(jni::JNIEnv&, const jni::Object&); + + static jni::Global> createJavaResource(jni::JNIEnv& env, + const mbgl::Resource &resource); + + static void registerNative(jni::JNIEnv&); + }; + + class PluginFileSourceContainer { + public: + jni::Global> _fileSource; + }; + + } +} + + diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/MapLibreMap.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/MapLibreMap.java index cdbecdfd660a..82ad755da11e 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/MapLibreMap.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/MapLibreMap.java @@ -20,6 +20,7 @@ import org.maplibre.android.gestures.RotateGestureDetector; import org.maplibre.android.gestures.ShoveGestureDetector; import org.maplibre.android.gestures.StandardScaleGestureDetector; +import org.maplibre.android.plugin.PluginProtocolHandler; import org.maplibre.geojson.Feature; import org.maplibre.geojson.Geometry; import org.maplibre.android.MapStrictMode; @@ -2694,4 +2695,19 @@ private void notifyDeveloperAnimationListeners() { listener.onDeveloperAnimationStarted(); } } + + + + /** + * Adds a custom protocol handler to the map view + */ + ArrayList pluginProtocolHandlers = new ArrayList(); + public void addPluginProtocolHandler(PluginProtocolHandler protocolHandler) { + pluginProtocolHandlers.add(protocolHandler); + nativeMapView.addPluginProtocolHandler(protocolHandler); + + // nativeMapView.addPolygon() + } + + } diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/MapView.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/MapView.java index d0828b14272f..7673241ec043 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/MapView.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/MapView.java @@ -31,6 +31,7 @@ import org.maplibre.android.maps.renderer.MapRenderer; import org.maplibre.android.maps.widgets.CompassView; import org.maplibre.android.net.ConnectivityReceiver; +import org.maplibre.android.plugin.PluginProtocolHandler; import org.maplibre.android.storage.FileSource; import org.maplibre.android.utils.BitmapUtils; import org.maplibre.android.tile.TileOperation; @@ -1817,4 +1818,14 @@ private AttributionDialogManager getDialogManager() { public static void setMapStrictModeEnabled(boolean strictModeEnabled) { MapStrictMode.setStrictModeEnabled(strictModeEnabled); } + + /** + * Adds a custom protocol handler to the map view + */ + public void addPluginProtocolHandler(PluginProtocolHandler protocolHandler) { + if (maplibreMap != null) { + maplibreMap.addPluginProtocolHandler(protocolHandler); + } + } + } diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMap.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMap.java index 585f7ed332b6..50dd727e6971 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMap.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMap.java @@ -8,6 +8,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import org.maplibre.android.plugin.PluginProtocolHandler; import org.maplibre.geojson.Feature; import org.maplibre.geojson.Geometry; import org.maplibre.android.annotations.Marker; @@ -270,6 +271,8 @@ List queryRenderedFeatures(@NonNull RectF coordinates, void enableRenderingStatsView(boolean value); + void addPluginProtocolHandler(PluginProtocolHandler protocolHandler); + void setSwapBehaviorFlush(boolean flush); // diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMapView.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMapView.java index 571193bd45d5..1e89a31b07cd 100755 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMapView.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/maps/NativeMapView.java @@ -13,6 +13,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import org.maplibre.android.plugin.PluginFileSource; +import org.maplibre.android.plugin.PluginProtocolHandler; +import org.maplibre.android.plugin.PluginProtocolHandlerResource; import org.maplibre.geojson.Feature; import org.maplibre.geojson.Geometry; import org.maplibre.android.LibraryLoader; @@ -38,6 +41,7 @@ import org.maplibre.android.style.sources.Source; import org.maplibre.android.utils.BitmapUtils; import org.maplibre.android.tile.TileOperation; +import org.maplibre.android.plugin.PluginFileSource; import java.util.ArrayList; import java.util.Arrays; @@ -1149,6 +1153,13 @@ public void enableRenderingStatsView(boolean value) { nativeEnableRenderingStatsView(value); } + @Override + public void addPluginProtocolHandler(PluginProtocolHandler protocolHandler) { + PluginFileSource pluginFileSource = new PluginFileSource(); + pluginFileSource.protocolHandler = protocolHandler; + nativeAddPluginFileSource(pluginFileSource); + } + @Override public void setSwapBehaviorFlush(boolean flush) { mapRenderer.setSwapBehaviorFlush(flush); @@ -1746,6 +1757,11 @@ public long getNativePtr() { @Keep private native void nativeEnableRenderingStatsView(boolean enabled); + @Keep + private native void nativeAddPluginFileSource(PluginFileSource fileSource); + + + // // Snapshot // diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginFileSource.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginFileSource.java new file mode 100644 index 000000000000..5f19cad98fba --- /dev/null +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginFileSource.java @@ -0,0 +1,28 @@ +package org.maplibre.android.plugin; + +public class PluginFileSource { + + public PluginProtocolHandler protocolHandler; + + public boolean canRequestResource(PluginProtocolHandlerResource resource) { + + if (protocolHandler.canRequestResource(resource)) { + return true; + } + return false; + + } +/* + public boolean canRequestResource() { + if (protocolHandler.canRequestResource(resource)) { + return true; + } + return false; + } +*/ + public PluginProtocolHandlerResponse requestResource(PluginProtocolHandlerResource resource) { + PluginProtocolHandlerResponse response = protocolHandler.requestResource(resource); + return response; + } + +} diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandler.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandler.kt new file mode 100644 index 000000000000..2b84385a9d2a --- /dev/null +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandler.kt @@ -0,0 +1,18 @@ +package org.maplibre.android.plugin + +import android.icu.text.Normalizer + +public open class PluginProtocolHandler { + + open fun canRequestResource(resource: PluginProtocolHandlerResource?): Boolean { + // Base class does nothing + return false; + } + + + open fun requestResource(resource: PluginProtocolHandlerResource?): PluginProtocolHandlerResponse? { + // Base class does nothing + return null; + } + +} diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResource.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResource.kt new file mode 100644 index 000000000000..f72b4628889f --- /dev/null +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResource.kt @@ -0,0 +1,33 @@ +package org.maplibre.android.plugin + +class PluginProtocolHandlerResource { + + enum class PluginProtocolHandlerResourceKind { + Unknown, + Style, + Source, + Tile, + Glyphs, + SpriteImage, + SpriteJSON, + Image + }; + + enum class PluginProtocolHandlerResourceLoadingMethod { + Unknown, + CacheOnly, + NetworkOnly, + All + }; + + var resourceURL: String = "Test"; + + var kind: Int = 0; + + var resourceKind: PluginProtocolHandlerResourceKind = PluginProtocolHandlerResourceKind.Unknown; + + var loadingMethod: PluginProtocolHandlerResourceLoadingMethod = PluginProtocolHandlerResourceLoadingMethod.Unknown; + + var tileData: TileData? = null; + +} diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt new file mode 100644 index 000000000000..eb36275ec31d --- /dev/null +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt @@ -0,0 +1,7 @@ +package org.maplibre.android.plugin + +class PluginProtocolHandlerResponse { + + var data: ByteArray? = null; + +} \ No newline at end of file diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/TileData.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/TileData.kt new file mode 100644 index 000000000000..9ecdb35b5460 --- /dev/null +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/TileData.kt @@ -0,0 +1,15 @@ +package org.maplibre.android.plugin + +class TileData { + + var tileURLTemplate: String? = null; + + var tilePixelRatio: Int = 0; + + var tileX: Int = 0; + + var tileY: Int = 0; + + var tileZoom: Int = 0; + +} \ No newline at end of file diff --git a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/maplayout/SimpleMapActivity.kt b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/maplayout/SimpleMapActivity.kt index 8afad9bf94be..1717ee451d08 100644 --- a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/maplayout/SimpleMapActivity.kt +++ b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/maplayout/SimpleMapActivity.kt @@ -6,6 +6,7 @@ import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity import org.maplibre.android.maps.* import org.maplibre.android.testapp.R +import org.maplibre.android.testapp.activity.plugin.PluginProtocolExample import org.maplibre.android.testapp.utils.ApiKeyUtils import org.maplibre.android.testapp.utils.NavUtils @@ -27,6 +28,8 @@ class SimpleMapActivity : AppCompatActivity() { mapView = findViewById(R.id.mapView) mapView.onCreate(savedInstanceState) mapView.getMapAsync { + val protocolExample = PluginProtocolExample(); + mapView.addPluginProtocolHandler(protocolExample); val key = ApiKeyUtils.getApiKey(applicationContext) if (key == null || key == "YOUR_API_KEY_GOES_HERE") { it.setStyle( diff --git a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt new file mode 100644 index 000000000000..fdddaecf7668 --- /dev/null +++ b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt @@ -0,0 +1,34 @@ +package org.maplibre.android.testapp.activity.plugin + +import org.maplibre.android.plugin.PluginProtocolHandler +import org.maplibre.android.plugin.PluginProtocolHandlerResource +import org.maplibre.android.plugin.PluginProtocolHandlerResponse + +class PluginProtocolExample : PluginProtocolHandler() { + + override fun canRequestResource(resource: PluginProtocolHandlerResource?): Boolean { + + if (resource == null) { + return false; + } + + if (resource.resourceURL != null) { + if (resource.resourceURL!!.contains("pluginProtocol")) { + return true; + } + } + + if (resource.resourceKind == PluginProtocolHandlerResource.PluginProtocolHandlerResourceKind.Unknown) { + return true; + } + + return false; + } + + + override fun requestResource(resource: PluginProtocolHandlerResource?): PluginProtocolHandlerResponse? { + // Return some data here + return null; + } + +} \ No newline at end of file diff --git a/platform/android/android.cmake b/platform/android/android.cmake index cb9e28e5a5de..72fc11d7276f 100644 --- a/platform/android/android.cmake +++ b/platform/android/android.cmake @@ -45,6 +45,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/platform/android/src/string_util.cpp ${PROJECT_SOURCE_DIR}/platform/android/src/thread.cpp ${PROJECT_SOURCE_DIR}/platform/android/src/timer.cpp + ${PROJECT_SOURCE_DIR}/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/gfx/headless_backend.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/gfx/headless_frontend.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/map/map_snapshotter.cpp @@ -61,6 +62,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/offline_database.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/offline_download.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/online_file_source.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/plugin_file_source.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/$,pmtiles_file_source.cpp,pmtiles_file_source_stub.cpp> ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/storage/sqlite3.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/text/bidi.cpp diff --git a/platform/default/src/mbgl/storage/plugin_file_source.cpp b/platform/default/src/mbgl/storage/plugin_file_source.cpp index 0e0fa0b79b1c..120308a743da 100644 --- a/platform/default/src/mbgl/storage/plugin_file_source.cpp +++ b/platform/default/src/mbgl/storage/plugin_file_source.cpp @@ -15,7 +15,7 @@ namespace mbgl { -void PluginFileSource::setProtocolPrefix(const std::string& protocolPrefix) {} +void PluginFileSource::setProtocolPrefix([[maybe_unused]] const std::string& protocolPrefix) {} class PluginFileSource::Impl { public: From 7d27873278e4ff8bf8d6e823e4b85677f731c794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Tue, 29 Jul 2025 17:16:20 -0400 Subject: [PATCH 36/49] Passing along the byte buffer from the plugin to the native response --- .../MapLibreAndroid/src/cpp/jni_native.cpp | 1 + .../src/cpp/native_map_view.cpp | 13 ++++- .../src/cpp/plugin/plugin_file_source.cpp | 51 ++++++++++++++----- .../src/cpp/plugin/plugin_file_source.hpp | 12 +++++ .../android/plugin/PluginFileSource.java | 14 +---- .../plugin/PluginProtocolHandlerResponse.kt | 14 ++++- .../activity/plugin/PluginProtocolExample.kt | 4 +- 7 files changed, 79 insertions(+), 30 deletions(-) diff --git a/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp b/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp index 55071f20bf42..24ab77e1b224 100644 --- a/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/jni_native.cpp @@ -110,6 +110,7 @@ void registerNatives(JavaVM* vm) { // Plugins PluginProtocolHandlerResource::registerNative(env); + PluginProtocolHandlerResponse::registerNative(env); PluginFileSource::registerNative(env); // Map diff --git a/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp b/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp index 588dcd67a080..8fa8331b6839 100644 --- a/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp @@ -1342,9 +1342,18 @@ void NativeMapView::addPluginFileSource(JNIEnv &jniEnv, std::shared_ptr pluginSource = std::make_shared(resourceOptions, clientOptions); pluginSource->setOnRequestResourceFunction([fileSourceContainer](const mbgl::Resource &resource) -> mbgl::Response { - mbgl::Response tempResult; + mbgl::Response tempResponse; - return tempResult; + android::UniqueEnv env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*env); + static auto requestResource = javaClass.GetMethod(jni::Object)>(*env, "requestResource"); + auto javaResource = PluginFileSource::createJavaResource(*env, resource); + auto tempResult = fileSourceContainer->_fileSource.Call(*env, requestResource, javaResource); + PluginProtocolHandlerResponse::Update(*env, + tempResult, + tempResponse); + + return tempResponse; }); pluginSource->setOnCanRequestFunction([fileSourceContainer](const mbgl::Resource &resource) -> bool { android::UniqueEnv env = android::AttachEnv(); diff --git a/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp b/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp index 425142d21a18..a7153e87c11d 100644 --- a/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp @@ -3,6 +3,25 @@ using namespace mbgl::android; +// Putting these here (should probably move out to a more dedicated JNI place within +// the native repo at some point, but this means we don't have to update +// the jni.hpp dependency +namespace jni { + + struct ByteBufferTag + { + static constexpr auto Name() { return "java/nio/ByteBuffer"; } + }; + + template <> + struct TagTraits< ByteBufferTag > + { + using SuperType = Object; + using UntaggedType = jobject; + }; + +} + void PluginFileSource::registerNative(jni::JNIEnv& env) { jni::Class::Singleton(env); } @@ -40,20 +59,24 @@ void PluginProtocolHandlerResource::Update(jni::JNIEnv& env, } +void PluginProtocolHandlerResponse::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} +jni::Local> PluginProtocolHandlerResponse::Create(jni::JNIEnv&env) { + auto& javaClass = jni::Class::Singleton(env); + auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor); +} - - - -/* -mbgl::PluginFileSource PluginFileSource::getFileSource(jni::JNIEnv&, - const jni::Object&) { - - ResourceOptions resourceOptions; - ClientOptions clientOptions; - mbgl::PluginFileSource tempResult(resourceOptions, clientOptions); - - return tempResult; - +void PluginProtocolHandlerResponse::Update(jni::JNIEnv & env, + [[maybe_unused]] jni::Object& javaObject, + [[maybe_unused]] mbgl::Response &response) { + static auto &javaClass = jni::Class::Singleton(env); + static auto dataField = javaClass.GetField>(env, "data"); + auto objectValue = javaObject.Get(env, dataField); + auto objectRef = jobject(objectValue.get()); + void* bufPtr = env.GetDirectBufferAddress(objectRef); + jsize length = env.GetDirectBufferCapacity(objectRef); + response.data = std::make_shared((const char*)bufPtr, length); } -*/ \ No newline at end of file diff --git a/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.hpp b/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.hpp index a98c0bcc9b45..6e829004a513 100644 --- a/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.hpp +++ b/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.hpp @@ -15,6 +15,18 @@ namespace mbgl { static void Update(jni::JNIEnv&, jni::Object&, const mbgl::Resource &); }; + class PluginProtocolHandlerResponse { + public: + static constexpr auto Name() { return "org/maplibre/android/plugin/PluginProtocolHandlerResponse"; }; + static void registerNative(jni::JNIEnv&); + + static jni::Local> Create(jni::JNIEnv&); + static void Update(jni::JNIEnv&, + jni::Object&, + mbgl::Response &); + + }; + class PluginFileSource { public: static constexpr auto Name() { return "org/maplibre/android/plugin/PluginFileSource"; }; diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginFileSource.java b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginFileSource.java index 5f19cad98fba..e99ca05a08fb 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginFileSource.java +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginFileSource.java @@ -6,20 +6,10 @@ public class PluginFileSource { public boolean canRequestResource(PluginProtocolHandlerResource resource) { - if (protocolHandler.canRequestResource(resource)) { - return true; - } - return false; + return protocolHandler.canRequestResource(resource); } -/* - public boolean canRequestResource() { - if (protocolHandler.canRequestResource(resource)) { - return true; - } - return false; - } -*/ + public PluginProtocolHandlerResponse requestResource(PluginProtocolHandlerResource resource) { PluginProtocolHandlerResponse response = protocolHandler.requestResource(resource); return response; diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt index eb36275ec31d..d9fd3a242739 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt @@ -1,7 +1,19 @@ package org.maplibre.android.plugin +import java.nio.ByteBuffer + class PluginProtocolHandlerResponse { - var data: ByteArray? = null; + fun generateBuffer() { + data = ByteBuffer.allocateDirect(1000); + + // Example: write bytes + for (i in 0..<255) { + data!!.put(i.toByte()) + } + + } + + var data: ByteBuffer? = null; } \ No newline at end of file diff --git a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt index fdddaecf7668..7b1970a886a6 100644 --- a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt +++ b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt @@ -28,7 +28,9 @@ class PluginProtocolExample : PluginProtocolHandler() { override fun requestResource(resource: PluginProtocolHandlerResource?): PluginProtocolHandlerResponse? { // Return some data here - return null; + var tempResult = PluginProtocolHandlerResponse(); + tempResult.generateBuffer(); + return tempResult; } } \ No newline at end of file From 73d92782e8a2f0ecfb6fd08de5feaca14ecd754e Mon Sep 17 00:00:00 2001 From: AtlasProgramming Date: Tue, 29 Jul 2025 17:27:52 -0400 Subject: [PATCH 37/49] Update src/mbgl/plugin/feature_collection.hpp Co-authored-by: Tim Sylvester --- src/mbgl/plugin/feature_collection.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/plugin/feature_collection.hpp b/src/mbgl/plugin/feature_collection.hpp index 3ea9b5c70b5a..6520105f3294 100644 --- a/src/mbgl/plugin/feature_collection.hpp +++ b/src/mbgl/plugin/feature_collection.hpp @@ -22,7 +22,7 @@ class FeatureCoordinate { double _tileY = 0; // Tile coord }; -// This is a list of coordinates. Broken out into it's own class because +// This is a list of coordinates. Broken out into its own class because // a raw bucket feature can have an array of these class FeatureCoordinateCollection { public: From 386b898f97c315c8f2e0a70d30cef81d4fe36873 Mon Sep 17 00:00:00 2001 From: AtlasProgramming Date: Tue, 29 Jul 2025 17:28:06 -0400 Subject: [PATCH 38/49] Update src/mbgl/plugin/plugin_layer_render.cpp Co-authored-by: Tim Sylvester --- src/mbgl/plugin/plugin_layer_render.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/plugin/plugin_layer_render.cpp b/src/mbgl/plugin/plugin_layer_render.cpp index 8b57e8d071eb..27c4d3b6e806 100644 --- a/src/mbgl/plugin/plugin_layer_render.cpp +++ b/src/mbgl/plugin/plugin_layer_render.cpp @@ -130,7 +130,7 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis continue; } - // See if we already have this tile'a feature collection + // See if we already have this tile's feature collection if (_featureCollectionByTile.contains(tileID)) { continue; } From 34d9abf2d4929bebd2f74a11d3d9e49179a9640b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Tue, 29 Jul 2025 17:38:34 -0400 Subject: [PATCH 39/49] Updafed with feedback --- platform/ios/src/MLNMapView.mm | 2 +- src/mbgl/plugin/feature_collection_bucket.cpp | 13 +++++-------- src/mbgl/plugin/feature_collection_bucket.hpp | 1 - src/mbgl/plugin/plugin_layer_factory.cpp | 4 ++-- src/mbgl/plugin/plugin_layer_factory.hpp | 2 +- src/mbgl/plugin/plugin_layer_render.cpp | 3 --- 6 files changed, 9 insertions(+), 16 deletions(-) diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index 4c2aa9d24851..001279737495 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -7745,7 +7745,7 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { __weak MLNMapView *weakMapView = self; Class layerClass = pluginLayerClass; - factory->_supportsFeatureCollectionBuckets = capabilities.supportsReadingTileFeatures; + factory->supportsFeatureCollectionBuckets = capabilities.supportsReadingTileFeatures; factory->setOnLayerCreatedEvent([layerClass, weakMapView, pluginLayerClass](mbgl::style::PluginLayer *pluginLayer) { //NSLog(@"Creating Plugin Layer: %@", layerClass); diff --git a/src/mbgl/plugin/feature_collection_bucket.cpp b/src/mbgl/plugin/feature_collection_bucket.cpp index 05cdf268c4b6..fb2c9f9e6625 100644 --- a/src/mbgl/plugin/feature_collection_bucket.cpp +++ b/src/mbgl/plugin/feature_collection_bucket.cpp @@ -38,18 +38,15 @@ void geometryToLatLon(const GeometryCoordinate& coord, } std::string toString(FeatureIdentifier& v) { - std::string tempResult = ""; auto ti = v.which(); - if (ti == 0) { - return tempResult; - } else if (ti == 1) { - tempResult = std::to_string(v.get()); + if (ti == 1) { + return std::to_string(v.get()); } else if (ti == 2) { - tempResult = std::to_string(v.get()); + return std::to_string(v.get()); } else if (ti == 3) { - tempResult = v.get(); + return v.get(); } - return tempResult; + return ""; } void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, diff --git a/src/mbgl/plugin/feature_collection_bucket.hpp b/src/mbgl/plugin/feature_collection_bucket.hpp index fc5499488822..90ae88bb738f 100644 --- a/src/mbgl/plugin/feature_collection_bucket.hpp +++ b/src/mbgl/plugin/feature_collection_bucket.hpp @@ -19,7 +19,6 @@ class RenderFillLayer; class FeatureCollectionBucket final : public Bucket { public: ~FeatureCollectionBucket() override; - // using PossiblyEvaluatedLayoutProperties = style::FillLayoutProperties::PossiblyEvaluated; FeatureCollectionBucket(const BucketParameters&, const std::vector>&); diff --git a/src/mbgl/plugin/plugin_layer_factory.cpp b/src/mbgl/plugin/plugin_layer_factory.cpp index a30db5105ee8..8fc2d8b1027f 100644 --- a/src/mbgl/plugin/plugin_layer_factory.cpp +++ b/src/mbgl/plugin/plugin_layer_factory.cpp @@ -151,7 +151,7 @@ std::unique_ptr PluginLayerFactory::createLayer(const std::string& } std::string sourceStr = "pluginLayerNoSource"; - if (_supportsFeatureCollectionBuckets) { + if (supportsFeatureCollectionBuckets) { auto source = getSource(value); if (source.has_value()) { sourceStr = source.value(); @@ -179,7 +179,7 @@ std::unique_ptr PluginLayerFactory::createLayer(const std::string& std::unique_ptr PluginLayerFactory::createBucket( [[maybe_unused]] const BucketParameters& parameters, [[maybe_unused]] const std::vector>& layers) noexcept { - if (_supportsFeatureCollectionBuckets) { + if (supportsFeatureCollectionBuckets) { return std::make_unique(parameters, layers); } return nullptr; diff --git a/src/mbgl/plugin/plugin_layer_factory.hpp b/src/mbgl/plugin/plugin_layer_factory.hpp index e2d3aa4e392b..a0acc5936afd 100644 --- a/src/mbgl/plugin/plugin_layer_factory.hpp +++ b/src/mbgl/plugin/plugin_layer_factory.hpp @@ -24,7 +24,7 @@ class PluginLayerFactory : public LayerFactory { mbgl::style::LayerTypeInfo::TileKind tileKind); // Set to false, but if the caller wants to support on features loaded, then set this to true - bool _supportsFeatureCollectionBuckets = false; + bool supportsFeatureCollectionBuckets = false; using OnLayerCreatedEvent = std::function; void setOnLayerCreatedEvent(OnLayerCreatedEvent onLayerCreated) { _onLayerCreated = onLayerCreated; } diff --git a/src/mbgl/plugin/plugin_layer_render.cpp b/src/mbgl/plugin/plugin_layer_render.cpp index 8b57e8d071eb..cd858a688a48 100644 --- a/src/mbgl/plugin/plugin_layer_render.cpp +++ b/src/mbgl/plugin/plugin_layer_render.cpp @@ -115,9 +115,6 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); - if (!hasRenderTile(tileID)) { - } - const auto* optRenderData = getRenderDataForPass(tile, drawPass); if (!optRenderData || !optRenderData->bucket || !optRenderData->bucket->hasData()) { removeTile(drawPass, tileID); From 9c3ef30aa787a2eaa01b776b5a3ccaf423d19a6b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 21:42:24 +0000 Subject: [PATCH 40/49] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../src/cpp/native_map_view.cpp | 83 ++++++++----------- .../src/cpp/native_map_view.hpp | 5 +- .../src/cpp/plugin/plugin_file_source.cpp | 46 +++++----- .../src/cpp/plugin/plugin_file_source.hpp | 63 +++++++------- .../plugin/PluginProtocolHandlerResponse.kt | 2 +- .../org/maplibre/android/plugin/TileData.kt | 2 +- .../activity/plugin/PluginProtocolExample.kt | 2 +- 7 files changed, 91 insertions(+), 112 deletions(-) diff --git a/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp b/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp index 8fa8331b6839..910ef7d4fea4 100644 --- a/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp @@ -1323,9 +1323,7 @@ void NativeMapView::enableRenderingStatsView(JNIEnv&, jni::jboolean value) { } // Plugins -void NativeMapView::addPluginFileSource(JNIEnv &jniEnv, - const jni::Object& pluginFileSource) { - +void NativeMapView::addPluginFileSource(JNIEnv& jniEnv, const jni::Object& pluginFileSource) { // TODO: Unclear if any of these options are needed for plugins mbgl::ResourceOptions resourceOptions; @@ -1340,30 +1338,31 @@ void NativeMapView::addPluginFileSource(JNIEnv &jniEnv, fileSourceContainer->_fileSource = std::move(pluginPeer); _pluginFileSources.push_back(fileSourceContainer); - std::shared_ptr pluginSource = std::make_shared(resourceOptions, clientOptions); - pluginSource->setOnRequestResourceFunction([fileSourceContainer](const mbgl::Resource &resource) -> mbgl::Response { + std::shared_ptr pluginSource = std::make_shared(resourceOptions, + clientOptions); + pluginSource->setOnRequestResourceFunction([fileSourceContainer](const mbgl::Resource& resource) -> mbgl::Response { mbgl::Response tempResponse; android::UniqueEnv env = android::AttachEnv(); static auto& javaClass = jni::Class::Singleton(*env); - static auto requestResource = javaClass.GetMethod(jni::Object)>(*env, "requestResource"); + static auto requestResource = + javaClass.GetMethod(jni::Object)>( + *env, "requestResource"); auto javaResource = PluginFileSource::createJavaResource(*env, resource); auto tempResult = fileSourceContainer->_fileSource.Call(*env, requestResource, javaResource); - PluginProtocolHandlerResponse::Update(*env, - tempResult, - tempResponse); + PluginProtocolHandlerResponse::Update(*env, tempResult, tempResponse); return tempResponse; }); - pluginSource->setOnCanRequestFunction([fileSourceContainer](const mbgl::Resource &resource) -> bool { + pluginSource->setOnCanRequestFunction([fileSourceContainer](const mbgl::Resource& resource) -> bool { android::UniqueEnv env = android::AttachEnv(); static auto& javaClass = jni::Class::Singleton(*env); - static auto canRequestResource = javaClass.GetMethod)>(*env, "canRequestResource"); + static auto canRequestResource = javaClass.GetMethod)>( + *env, "canRequestResource"); auto javaResource = PluginFileSource::createJavaResource(*env, resource); auto tempResult = fileSourceContainer->_fileSource.Call(*env, canRequestResource, javaResource); return tempResult; - /* if (!renderingStats) { renderingStats = jni::NewGlobal(*_env, RenderingStats::Create(*_env)); @@ -1376,49 +1375,40 @@ void NativeMapView::addPluginFileSource(JNIEnv &jniEnv, (jboolean)(status.mode != MapObserver::RenderMode::Partial), renderingStats); */ -/* - static auto resourceURLField = javaClass.GetField>(env, "resource"); - auto str = jni::Make(env, resource.url); // wrap the jstring - javaObject.Set(env, resourceURLField, str); - - fileSourceContainer->_fileSource.Set(env, ) -*/ - - - + /* + static auto resourceURLField = javaClass.GetField>(env, + "resource"); auto str = jni::Make(env, resource.url); // wrap the jstring javaObject.Set(env, + resourceURLField, str); + fileSourceContainer->_fileSource.Set(env, ) + */ }); auto fileSourceManager = mbgl::FileSourceManager::get(); fileSourceManager->registerCustomFileSource(pluginSource); - -/* - android::UniqueEnv _env = android::AttachEnv(); - static auto& javaClass = jni::Class::Singleton(*_env); - static auto onDidFinishRenderingFrame = javaClass.GetMethod)>( - *_env, "onDidFinishRenderingFrame"); - auto weakReference = javaPeer.get(*_env); - if (weakReference) { - if (!renderingStats) { - renderingStats = jni::NewGlobal(*_env, RenderingStats::Create(*_env)); + /* + android::UniqueEnv _env = android::AttachEnv(); + static auto& javaClass = jni::Class::Singleton(*_env); + static auto onDidFinishRenderingFrame = javaClass.GetMethod)>( + *_env, "onDidFinishRenderingFrame"); + auto weakReference = javaPeer.get(*_env); + if (weakReference) { + if (!renderingStats) { + renderingStats = jni::NewGlobal(*_env, RenderingStats::Create(*_env)); + } + + RenderingStats::Update(*_env, renderingStats, status.renderingStats); + + weakReference.Call(*_env, + onDidFinishRenderingFrame, + (jboolean)(status.mode != MapObserver::RenderMode::Partial), + renderingStats); } - RenderingStats::Update(*_env, renderingStats, status.renderingStats); - - weakReference.Call(*_env, - onDidFinishRenderingFrame, - (jboolean)(status.mode != MapObserver::RenderMode::Partial), - renderingStats); - } - - */ - - - + */ } - - // Static methods // void NativeMapView::registerNative(jni::JNIEnv& env) { @@ -1543,7 +1533,6 @@ void NativeMapView::registerNative(jni::JNIEnv& env) { METHOD(&NativeMapView::isRenderingStatsViewEnabled, "nativeIsRenderingStatsViewEnabled"), METHOD(&NativeMapView::enableRenderingStatsView, "nativeEnableRenderingStatsView"), METHOD(&NativeMapView::addPluginFileSource, "nativeAddPluginFileSource")); - } void NativeMapView::onRegisterShaders(gfx::ShaderRegistry&) {}; diff --git a/platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp b/platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp index 2eec8461c909..ab58fcdd904b 100644 --- a/platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp +++ b/platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp @@ -326,10 +326,9 @@ class NativeMapView : public MapObserver { void enableRenderingStatsView(JNIEnv&, jni::jboolean); // Plugins - void addPluginFileSource(JNIEnv &, - const jni::Object& ); + void addPluginFileSource(JNIEnv&, const jni::Object&); - // Shader compilation + // Shader compilation void onRegisterShaders(mbgl::gfx::ShaderRegistry&) override; void onPreCompileShader(mbgl::shaders::BuiltIn, mbgl::gfx::Backend::Type, const std::string&) override; void onPostCompileShader(mbgl::shaders::BuiltIn, mbgl::gfx::Backend::Type, const std::string&) override; diff --git a/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp b/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp index a7153e87c11d..b288678af17a 100644 --- a/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.cpp @@ -8,27 +8,26 @@ using namespace mbgl::android; // the jni.hpp dependency namespace jni { - struct ByteBufferTag - { - static constexpr auto Name() { return "java/nio/ByteBuffer"; } - }; - - template <> - struct TagTraits< ByteBufferTag > - { - using SuperType = Object; - using UntaggedType = jobject; - }; +struct ByteBufferTag { + static constexpr auto Name() { return "java/nio/ByteBuffer"; } +}; -} +template <> +struct TagTraits { + using SuperType = Object; + using UntaggedType = jobject; +}; + +} // namespace jni void PluginFileSource::registerNative(jni::JNIEnv& env) { jni::Class::Singleton(env); } -jni::Global> PluginFileSource::createJavaResource(jni::JNIEnv& env, - const mbgl::Resource &resource) { - jni::Global> tempResult = jni::NewGlobal(env, PluginProtocolHandlerResource::Create(env)); +jni::Global> PluginFileSource::createJavaResource( + jni::JNIEnv& env, const mbgl::Resource& resource) { + jni::Global> tempResult = jni::NewGlobal( + env, PluginProtocolHandlerResource::Create(env)); PluginProtocolHandlerResource::Update(env, tempResult, resource); return tempResult; } @@ -44,10 +43,9 @@ jni::Local> PluginProtocolHandlerReso } void PluginProtocolHandlerResource::Update(jni::JNIEnv& env, - jni::Object& javaObject, - const mbgl::Resource &resource) { - - static auto &javaClass = jni::Class::Singleton(env); + jni::Object& javaObject, + const mbgl::Resource& resource) { + static auto& javaClass = jni::Class::Singleton(env); static auto resourceKindField = javaClass.GetField(env, "kind"); javaObject.Set(env, resourceKindField, static_cast(resource.kind)); @@ -55,24 +53,22 @@ void PluginProtocolHandlerResource::Update(jni::JNIEnv& env, static auto resourceURLField = javaClass.GetField(env, "resourceURL"); auto str = jni::Make(env, resource.url); // wrap the jstring javaObject.Set(env, resourceURLField, str); - } - void PluginProtocolHandlerResponse::registerNative(jni::JNIEnv& env) { jni::Class::Singleton(env); } -jni::Local> PluginProtocolHandlerResponse::Create(jni::JNIEnv&env) { +jni::Local> PluginProtocolHandlerResponse::Create(jni::JNIEnv& env) { auto& javaClass = jni::Class::Singleton(env); auto constructor = javaClass.GetConstructor(env); return javaClass.New(env, constructor); } -void PluginProtocolHandlerResponse::Update(jni::JNIEnv & env, +void PluginProtocolHandlerResponse::Update(jni::JNIEnv& env, [[maybe_unused]] jni::Object& javaObject, - [[maybe_unused]] mbgl::Response &response) { - static auto &javaClass = jni::Class::Singleton(env); + [[maybe_unused]] mbgl::Response& response) { + static auto& javaClass = jni::Class::Singleton(env); static auto dataField = javaClass.GetField>(env, "data"); auto objectValue = javaObject.Get(env, dataField); auto objectRef = jobject(objectValue.get()); diff --git a/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.hpp b/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.hpp index 6e829004a513..cea25e21e4de 100644 --- a/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.hpp +++ b/platform/android/MapLibreAndroid/src/cpp/plugin/plugin_file_source.hpp @@ -4,47 +4,42 @@ #include namespace mbgl { - namespace android { +namespace android { - class PluginProtocolHandlerResource { - public: - static constexpr auto Name() { return "org/maplibre/android/plugin/PluginProtocolHandlerResource"; }; - static void registerNative(jni::JNIEnv&); +class PluginProtocolHandlerResource { +public: + static constexpr auto Name() { return "org/maplibre/android/plugin/PluginProtocolHandlerResource"; }; + static void registerNative(jni::JNIEnv &); - static jni::Local> Create(jni::JNIEnv&); - static void Update(jni::JNIEnv&, jni::Object&, const mbgl::Resource &); - }; + static jni::Local> Create(jni::JNIEnv &); + static void Update(jni::JNIEnv &, jni::Object &, const mbgl::Resource &); +}; - class PluginProtocolHandlerResponse { - public: - static constexpr auto Name() { return "org/maplibre/android/plugin/PluginProtocolHandlerResponse"; }; - static void registerNative(jni::JNIEnv&); +class PluginProtocolHandlerResponse { +public: + static constexpr auto Name() { return "org/maplibre/android/plugin/PluginProtocolHandlerResponse"; }; + static void registerNative(jni::JNIEnv &); - static jni::Local> Create(jni::JNIEnv&); - static void Update(jni::JNIEnv&, - jni::Object&, - mbgl::Response &); + static jni::Local> Create(jni::JNIEnv &); + static void Update(jni::JNIEnv &, jni::Object &, mbgl::Response &); +}; - }; +class PluginFileSource { +public: + static constexpr auto Name() { return "org/maplibre/android/plugin/PluginFileSource"; }; - class PluginFileSource { - public: - static constexpr auto Name() { return "org/maplibre/android/plugin/PluginFileSource"; }; + // static mbgl::PluginFileSource getFileSource(jni::JNIEnv&, const jni::Object&); - //static mbgl::PluginFileSource getFileSource(jni::JNIEnv&, const jni::Object&); + static jni::Global> createJavaResource(jni::JNIEnv &env, + const mbgl::Resource &resource); - static jni::Global> createJavaResource(jni::JNIEnv& env, - const mbgl::Resource &resource); - - static void registerNative(jni::JNIEnv&); - }; - - class PluginFileSourceContainer { - public: - jni::Global> _fileSource; - }; - - } -} + static void registerNative(jni::JNIEnv &); +}; +class PluginFileSourceContainer { +public: + jni::Global> _fileSource; +}; +} // namespace android +} // namespace mbgl diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt index d9fd3a242739..c630626e4ed8 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt @@ -16,4 +16,4 @@ class PluginProtocolHandlerResponse { var data: ByteBuffer? = null; -} \ No newline at end of file +} diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/TileData.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/TileData.kt index 9ecdb35b5460..2a9f27abe151 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/TileData.kt +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/TileData.kt @@ -12,4 +12,4 @@ class TileData { var tileZoom: Int = 0; -} \ No newline at end of file +} diff --git a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt index 7b1970a886a6..42838fadcce5 100644 --- a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt +++ b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt @@ -33,4 +33,4 @@ class PluginProtocolExample : PluginProtocolHandler() { return tempResult; } -} \ No newline at end of file +} From f40828257f49421ba5324f370f4ea42f4e417e19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Tue, 29 Jul 2025 18:10:53 -0400 Subject: [PATCH 41/49] Updates --- .../plugin/PluginProtocolHandlerResource.kt | 10 ++-- .../plugin/PluginProtocolHandlerResponse.kt | 15 +++--- .../activity/plugin/PluginProtocolExample.kt | 48 +++++++++++++------ 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResource.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResource.kt index f72b4628889f..606311cdf690 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResource.kt +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResource.kt @@ -2,7 +2,7 @@ package org.maplibre.android.plugin class PluginProtocolHandlerResource { - enum class PluginProtocolHandlerResourceKind { + enum class Kind { Unknown, Style, Source, @@ -13,20 +13,20 @@ class PluginProtocolHandlerResource { Image }; - enum class PluginProtocolHandlerResourceLoadingMethod { + enum class LoadingMethod { Unknown, CacheOnly, NetworkOnly, All }; - var resourceURL: String = "Test"; + var resourceURL: String = ""; var kind: Int = 0; - var resourceKind: PluginProtocolHandlerResourceKind = PluginProtocolHandlerResourceKind.Unknown; + var resourceKind: Kind = Kind.Unknown; - var loadingMethod: PluginProtocolHandlerResourceLoadingMethod = PluginProtocolHandlerResourceLoadingMethod.Unknown; + var loadingMethod: LoadingMethod = LoadingMethod.Unknown; var tileData: TileData? = null; diff --git a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt index c630626e4ed8..5df047bd7c51 100644 --- a/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt +++ b/platform/android/MapLibreAndroid/src/main/java/org/maplibre/android/plugin/PluginProtocolHandlerResponse.kt @@ -1,17 +1,16 @@ package org.maplibre.android.plugin import java.nio.ByteBuffer +import java.nio.charset.StandardCharsets class PluginProtocolHandlerResponse { - fun generateBuffer() { - data = ByteBuffer.allocateDirect(1000); - - // Example: write bytes - for (i in 0..<255) { - data!!.put(i.toByte()) - } - + fun generateBuffer(stringBuffer: String) { + val byteArray = stringBuffer.toByteArray(StandardCharsets.UTF_8); + val buffer = ByteBuffer.allocateDirect(byteArray.size); + buffer.put(byteArray); + buffer.flip(); + data = buffer; } var data: ByteBuffer? = null; diff --git a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt index 42838fadcce5..6e99f2cf0b73 100644 --- a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt +++ b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt @@ -3,33 +3,51 @@ package org.maplibre.android.testapp.activity.plugin import org.maplibre.android.plugin.PluginProtocolHandler import org.maplibre.android.plugin.PluginProtocolHandlerResource import org.maplibre.android.plugin.PluginProtocolHandlerResponse +import java.net.URI + class PluginProtocolExample : PluginProtocolHandler() { override fun canRequestResource(resource: PluginProtocolHandlerResource?): Boolean { - if (resource == null) { - return false; - } - - if (resource.resourceURL != null) { - if (resource.resourceURL!!.contains("pluginProtocol")) { - return true; - } - } + return true; - if (resource.resourceKind == PluginProtocolHandlerResource.PluginProtocolHandlerResourceKind.Unknown) { - return true; - } - - return false; } override fun requestResource(resource: PluginProtocolHandlerResource?): PluginProtocolHandlerResponse? { // Return some data here var tempResult = PluginProtocolHandlerResponse(); - tempResult.generateBuffer(); + + val tempStyle: String = + "{\n" + + " \"id\": \"43f36e14-e3f5-43c1-84c0-50a9c80dc5c7\",\n" + + " \"name\": \"MapLibre\",\n" + + " \"zoom\": 0.8619833357855968,\n" + + " \"pitch\": 0,\n" + + " \"center\": [\n" + + " 17.65431710431244,\n" + + " 32.954120326746775\n" + + " ],\n" + + " \"layers\": [\n" + + " {\n" + + " \"id\": \"background\",\n" + + " \"type\": \"background\",\n" + + " \"paint\": {\n" + + " \"background-color\": \"#000000\"\n" + + " },\n" + + " \"filter\": [\n" + + " \"all\"\n" + + " ],\n" + + " \"layout\": {\n" + + " \"visibility\": \"visible\"\n" + + " },\n" + + " \"maxzoom\": 24\n" + + " }\n" + " ]\n" + " } \n" + + tempResult.generateBuffer(tempStyle); return tempResult; } From 3406120f733f8621174ed2dd441f4f6dbbc41763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Tue, 29 Jul 2025 21:15:09 -0400 Subject: [PATCH 42/49] Added example plugin --- .../activity/plugin/PluginProtocolExample.kt | 60 +++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt index 6e99f2cf0b73..f027dde05fc3 100644 --- a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt +++ b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/plugin/PluginProtocolExample.kt @@ -7,10 +7,14 @@ import java.net.URI class PluginProtocolExample : PluginProtocolHandler() { + var styleLoaded: Boolean = false; override fun canRequestResource(resource: PluginProtocolHandlerResource?): Boolean { - - return true; + if (!styleLoaded) { + styleLoaded = true; + return true; + } + return false; } @@ -43,9 +47,55 @@ class PluginProtocolExample : PluginProtocolHandler() { " \"visibility\": \"visible\"\n" + " },\n" + " \"maxzoom\": 24\n" + - " }\n" - " ]\n" - " } \n" + " },\n"+ + " {\n" + + " \"id\": \"coastline\",\n" + + " \"type\": \"line\",\n" + + " \"paint\": {\n" + + " \"line-blur\": 0.5,\n" + + " \"line-color\": \"#198EC8\",\n" + + " \"line-width\": {\n" + + " \"stops\": [\n" + + " [\n" + + " 0,\n" + + " 2\n" + + " ],\n" + + " [\n" + + " 6,\n" + + " 6\n" + + " ],\n" + + " [\n" + + " 14,\n" + + " 9\n" + + " ],\n" + + " [\n" + + " 22,\n" + + " 18\n" + + " ]\n" + + " ]\n" + + " }\n" + + " },\n" + + " \"filter\": [\n" + + " \"all\"\n" + + " ],\n" + + " \"layout\": {\n" + + " \"line-cap\": \"round\",\n" + + " \"line-join\": \"round\",\n" + + " \"visibility\": \"visible\"\n" + + " },\n" + + " \"source\": \"maplibre\",\n" + + " \"maxzoom\": 24,\n" + + " \"minzoom\": 0,\n" + + " \"source-layer\": \"countries\"\n" + + " }"+ + " ],\n"+ + " \"sources\": {\n" + + " \"maplibre\": {\n" + + " \"url\": \"https://demotiles.maplibre.org/tiles/tiles.json\",\n" + + " \"type\": \"vector\"\n" + + " },"+ + " \"version\": 8\n"+ + " } }\n"; tempResult.generateBuffer(tempStyle); return tempResult; From 4a8010c08b1f3a2170ca83cecf65041860e0e26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Fri, 1 Aug 2025 10:10:26 -0400 Subject: [PATCH 43/49] Updated the file source name --- platform/default/src/mbgl/storage/plugin_file_source.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/default/src/mbgl/storage/plugin_file_source.cpp b/platform/default/src/mbgl/storage/plugin_file_source.cpp index 120308a743da..163542eeef30 100644 --- a/platform/default/src/mbgl/storage/plugin_file_source.cpp +++ b/platform/default/src/mbgl/storage/plugin_file_source.cpp @@ -75,7 +75,7 @@ void PluginFileSource::setOnRequestResourceFunction(OnRequestResource requestFun PluginFileSource::PluginFileSource(const ResourceOptions& resourceOptions, const ClientOptions& clientOptions) : impl(std::make_unique>( util::makeThreadPrioritySetter(platform::EXPERIMENTAL_THREAD_PRIORITY_FILE), - "LocalFileSource", + "PluginFileSource", resourceOptions.clone(), clientOptions.clone())) {} From 0199769f7682c034b7758f7e6bbc622bf0e8a76b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Fri, 1 Aug 2025 10:55:29 -0400 Subject: [PATCH 44/49] Clean up from merge --- platform/ios/src/MLNMapView.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index 8c77a023f65a..305ebbf0adf7 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -7921,7 +7921,6 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { } -<<<<<<< HEAD - (MLNPluginProtocolHandlerResource *)resourceFromCoreResource:(const mbgl::Resource &)resource { MLNPluginProtocolHandlerResource *tempResult = [[MLNPluginProtocolHandlerResource alloc] init]; From a75ca03539bc042ed8eb54801f414ce8416add95 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 1 Aug 2025 15:16:32 +0000 Subject: [PATCH 45/49] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- platform/ios/src/MLNMapView.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/ios/src/MLNMapView.h b/platform/ios/src/MLNMapView.h index 5ce8c69b24cc..3758303e8d4c 100644 --- a/platform/ios/src/MLNMapView.h +++ b/platform/ios/src/MLNMapView.h @@ -2282,7 +2282,7 @@ vertically on the map. */ - (void)addPluginProtocolHandler:(Class)pluginProtocolHandlerClass; -/** +/** Adds a style filter to the map view */ - (void)addStyleFilter:(MLNStyleFilter *)styleFilter; From 9688d7d964c41d79479f0a2ea6c3323e186ada17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Tue, 5 Aug 2025 23:06:51 -0400 Subject: [PATCH 46/49] Added a couple of delegate methods to the network delegate --- platform/darwin/core/http_file_source.mm | 9 +++++++++ .../include/mbgl/interface/native_apple_interface.h | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/platform/darwin/core/http_file_source.mm b/platform/darwin/core/http_file_source.mm index 62ced8e7d1f3..5ca75e65c057 100644 --- a/platform/darwin/core/http_file_source.mm +++ b/platform/darwin/core/http_file_source.mm @@ -292,11 +292,20 @@ BOOL isValidMapboxEndpoint(NSURL *url) { assert(session); + if ([networkManager.delegate respondsToSelector:@selector(willSendRequest:)]) { + req = [networkManager.delegate willSendRequest:req]; + } + request->task = [session dataTaskWithRequest:req completionHandler:^(NSData* data, NSURLResponse* res, NSError* error) { session = nil; + if ([networkManager.delegate respondsToSelector:@selector(didReceiveResponse:data:error:)]) { + [networkManager.delegate didReceiveResponse:res data:data error:error]; + } + + if (error && [error code] == NSURLErrorCancelled) { [MLNNativeNetworkManager.sharedManager cancelDownloadEventForResponse:res]; return; diff --git a/platform/darwin/include/mbgl/interface/native_apple_interface.h b/platform/darwin/include/mbgl/interface/native_apple_interface.h index 7633819bb302..0976ed8a405f 100644 --- a/platform/darwin/include/mbgl/interface/native_apple_interface.h +++ b/platform/darwin/include/mbgl/interface/native_apple_interface.h @@ -10,6 +10,10 @@ NS_ASSUME_NONNULL_BEGIN - (NSURLSession *)sessionForNetworkManager:(MLNNativeNetworkManager *)networkManager; +-(NSMutableURLRequest *)willSendRequest:(NSMutableURLRequest *)request; + +-(void)didReceiveResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *)error; + @required - (NSURLSessionConfiguration *)sessionConfiguration; From f6684f57ae68ff02e75be1b6c10cff91202064f2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 03:09:31 +0000 Subject: [PATCH 47/49] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- platform/darwin/core/http_file_source.mm | 6 +++--- .../darwin/include/mbgl/interface/native_apple_interface.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/darwin/core/http_file_source.mm b/platform/darwin/core/http_file_source.mm index 5ca75e65c057..3c7303cfe92b 100644 --- a/platform/darwin/core/http_file_source.mm +++ b/platform/darwin/core/http_file_source.mm @@ -295,7 +295,7 @@ BOOL isValidMapboxEndpoint(NSURL *url) { if ([networkManager.delegate respondsToSelector:@selector(willSendRequest:)]) { req = [networkManager.delegate willSendRequest:req]; } - + request->task = [session dataTaskWithRequest:req completionHandler:^(NSData* data, NSURLResponse* res, NSError* error) { @@ -304,8 +304,8 @@ BOOL isValidMapboxEndpoint(NSURL *url) { if ([networkManager.delegate respondsToSelector:@selector(didReceiveResponse:data:error:)]) { [networkManager.delegate didReceiveResponse:res data:data error:error]; } - - + + if (error && [error code] == NSURLErrorCancelled) { [MLNNativeNetworkManager.sharedManager cancelDownloadEventForResponse:res]; return; diff --git a/platform/darwin/include/mbgl/interface/native_apple_interface.h b/platform/darwin/include/mbgl/interface/native_apple_interface.h index 0976ed8a405f..74532d763df9 100644 --- a/platform/darwin/include/mbgl/interface/native_apple_interface.h +++ b/platform/darwin/include/mbgl/interface/native_apple_interface.h @@ -10,9 +10,9 @@ NS_ASSUME_NONNULL_BEGIN - (NSURLSession *)sessionForNetworkManager:(MLNNativeNetworkManager *)networkManager; --(NSMutableURLRequest *)willSendRequest:(NSMutableURLRequest *)request; +- (NSMutableURLRequest *)willSendRequest:(NSMutableURLRequest *)request; --(void)didReceiveResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *)error; +- (void)didReceiveResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *)error; @required From 61dfbb35e3f74f687d33ede9e916d79f08d2970f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sat, 9 Aug 2025 21:58:41 -0400 Subject: [PATCH 48/49] Removed single feature loaded function --- platform/darwin/app/PluginLayerExample.mm | 6 ------ platform/darwin/src/MLNPluginLayer.h | 7 ------- platform/darwin/src/MLNPluginLayer.mm | 6 ------ platform/ios/src/MLNMapView.mm | 11 ----------- src/mbgl/plugin/feature_collection_bucket.cpp | 11 ----------- src/mbgl/plugin/plugin_layer.hpp | 1 - src/mbgl/plugin/plugin_layer_impl.hpp | 7 ------- 7 files changed, 49 deletions(-) diff --git a/platform/darwin/app/PluginLayerExample.mm b/platform/darwin/app/PluginLayerExample.mm index 92d7056a0f19..1339f51289dd 100644 --- a/platform/darwin/app/PluginLayerExample.mm +++ b/platform/darwin/app/PluginLayerExample.mm @@ -69,12 +69,6 @@ -(void)featureUnloaded:(MLNPluginLayerTileFeature *)tileFeature { } -- (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature { - - [self featureLoaded:tileFeature]; - -} - /// Called when a set of features are loaded from the tile - (void)onFeatureCollectionLoaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection { //NSLog(@"Feature Collection Loaded for tile: %@", tileFeatureCollection.tileID); diff --git a/platform/darwin/src/MLNPluginLayer.h b/platform/darwin/src/MLNPluginLayer.h index 5b3fe06f7cca..7f3242a13573 100644 --- a/platform/darwin/src/MLNPluginLayer.h +++ b/platform/darwin/src/MLNPluginLayer.h @@ -123,14 +123,7 @@ MLN_EXPORT /// dynamic properties are updated - (void)onUpdateLayerProperties:(NSDictionary *)layerProperties; -/// Called when a feature is loaded from the tile -- (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature; - /// Called when a set of features are loaded from the tile -/* - TODO: Think about returning that this layer doesn't care about this feature collection via a - bool/etc and then the underlying layer won't have to track this collection. - */ - (void)onFeatureCollectionLoaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection; /// Called when a set of features are unloaded because the tile goes out of scene/etc diff --git a/platform/darwin/src/MLNPluginLayer.mm b/platform/darwin/src/MLNPluginLayer.mm index 05de4517e1ce..0e57affd1e7f 100644 --- a/platform/darwin/src/MLNPluginLayer.mm +++ b/platform/darwin/src/MLNPluginLayer.mm @@ -74,12 +74,6 @@ -(void)onUpdateLayerProperties:(NSDictionary *)layerProperties { // Base class does nothing } -// If the layer properties indicate that this layer has a the ability to intercept -// features, then this method will be called when a feature is loaded -- (void)onFeatureLoaded:(MLNPluginLayerTileFeature *)tileFeature { - // Base class does nothing -} - // If the layer properties indicate that this layer has a the ability to intercept // features, then this method will be called when a feature is loaded - (void)onFeatureCollectionLoaded:(MLNPluginLayerTileFeatureCollection *)tileFeatureCollection { diff --git a/platform/ios/src/MLNMapView.mm b/platform/ios/src/MLNMapView.mm index 305ebbf0adf7..8e62beaeb131 100644 --- a/platform/ios/src/MLNMapView.mm +++ b/platform/ios/src/MLNMapView.mm @@ -7851,17 +7851,6 @@ -(void)addPluginLayerType:(Class)pluginLayerClass { // If this layer can read tile features, then setup that lambda if (capabilities.supportsReadingTileFeatures) { - pluginLayerImpl->setFeatureLoadedFunction([weakPlugInLayer, weakMapView](const std::shared_ptr feature) { - - @autoreleasepool { - MLNPluginLayerTileFeature *tileFeature = [weakMapView featureFromCore:feature]; - - [weakPlugInLayer onFeatureLoaded:tileFeature]; - - } - - }); - pluginLayerImpl->setFeatureCollectionLoadedFunction([weakPlugInLayer, weakMapView](const std::shared_ptr featureCollection) { diff --git a/src/mbgl/plugin/feature_collection_bucket.cpp b/src/mbgl/plugin/feature_collection_bucket.cpp index fb2c9f9e6625..09d24dbbd09b 100644 --- a/src/mbgl/plugin/feature_collection_bucket.cpp +++ b/src/mbgl/plugin/feature_collection_bucket.cpp @@ -111,17 +111,6 @@ void FeatureCollectionBucket::addFeature(const GeometryTileFeature& tileFeature, tempFeature->_featureCoordinates.push_back(c); } - for (auto l : _layers) { - auto bi = l->baseImpl; - auto bip = bi.get(); - auto pluginLayer = static_cast(bip); - if (pluginLayer != nullptr) { - if (pluginLayer->_featureLoadedFunction != nullptr) { - pluginLayer->_featureLoadedFunction(tempFeature); - } - } - } - _featureCollection->_features.push_back(tempFeature); } diff --git a/src/mbgl/plugin/plugin_layer.hpp b/src/mbgl/plugin/plugin_layer.hpp index 5e6bb9adb06d..07fd90228cad 100644 --- a/src/mbgl/plugin/plugin_layer.hpp +++ b/src/mbgl/plugin/plugin_layer.hpp @@ -31,7 +31,6 @@ class PluginLayer final : public Layer { using OnRenderLayer = std::function; using OnUpdateLayer = std::function; using OnUpdateLayerProperties = std::function; - using OnFeatureLoaded = std::function feature)>; using OnFeatureCollectionLoaded = std::function featureCollection)>; using OnFeatureCollectionUnloaded = diff --git a/src/mbgl/plugin/plugin_layer_impl.hpp b/src/mbgl/plugin/plugin_layer_impl.hpp index 7b79399ee07b..e79e75320d77 100644 --- a/src/mbgl/plugin/plugin_layer_impl.hpp +++ b/src/mbgl/plugin/plugin_layer_impl.hpp @@ -99,10 +99,6 @@ class PluginLayer::Impl : public Layer::Impl { _updateLayerPropertiesFunction = updateLayerPropertiesFunction; } - void setFeatureLoadedFunction(OnFeatureLoaded featureLoadedFunction) { - _featureLoadedFunction = featureLoadedFunction; - } - void setFeatureCollectionLoadedFunction(OnFeatureCollectionLoaded featureCollectionLoadedFunction) { _featureCollectionLoadedFunction = featureCollectionLoadedFunction; } @@ -125,9 +121,6 @@ class PluginLayer::Impl : public Layer::Impl { //! Optional: Called when the layer properties change. The properties are passed as JSON for now OnUpdateLayerProperties _updateLayerPropertiesFunction; - //! Optional: Called when feature is loaded - OnFeatureLoaded _featureLoadedFunction; - //! Optional: Called when a feature collection is loaded OnFeatureCollectionLoaded _featureCollectionLoadedFunction; From 34031b3242673b43cbebed848f5132e45727920f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CMalcolm?= <“mtoon@atlasprogramming.com”> Date: Sun, 14 Sep 2025 08:54:40 -0400 Subject: [PATCH 49/49] Updates --- platform/darwin/core/http_file_source.mm | 8 ++- platform/darwin/core/native_apple_interface.m | 16 +++++ .../mbgl/interface/native_apple_interface.h | 15 ++++- platform/ios/app/MBXViewController.mm | 1 + src/mbgl/plugin/plugin_layer_render.cpp | 62 ++++++++++--------- 5 files changed, 69 insertions(+), 33 deletions(-) diff --git a/platform/darwin/core/http_file_source.mm b/platform/darwin/core/http_file_source.mm index 3c7303cfe92b..d88f10e4b56e 100644 --- a/platform/darwin/core/http_file_source.mm +++ b/platform/darwin/core/http_file_source.mm @@ -301,8 +301,12 @@ BOOL isValidMapboxEndpoint(NSURL *url) { completionHandler:^(NSData* data, NSURLResponse* res, NSError* error) { session = nil; - if ([networkManager.delegate respondsToSelector:@selector(didReceiveResponse:data:error:)]) { - [networkManager.delegate didReceiveResponse:res data:data error:error]; + if ([networkManager.delegate respondsToSelector:@selector(didReceiveResponse:)]) { + NetworkResponse *networkResponse = [NetworkResponse responseWithData:data urlResponse:res error:error]; + networkResponse = [networkManager.delegate didReceiveResponse:networkResponse]; + data = networkResponse.data; + res = networkResponse.response; + error = networkResponse.error; } diff --git a/platform/darwin/core/native_apple_interface.m b/platform/darwin/core/native_apple_interface.m index edd3b981d76b..5d176ea4e255 100644 --- a/platform/darwin/core/native_apple_interface.m +++ b/platform/darwin/core/native_apple_interface.m @@ -1,6 +1,22 @@ #import #import +@implementation NetworkResponse + ++(NetworkResponse *)responseWithData:(NSData *)data + urlResponse:(NSURLResponse *)response + error:(NSError *)error { + + NetworkResponse *tempResult = [[NetworkResponse alloc] init]; + tempResult.data = data; + tempResult.response = response; + tempResult.error = error; + return tempResult; +} + +@end + + @implementation MLNNativeNetworkManager static MLNNativeNetworkManager *instance = nil; diff --git a/platform/darwin/include/mbgl/interface/native_apple_interface.h b/platform/darwin/include/mbgl/interface/native_apple_interface.h index 74532d763df9..34513c5850e0 100644 --- a/platform/darwin/include/mbgl/interface/native_apple_interface.h +++ b/platform/darwin/include/mbgl/interface/native_apple_interface.h @@ -4,6 +4,19 @@ NS_ASSUME_NONNULL_BEGIN @class MLNNativeNetworkManager; +@interface NetworkResponse : NSObject + +@property (nullable) NSError *error; +@property (nullable) NSData *data; +@property NSURLResponse *response; + ++(NetworkResponse *)responseWithData:(NSData *)data + urlResponse:(NSURLResponse *)response + error:(NSError *)error; + +@end + + @protocol MLNNativeNetworkDelegate @optional @@ -12,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN - (NSMutableURLRequest *)willSendRequest:(NSMutableURLRequest *)request; -- (void)didReceiveResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *)error; +- (NetworkResponse *)didReceiveResponse:(NetworkResponse *)response; @required diff --git a/platform/ios/app/MBXViewController.mm b/platform/ios/app/MBXViewController.mm index b803bda8b0cd..f344302088ca 100644 --- a/platform/ios/app/MBXViewController.mm +++ b/platform/ios/app/MBXViewController.mm @@ -284,6 +284,7 @@ -(void)addPluginLayers { [self.mapView addPluginLayerType:[PluginLayerExample class]]; [self.mapView addPluginLayerType:[PluginLayerExampleMetalRendering class]]; [self.mapView addPluginProtocolHandler:[PluginProtocolExample class]]; + [self.mapView addStyleFilter:[[StyleFilterExample alloc] init]]; } diff --git a/src/mbgl/plugin/plugin_layer_render.cpp b/src/mbgl/plugin/plugin_layer_render.cpp index 563c896e14a5..1368d5694ecb 100644 --- a/src/mbgl/plugin/plugin_layer_render.cpp +++ b/src/mbgl/plugin/plugin_layer_render.cpp @@ -86,10 +86,10 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis [[maybe_unused]] const RenderTree& renderTree, [[maybe_unused]] UniqueChangeRequestVec& changes) { auto pluginLayer = static_cast(*baseImpl); - + std::vector removedTiles; bool removeAllTiles = ((renderTiles == nullptr) || (renderTiles->empty())); - + // Get list of tiles to remove and then remove them for (auto currentCollection : _featureCollectionByTile) { if (removeAllTiles || !hasRenderTile(currentCollection.first)) { @@ -105,16 +105,16 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis _featureCollectionByTile.erase(tileID); } } - + if (renderTiles) { if (!renderTiles->empty()) { auto drawPass = RenderPass::Pass3D; - + // If we're reading feature collections, go through // and notify the plugin of any new feature collections for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); - + const auto* optRenderData = getRenderDataForPass(tile, drawPass); if (!optRenderData || !optRenderData->bucket || !optRenderData->bucket->hasData()) { removeTile(drawPass, tileID); @@ -126,14 +126,14 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis if (featureCollection == nullptr) { continue; } - + // See if we already have this tile's feature collection if (_featureCollectionByTile.contains(tileID)) { continue; } - + _featureCollectionByTile[tileID] = featureCollection; - + // static_cast(*baseImpl); // auto layer = static_cast(*renderData.layerProperties->baseImpl); @@ -145,38 +145,40 @@ void RenderPluginLayer::update([[maybe_unused]] gfx::ShaderRegistry& shaderRegis } } } - + // create layer group if (!layerGroup) { if (auto layerGroup_ = context.createLayerGroup(layerIndex, /*initialCapacity=*/1, getID())) { setLayerGroup(std::move(layerGroup_), changes); } } - + auto* localLayerGroup = static_cast(layerGroup.get()); - + // TODO: Implement this bool hostChanged = false; - + // create drawable - if (localLayerGroup->getDrawableCount() == 0 || hostChanged) { - localLayerGroup->clearDrawables(); - - // create tweaker - auto tweaker = std::make_shared(this); - - // create empty drawable using a builder - std::unique_ptr builder = context.createDrawableBuilder(getID()); - auto& drawable = builder->getCurrentDrawable(true); - drawable->setIsCustom(true); - drawable->setRenderPass(RenderPass::Translucent); - - // assign tweaker to drawable - drawable->addTweaker(tweaker); - - // add drawable to layer group - localLayerGroup->addDrawable(std::move(drawable)); - ++stats.drawablesAdded; + if (pluginLayer.getTypeInfo()->source != mbgl::style::LayerTypeInfo::Source::Required) { + if (localLayerGroup->getDrawableCount() == 0 || hostChanged) { + localLayerGroup->clearDrawables(); + + // create tweaker + auto tweaker = std::make_shared(this); + + // create empty drawable using a builder + std::unique_ptr builder = context.createDrawableBuilder(getID()); + auto& drawable = builder->getCurrentDrawable(true); + drawable->setIsCustom(true); + drawable->setRenderPass(RenderPass::Translucent); + + // assign tweaker to drawable + drawable->addTweaker(tweaker); + + // add drawable to layer group + localLayerGroup->addDrawable(std::move(drawable)); + ++stats.drawablesAdded; + } } }