From d046be5e522de9f8a02c5133d0ac1c8ff12ce949 Mon Sep 17 00:00:00 2001 From: OpenAI Codex Date: Sat, 29 Aug 2026 12:55:54 +0800 Subject: [PATCH] test: add core particle render layer validation --- CMakeLists.txt | 7 + bazel/core.bzl | 7 + .../30_01_CoreRenderLayer接入验证指令书_v1.md | 731 ++++++++++++++++++ ...01_CoreRenderLayer接入最小技术验证报告_v1.md | 193 +++++ ..._CoreRenderLayer接入验证_Codex完成报告_v1.md | 141 ++++ .../particle_validation_layer_factory.hpp | 16 + .../layers/particle_validation_layer.hpp | 32 + .../src/cpp/style/layers/layer_manager.cpp | 3 + .../src/main/AndroidManifest.xml | 12 + .../ParticleCoreLayerValidationActivity.kt | 93 +++ ...ctivity_particle_core_layer_validation.xml | 48 ++ .../src/main/res/values/descriptions.xml | 1 + .../src/main/res/values/strings.xml | 4 + .../src/main/res/values/titles.xml | 1 + .../src/mbgl/layermanager/layer_manager.cpp | 3 + .../particle_validation_layer_factory.cpp | 25 + .../render_particle_validation_layer.cpp | 132 ++++ .../render_particle_validation_layer.hpp | 30 + src/mbgl/renderer/render_layer.hpp | 3 + src/mbgl/renderer/render_orchestrator.cpp | 2 +- .../layers/particle_validation_layer.cpp | 110 +++ .../layers/particle_validation_layer_impl.hpp | 36 + 粒子开发记录.md | 11 + 23 files changed, 1640 insertions(+), 1 deletion(-) create mode 100644 docs/40_任务/30_01_CoreRenderLayer接入验证指令书_v1.md create mode 100644 docs/60_测试/30_01_CoreRenderLayer接入最小技术验证报告_v1.md create mode 100644 docs/报告/30_01_CoreRenderLayer接入验证_Codex完成报告_v1.md create mode 100644 include/mbgl/layermanager/particle_validation_layer_factory.hpp create mode 100644 include/mbgl/style/layers/particle_validation_layer.hpp create mode 100644 platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/particle/ParticleCoreLayerValidationActivity.kt create mode 100644 platform/android/MapLibreAndroidTestApp/src/main/res/layout/activity_particle_core_layer_validation.xml create mode 100644 src/mbgl/layermanager/particle_validation_layer_factory.cpp create mode 100644 src/mbgl/renderer/layers/render_particle_validation_layer.cpp create mode 100644 src/mbgl/renderer/layers/render_particle_validation_layer.hpp create mode 100644 src/mbgl/style/layers/particle_validation_layer.cpp create mode 100644 src/mbgl/style/layers/particle_validation_layer_impl.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a940a55d8..26ab14508 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -246,6 +246,7 @@ list(APPEND INCLUDE_FILES ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/types.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/vertex_buffer.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/layermanager/background_layer_factory.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/layermanager/particle_validation_layer_factory.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/layermanager/circle_layer_factory.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/layermanager/custom_layer_factory.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/layermanager/fill_extrusion_layer_factory.hpp @@ -357,6 +358,7 @@ list(APPEND INCLUDE_FILES ${PROJECT_SOURCE_DIR}/include/mbgl/style/layer_properties.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/layer.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/layers/background_layer.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/style/layers/particle_validation_layer.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/layers/circle_layer.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/layers/custom_layer_host.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/layers/custom_layer_init_parameters.hpp @@ -501,6 +503,7 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/upload_pass.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/vertex_vector.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/background_layer_factory.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/particle_validation_layer_factory.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/circle_layer_factory.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/fill_extrusion_layer_factory.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/fill_layer_factory.cpp @@ -578,6 +581,8 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/image_manager_observer.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_background_layer.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_background_layer.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_particle_validation_layer.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_particle_validation_layer.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_circle_layer.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_circle_layer.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -747,6 +752,8 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/style/layer_impl.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/layer_observer.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/background_layer.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/particle_validation_layer.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/particle_validation_layer_impl.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/background_layer_impl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/background_layer_impl.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/layers/background_layer_properties.cpp diff --git a/bazel/core.bzl b/bazel/core.bzl index bbbc4b7a9..198ba465d 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -64,6 +64,7 @@ MLN_GENERATED_STYLE_SOURCE = [ "src/mbgl/style/layers/color_relief_layer.cpp", "src/mbgl/style/layers/background_layer_properties.cpp", "src/mbgl/style/layers/background_layer.cpp", + "src/mbgl/style/layers/particle_validation_layer.cpp", "src/mbgl/style/layers/location_indicator_layer_properties.cpp", "src/mbgl/style/layers/location_indicator_layer.cpp", "src/mbgl/style/light.cpp", @@ -162,6 +163,7 @@ MLN_CORE_SOURCE = [ "src/mbgl/gfx/upload_pass.hpp", "src/mbgl/gfx/vertex_vector.hpp", "src/mbgl/layermanager/background_layer_factory.cpp", + "src/mbgl/layermanager/particle_validation_layer_factory.cpp", "src/mbgl/layermanager/circle_layer_factory.cpp", "src/mbgl/layermanager/custom_layer_factory.cpp", "src/mbgl/layermanager/fill_extrusion_layer_factory.cpp", @@ -233,6 +235,8 @@ MLN_CORE_SOURCE = [ "src/mbgl/renderer/image_manager_observer.hpp", "src/mbgl/renderer/layers/render_background_layer.cpp", "src/mbgl/renderer/layers/render_background_layer.hpp", + "src/mbgl/renderer/layers/render_particle_validation_layer.cpp", + "src/mbgl/renderer/layers/render_particle_validation_layer.hpp", "src/mbgl/renderer/layers/render_circle_layer.cpp", "src/mbgl/renderer/layers/render_circle_layer.hpp", "src/mbgl/renderer/layers/render_custom_layer.cpp", @@ -406,6 +410,7 @@ MLN_CORE_SOURCE = [ "src/mbgl/style/layer_observer.hpp", "src/mbgl/style/layers/background_layer_impl.cpp", "src/mbgl/style/layers/background_layer_impl.hpp", + "src/mbgl/style/layers/particle_validation_layer_impl.hpp", "src/mbgl/style/layers/circle_layer_impl.cpp", "src/mbgl/style/layers/circle_layer_impl.hpp", "src/mbgl/style/layers/custom_layer.cpp", @@ -660,6 +665,7 @@ MLN_CORE_HEADERS = [ "include/mbgl/i18n/collator.hpp", "include/mbgl/i18n/number_format.hpp", "include/mbgl/layermanager/background_layer_factory.hpp", + "include/mbgl/layermanager/particle_validation_layer_factory.hpp", "include/mbgl/layermanager/circle_layer_factory.hpp", "include/mbgl/layermanager/custom_layer_factory.hpp", "include/mbgl/layermanager/fill_extrusion_layer_factory.hpp", @@ -673,6 +679,7 @@ MLN_CORE_HEADERS = [ "include/mbgl/layermanager/location_indicator_layer_factory.hpp", "include/mbgl/layermanager/raster_layer_factory.hpp", "include/mbgl/layermanager/symbol_layer_factory.hpp", + "include/mbgl/style/layers/particle_validation_layer.hpp", "include/mbgl/map/bound_options.hpp", "include/mbgl/map/camera.hpp", "include/mbgl/map/change.hpp", diff --git a/docs/40_任务/30_01_CoreRenderLayer接入验证指令书_v1.md b/docs/40_任务/30_01_CoreRenderLayer接入验证指令书_v1.md new file mode 100644 index 000000000..9d590d13a --- /dev/null +++ b/docs/40_任务/30_01_CoreRenderLayer接入验证指令书_v1.md @@ -0,0 +1,731 @@ +# MapLibreParticleLab 30_最小技术验证-01_Core RenderLayer 接入验证指令书 v1 + +## 1. 任务基本信息 + +- 项目:MapLibreParticleLab +- 阶段:`30_最小技术验证` +- 子任务:`30-01 Core RenderLayer 接入验证` +- 当前主线:`particle/main` +- 前置阶段: + - `10_架构调查` 已完成 + - `20_架构设计` 已完成 +- 前置正式架构文档: + - `docs/10_架构/20_粒子系统总体架构设计_v1.md` +- 任务性质:最小运行时技术验证 +- 本任务不是正式粒子功能实现 +- 本任务允许最少量验证代码,但必须保持隔离、可识别、可移除 +- 不允许顺手重构 MapLibre +- 不允许扩大到 GPU 粒子、真实场数据、Trail 或 Land/Ocean Mask 实现 + +--- + +## 2. 为什么本阶段先只做 30-01 + +当前总体架构已经选择独立 Core 粒子 Layer 作为正式主路线。 + +本阶段后续原计划还需要验证: + +1. Core RenderLayer / Style order / 同帧 transform / repaint +2. GPU State A/B + Trail A/B ping-pong 与 context recreation +3. Camera / world wrap / Land-Ocean Mask +4. iOS Core Layer 薄接入 + +但第 1 项属于前置门槛。 + +如果第 1 项失败,说明当前正式主路线可能需要调整,后续 GPU、Mask 和平台验证的代码位置、生命周期和验证方式都会变化。 + +因此本任务只完成 `30-01`。 + +只有 `30-01` 得出 PASS 后,才进入下一项。 + +不得提前为后续验证大量写代码。 + +--- + +## 3. 必须先读取 + +Codex 开始前必须完整读取: + +1. 根目录 `AGENTS.md` +2. `PARTICLE_BASELINE.md` +3. `docs/00_项目总则/` 下当前全部有效文档 +4. `docs/00_项目规范/` 下当前全部有效文档 +5. `docs/20_调查/10_架构调查报告_v1.md` +6. `docs/10_架构/20_粒子系统总体架构设计_v1.md` +7. `docs/报告/10_架构调查_Codex完成报告_v1.md` +8. `docs/报告/20_架构设计_Codex完成报告_v1.md` +9. `粒子开发记录.md` +10. 与下列现有实现直接相关的当前源码: + - Style Layer 注册链 + - RenderLayer / RenderTree / RenderOrchestrator + - RasterLayer 或其他最接近的现有 Layer 示例 + - CustomLayer / CustomDrawableLayer 示例 + - Android MapRenderer / AndroidRendererFrontend + - `triggerRepaint` / `requestRender` + - `TransformState` / `TransformParameters` / `PaintParameters` + +不得凭记忆或 MapLibre 通用知识直接开写。 + +--- + +## 4. 开始前 Git 检查 + +先执行只读检查并记录: + +- 当前分支 +- 当前 HEAD +- `git status` +- `origin` / 当前公开远端 +- `particle/main` 是否与远端同步 + +如果存在与本任务无关的本地修改: + +- 不得删除 +- 不得覆盖 +- 不得顺带提交 +- 在完成报告中记录 +- 本任务提交时只 stage 本任务相关文件 + +如果当前不是 `particle/main`,不要擅自切换覆盖用户工作。 + +先明确报告实际状态。 + +--- + +## 5. 验证目标 + +本任务只回答下面四个问题。 + +### V1. 独立 Core Layer 能否进入真实 MapLibre Style / RenderTree 顺序 + +必须验证一个最小实验 Layer: + +- 由 Core Style/Layer 系统识别 +- 能生成对应 RenderLayer +- 能进入真实 RenderTree +- 能按 Style Layer 顺序参与渲染 +- 不依赖 MapView 外部 Overlay +- 不依赖 JS/RN 每帧逻辑 +- 不把实现塞进现有 RasterLayer + +### V2. 该 Layer 能否在同一 MapLibre render frame 获得当前 Transform + +至少验证能够在真正绘制路径中读取或使用: + +- viewport size +- zoom +- bearing +- pitch +- projection / transform matrix 中架构要求的必要部分 + +验证重点不是把数值打印出来,而是确认这些值来自: + +> 当前 MapLibre render frame 的真实 `PaintParameters / TransformParameters / TransformState` 链 + +而不是另建独立 Camera 状态。 + +### V3. Layer 活动时能否驱动持续 repaint + +验证: + +- Layer 处于“动画活动”状态时,可以通过 MapLibre 自己的 render loop 持续获得下一帧 +- 不建立独立于 MapLibre 的第二套动画循环 +- 不依赖 Android UI Timer +- 不依赖 JS `requestAnimationFrame` + +### V4. Layer 停止活动后能否停止额外 repaint + +验证: + +- Layer 切换为静止/disabled 后,不继续无意义请求下一帧 +- 地图自身正常 pan/zoom/render 不受影响 +- 不产生永久 continuous rendering + +--- + +## 6. 本任务不是粒子实现 + +验证代码只能证明架构入口成立。 + +禁止在本任务实现: + +- 速度场 +- U/V Grid +- Field decode +- particle position +- age +- seed +- advection +- velocity texture +- particle state texture +- ping-pong +- Trail +- fade pass +- Land/Ocean Mask +- Wave/Tide/Current +- Wind fixture +- 真正 Particle Shader +- compute shader + +如需要视觉确认,只允许使用最简单的验证图元或调试绘制。 + +例如: + +- 单色矩形 +- 三角形 +- 简单全屏/局部 quad +- 简单随帧变化的 alpha / position + +不得把验证图元包装成“粒子初版”。 + +--- + +## 7. 验证代码命名 + +验证代码必须明确表明其临时技术验证属性。 + +优先使用: + +`ParticleValidation*` + +或: + +`RasterParticleValidation*` + +不要直接把不成熟的验证代码命名成最终生产类并假装已经冻结。 + +如果必须使用正式架构类名才能验证注册链,例如: + +- `RasterParticleLayer` +- `RenderRasterParticleLayer` + +则必须: + +1. 只实现验证所需最小骨架; +2. 在代码和文档中明确 `VALIDATION ONLY`; +3. 不提前加入未来未验证业务接口; +4. 不把临时调试字段伪装成正式公共 API。 + +--- + +## 8. 最小实现范围 + +Codex 应先调查当前最小实现需要触及哪些文件。 + +原则: + +> 能用 5 个文件解决,不要改 15 个文件。 + +预计可能涉及,但不得机械照搬: + +- Core style layer 声明 +- Core style layer 实现 +- 对应 RenderLayer +- LayerManager / 注册位置 +- Android Test App 或现有测试入口 +- 最小验证日志/状态 + +最终以当前真实代码为准。 + +不得为了“以后可能用到”提前创建整套 particle 目录树。 + +--- + +## 9. Style / RenderTree 验证要求 + +必须证明实验 Layer 是通过正式 MapLibre Layer 链进入渲染。 + +验证报告至少记录实际链: + +```text +Style Layer +→ LayerManager / RenderLayer creation +→ RenderTree / RenderOrchestrator +→ 对应 RenderLayer +→ Render pass +``` + +必须指出: + +- 实际插入哪个 pass +- 与前后普通 Style Layer 的 order 是否正确 +- 是否需要 tile/source +- 当前验证 Layer 是否 source-less +- 如果 source-less 不可行,实际最小 Source 依赖是什么 + +不能只通过 CustomLayer 示例证明。 + +本任务要验证的是总体架构选择的“独立 Core Layer 路线”。 + +--- + +## 10. 同帧 Camera / Matrix 验证 + +验证代码必须从当前 render path 内取得 transform。 + +至少记录: + +- 获取位置 +- 对应源码对象 +- 生命周期 +- 是否每 frame 更新 +- 是否与当前 RenderTree frame 同步 + +至少验证以下地图变化不会让实验 Layer 明显脱离地图: + +- pan +- zoom +- bearing +- pitch +- resize + +本任务不要求完成 world wrap / antimeridian 专项验证。 + +这些留给后续 Mask/Camera 技术验证。 + +--- + +## 11. Repaint 验证 + +实验 Layer 必须提供最小“活动/停止”活动模型。 + +例如内部验证状态: + +```text +ACTIVE +STATIC +``` + +### ACTIVE + +必须证明: + +- 当前 frame 完成后仍会请求 MapLibre 下一帧 +- 连续帧来自 MapLibre render/repaint 链 +- 能观察到 frame counter 持续增长 + +### STATIC + +必须证明: + +- 不再由该 Layer 主动触发下一帧 +- 地图静止时 frame counter 不继续无意义增长 +- 用户操作地图时仍能正常重新绘制 + +不得使用平台 Timer 模拟。 + +--- + +## 12. 日志要求 + +验证期间允许增加最少量调试日志。 + +日志至少能识别: + +- Layer create +- RenderLayer create +- first render +- frame counter +- current active/static +- repaint request +- relevant transform snapshot +- destroy/deinitialize + +禁止每帧输出大量完整 matrix 导致日志爆炸。 + +建议: + +- 首帧输出一次完整关键参数 +- 后续每 N 帧输出 frame counter +- 状态变化时输出 +- 销毁时输出 + +验证完成后是否保留日志,由报告明确说明。 + +--- + +## 13. Android 第一验证平台 + +本任务第一运行平台固定为: + +**Android OpenGL** + +原因: + +- 当前架构设计将它作为第一共同验证入口; +- 本任务只验证 Core Layer + 同帧 transform + repaint; +- 不在本任务同时扩大到 Vulkan / iOS。 + +Vulkan 和 iOS 留到后续对应验证。 + +--- + +## 14. Android 编译规则:必须由用户手工执行 + +本项目 Android 编译必须由用户手工执行。 + +Codex 禁止运行: + +- Gradle Android build +- `./gradlew assemble...` +- `./gradlew install...` +- Android npm build +- 任何等价 Android 编译命令 + +Codex 可以: + +- 检查现有 Gradle 配置 +- 准备代码 +- 给出用户应执行的准确编译命令 +- 分析用户返回的编译错误 +- 在允许范围内修正本任务代码 + +Codex 不得代替用户执行 Android 编译。 + +--- + +## 15. 运行/设备验证规则 + +本任务不得默认替用户执行: + +- ADB 安装 +- ADB 启动 +- ADB 日志抓取 +- 真机操作 + +除非用户在后续明确授权。 + +因此第一轮 Codex 工作完成后,应输出: + +1. 用户手工编译命令 +2. 应打开的 Test App / 页面 / Activity +3. 需要执行的地图操作 +4. 需要观察的日志 +5. PASS/FAIL 判定方法 + +用户提供编译/运行结果后,再完成最终技术验证结论。 + +--- + +## 16. 两阶段执行方式 + +本任务允许同一份指令书分两次 Codex 执行。 + +### 阶段 A:验证代码准备 + +Codex: + +1. 读取基线 +2. 写最小验证代码 +3. 做静态检查 +4. 生成暂定验证报告 +5. 给出用户手工编译/运行步骤 +6. commit + push 到 `particle/main` + +此时报告结论必须写: + +`WAITING_MANUAL_VALIDATION` + +不得写 PASS。 + +### 阶段 B:用户返回实际编译/运行结果后 + +Codex: + +1. 读取用户提供的编译结果、日志和现象 +2. 如果失败,只修复本验证范围内问题 +3. 如果架构假设本身失败,停止,不强行修成另一套架构 +4. 更新正式验证报告 +5. 更新 Codex 完成报告 +6. 更新 `粒子开发记录.md` +7. commit + push 到 `particle/main` + +最终只能是: + +- `PASS` +- `FAIL` +- `BLOCKED` + +--- + +## 17. PASS 标准 + +只有同时满足以下条件,`30-01` 才能 PASS: + +- [ ] 独立 Core Style Layer 被正式识别 +- [ ] 对应 RenderLayer 被创建 +- [ ] 真正进入 RenderTree / Render pass +- [ ] Layer order 正确 +- [ ] 从当前 render frame 获得必要 Transform +- [ ] pan 正常 +- [ ] zoom 正常 +- [ ] bearing 正常 +- [ ] pitch 正常 +- [ ] resize 正常 +- [ ] ACTIVE 时由 MapLibre render loop 持续 repaint +- [ ] STATIC 时停止该 Layer 的额外 repaint +- [ ] 地图普通渲染不受破坏 +- [ ] 未使用外部 Overlay +- [ ] 未建立平台 Timer 动画循环 +- [ ] 未实现超出本任务范围的粒子系统 + +任何一项关键门槛失败,不得标 PASS。 + +--- + +## 18. FAIL 与停止条件 + +出现以下任一情况时,应停止继续向后实现: + +### F1 + +独立 Core Layer 无法在不破坏 MapLibre 现有主架构的情况下进入真实 RenderTree。 + +### F2 + +无法从该 Layer 的真实 render frame 获得足够 transform。 + +### F3 + +必须依赖外部 Overlay 或独立动画 loop 才能工作。 + +### F4 + +持续 repaint 必须通过明显侵入 Map 主循环才能实现。 + +### F5 + +验证要求迫使 Android/iOS 分别拥有不同 particle engine。 + +若触发 F1-F5: + +- 停止 +- 不继续 GPU ping-pong +- 不继续 Mask +- 不继续 iOS 实现 +- 报告失败事实 +- 回到架构设计重新决策 + +不得为了让验证“通过”扩大修改范围。 + +--- + +## 19. 禁止事项 + +本任务禁止: + +- 正式实现 Particle Field +- 正式实现 RasterArraySource 数据链 +- 正式实现 GPU Simulation +- 正式实现 Trail +- 正式实现 Mask +- 接真实天气数据 +- 引入新第三方依赖 +- 升级 MapLibre +- 升级 Android SDK / NDK / Gradle +- 修改无关 Layer +- 重构 Renderer +- 重构 Map +- 修改 iOS 代码 +- 实现 Vulkan 版本 +- 建立 RN/JS bridge +- 新增产品 API +- 清理与本任务无关的旧代码 + +--- + +## 20. 文档输出 + +### 20.1 技术验证报告 + +生成: + +`docs/60_测试/30_01_CoreRenderLayer接入最小技术验证报告_v1.md` + +如果同主题已有文件,按版本递增,不覆盖旧文件。 + +报告必须区分: + +- 静态确认 +- 用户手工编译结果 +- 用户运行结果 +- 实际日志证据 +- 推论 + +没有用户运行结果时,只能写: + +`WAITING_MANUAL_VALIDATION` + +### 20.2 Codex 完成报告 + +生成: + +`docs/报告/30_01_CoreRenderLayer接入验证_Codex完成报告_v1.md` + +同主题已有报告时递增版本号。 + +### 20.3 开发记录 + +追加: + +`粒子开发记录.md` + +不得覆盖历史内容。 + +--- + +## 21. 不主动创建 Step + +本任务不主动创建或修改 `docs/50_Step记录/`。 + +只有用户明确要求时才创建 Step。 + +--- + +## 22. Git 收尾规则 + +本任务凡产生文件修改,都必须提交并 push。 + +目标: + +- 本地主线:`particle/main` +- 公开远端对应分支:`particle/main` + +### 22.1 提交范围 + +只允许提交: + +- 本任务验证代码 +- 本任务验证文档 +- 本任务完成报告 +- 本任务对 `粒子开发记录.md` 的追加 + +不得把与本任务无关的本地修改一起提交。 + +### 22.2 阶段 A + +验证代码准备完成后: + +1. 检查 `git diff` +2. 明确列出本任务文件 +3. commit +4. push 到公开 `particle/main` +5. 确认远端可见 + +推荐提交信息: + +`test: add core particle render layer validation` + +### 22.3 阶段 B + +用户手工验证结果回填后: + +1. 更新验证报告 +2. 更新完成报告 +3. 更新开发记录 +4. 如有必要修复最小验证代码 +5. commit +6. push 到公开 `particle/main` + +推荐提交信息: + +`test: finalize core particle render layer validation` + +### 22.4 Push 失败 + +如果 push 失败: + +- 不得声称任务完整完成 +- 完成报告必须写明: + - push 失败 + - 错误原因 + - 本地 commit hash + - 目标远端 + - 目标分支 + +--- + +## 23. Git 信息记录 + +Codex 完成报告必须记录: + +- 任务开始 HEAD +- 本次主要变更 commit hash +- commit message +- push 是否成功 +- 公开远端 +- 远端分支 +- push 后远端可见状态 +- 是否存在未提交的无关本地改动 + +为避免“提交文件记录自己的 commit hash”产生自引用问题: + +- 完成报告中的 `主要变更 commit hash` 记录包含验证代码和主要文档的实质性提交; +- 如果随后还有仅用于回填报告元数据的收尾提交,Codex 最终回复中必须另外报告最终远端 HEAD; +- 不得为了回填当前提交自己的 hash 无限 amend。 + +--- + +## 24. Codex 完成报告必须逐项说明 + +至少包括: + +1. 前置文档读取 +2. 当前 Git 基线 +3. 实际修改文件 +4. Style Layer 接入位置 +5. RenderLayer 创建链 +6. RenderTree / pass +7. Transform 获取链 +8. Repaint 链 +9. Android OpenGL 验证入口 +10. 用户手工编译命令 +11. 用户手工运行步骤 +12. 当前状态: + - WAITING_MANUAL_VALIDATION + - PASS + - FAIL + - BLOCKED +13. 是否修改生产代码 +14. 是否扩大架构范围 +15. 是否安装/升级依赖 +16. Git commit +17. push 结果 +18. 是否可以进入下一个最小技术验证 + +--- + +## 25. 进入下一验证的条件 + +只有最终结果: + +`PASS` + +才允许进入下一个技术验证。 + +下一项预计验证: + +> GPU State A/B + Trail A/B 的 gfx ping-pong、RenderTarget、同步/barrier 与 context recreation。 + +如果本任务是: + +- FAIL +- BLOCKED + +则不得提前执行下一项。 + +必须先回到架构层决定如何处理。 + +--- + +## 26. 本任务完成定义 + +`30-01` 真正完成必须满足: + +> 用户手工 Android OpenGL 编译和运行后,已经通过实际运行证据确认:独立 Core Layer 可以进入 MapLibre 正式 Style/RenderTree 渲染链,在同一 render frame 使用 MapLibre 当前 Transform,并通过 MapLibre 自己的 repaint 机制在活动时持续渲染、停止时停止额外帧。 + +只有静态代码完成、没有实际运行结果,不叫验证完成。 + +只能标记: + +`WAITING_MANUAL_VALIDATION` diff --git a/docs/60_测试/30_01_CoreRenderLayer接入最小技术验证报告_v1.md b/docs/60_测试/30_01_CoreRenderLayer接入最小技术验证报告_v1.md new file mode 100644 index 000000000..d72806b1e --- /dev/null +++ b/docs/60_测试/30_01_CoreRenderLayer接入最小技术验证报告_v1.md @@ -0,0 +1,193 @@ +# 30-01 Core RenderLayer 接入最小技术验证报告 v1 + +日期:2026-08-29 + +当前状态:`WAITING_MANUAL_VALIDATION` + +本报告只记录阶段 A 的代码准备与静态证据。Android OpenGL 编译、安装、运行、手势和日志结果尚未由用户回填,因此不得标记 PASS。 + +## 1. 验证范围 + +本验证只回答:独立 Core Style Layer/RenderLayer 是否能进入正式 RenderTree 顺序、读取同帧 transform、在 ACTIVE 时通过 MapLibre 自身 loop 请求下一帧,并在 STATIC 时停止额外 repaint。 + +未实现速度场、粒子状态、advection、GPU ping-pong、Trail、Mask、真实天气数据或 compute shader。 + +## 2. 最小验证实现 + +- Style type:`particle-validation`。 +- Style class:`style::ParticleValidationLayer`,明确标记 `VALIDATION ONLY`。 +- Render class:`RenderParticleValidationLayer`。 +- Source:不要求 source;`LayerTypeInfo::Source::NotRequired`。 +- Pass:`RenderPass::Translucent`。 +- 状态:style paint 字段 `particle-validation-active=true/false`,只用于本验证。 +- Drawable:一个不输出像素的验证 Drawable,用于进入真实 LayerGroup/pass 顺序并在 drawable tweaker 中取得当前 `PaintParameters`;不使用 `CustomLayerHost`,不构成外部 CustomLayer 路线。 +- Android API:没有新增 Java/JNI 产品 API;Android 只把该类型注册为 JSON style 可用的 core-only layer。 + +## 3. Style / RenderTree / pass 静态确认 + +实际链路为: + +```text +Android Test App inline Style JSON +→ style::conversion::Converter> +→ LayerManagerAndroid::getFactory("particle-validation") +→ ParticleValidationLayerFactory::createLayer +→ style::ParticleValidationLayer immutable Impl +→ RenderOrchestrator layer diff/order +→ LayerManagerAndroid::createRenderLayer +→ ParticleValidationLayerFactory::createRenderLayer +→ RenderParticleValidationLayer +→ source-less LayerRenderItem +→ RenderParticleValidationLayer::update +→ source-less LayerGroup(layerIndex) +→ validation Drawable(RenderPass::Translucent) +→ main translucent pass 的 LayerGroup 顺序 +``` + +Test App style 顺序固定为: + +```text +validation-background +→ validation-below(蓝色大圆) +→ particle-validation-core +→ validation-above(黄色小圆) +``` + +验证 Drawable 的 `layerIndex` 由 RenderOrchestrator 正式 style order 分配,LayerGroup 以同一 index 注册。运行日志同时记录 `layerIndex` 和 pass 内的 `currentLayer`。实际 Android 顺序仍需用户运行日志确认。 + +## 4. 同帧 Transform 静态确认 + +验证日志在 DrawableTweaker 的 `execute(gfx::Drawable&, PaintParameters&)` 中生成。该回调发生在 MapLibre main translucent pass 对应 LayerGroup/Drawable 的真实执行路径中,直接读取: + +- `PaintParameters::state.getSize()`:viewport; +- `PaintParameters::state.getZoom()`:zoom; +- `PaintParameters::state.getBearing()`:bearing; +- `PaintParameters::state.getPitch()`:pitch; +- `PaintParameters::transformParams.projMatrix`:当前 frame projection matrix 摘要; +- `PaintParameters::frameCount`:MapLibre frame number。 + +未创建独立 Camera 状态,未从 Android UI 层复制或推算 transform。 + +## 5. Repaint 链静态确认 + +本任务增加一个薄 Core hook: + +```text +RenderParticleValidationLayer::needsRepaint() +→ RenderOrchestrator::hasTransitions() 汇总 +→ RenderTreeParameters::needsRepaint +→ RendererObserver::onDidFinishRenderingFrame(needsRepaint) +→ Map::Impl::onDidFinishRenderingFrame +→ needsRepaint=true 时 Map::Impl::onUpdate() +→ AndroidRendererFrontend::update() +→ Android MapRenderer.requestRender() +→ 下一 MapLibre render frame +``` + +所有其他 RenderLayer 默认返回 false,因此现有 Layer 行为不变。 + +- ACTIVE:验证 Layer 可见且 active 时返回 true。 +- STATIC:active=false 时返回 false;地图自己的 transition、手势和 source 更新仍可请求 frame。 +- 未使用 Android Timer、Handler 循环、JS `requestAnimationFrame` 或第二套动画 loop。 + +## 6. 日志格式 + +日志关键字统一为 `ParticleValidation`,包括: + +- Style Layer create/destroy; +- RenderLayer create/destroy; +- ACTIVE/STATIC; +- validation Drawable create/destroy; +- 首帧及每 60 帧:frame counter、MapLibre frame、状态、repaint、pass、layer order、viewport、zoom、bearing、pitch、projection matrix 摘要。 + +预期 ACTIVE 样例: + +```text +ParticleValidation: render frame=60 mapFrame=... state=ACTIVE repaint=requested pass=translucent layerIndex=... currentLayer=... viewport=... zoom=... bearing=... pitch=... proj=[...] +``` + +预期 STATIC 样例: + +```text +ParticleValidation: state=STATIC ... +ParticleValidation: render frame=1 ... state=STATIC repaint=stopped ... +``` + +地图静止后不应继续出现该 STATIC 实例的周期性 `frame=60/120/...`。 + +## 7. Codex 已执行检查 + +### 7.1 通过 + +- `git diff --check`:PASS。 +- 新增/修改 C++ 文件 `clang-format`:PASS。 +- Android Manifest、layout、values XML 使用 Python 标准库只读解析:PASS。 +- Android `MapLibreMap.getCameraPosition/setCameraPosition` API 静态确认:PASS。 +- Linux OpenGL CMake 重新配置:PASS。 +- 精确编译以下 Linux Core 对象:PASS: + - `particle_validation_layer_factory.cpp.o` + - `particle_validation_layer.cpp.o` + - `render_particle_validation_layer.cpp.o` + - `render_orchestrator.cpp.o` + - default `layer_manager.cpp.o` + +### 7.2 未完成 + +- Linux OpenGL 全量增量编译:公共 `RenderLayer` 头变化触发 321 个对象重编译;在 `41/321` 无错误时主动停止,随后改为上述任务相关对象精确编译并通过。 +- Android OpenGL Gradle/NDK/Test App 编译:按指令书禁止 Codex 执行,等待用户手工完成。 +- Android 运行、日志、pan/zoom/bearing/pitch/resize、ACTIVE/STATIC:等待用户。 + +## 8. 用户手工编译 + +在项目 Linux 环境执行: + +```bash +cd /mnt/sda1/MapLibreParticleLab +source /root/.maplibre-particle-env +cd platform/android +RENDERER=opengl BUILDTYPE=Debug JOBS=3 make android-x86-64 +``` + +预期 APK: + +```text +platform/android/MapLibreAndroidTestApp/build/outputs/apk/opengl/debug/MapLibreAndroidTestApp-opengl-debug.apk +``` + +若目标设备不是 x86_64,请将 `android-x86-64` 换成对应现有 Make target;不要切换 Vulkan,本任务平台固定 Android OpenGL。 + +## 9. 用户手工运行步骤 + +1. 安装并打开 `MapLibre Native Android TestApp`。 +2. 在 `Custom Layer` 分类打开 `Particle Core Layer Validation`。 +3. 确认页面显示蓝色大圆和其上的黄色小圆,初始状态文字为 ACTIVE。 +4. 过滤日志关键字:`adb logcat | grep ParticleValidation`;也可使用 Android Studio Logcat 搜索同一关键字。 +5. ACTIVE 静置至少 3 秒,确认 `frame=60/120/...` 持续增长。 +6. 分别执行 pan、双指 zoom、rotate、pitch,确认地图正常,并保存变化前后的 transform 日志。 +7. 旋转设备或改变模拟器窗口尺寸,确认 `viewport` 更新且页面正常。 +8. 点击 STATIC,静置至少 3 秒;确认不再周期性增长。 +9. STATIC 下再次 pan/zoom,确认地图仍会按正常地图事件重绘;操作停止后不继续产生验证层额外帧。 +10. 再点 ACTIVE,确认连续帧恢复。 + +## 10. PASS / FAIL 判定 + +### PASS 候选证据 + +- Style Layer、RenderLayer 和 validation Drawable 均创建; +- 日志显示 `pass=translucent` 且 layer order 与 style 顺序一致; +- viewport/zoom/bearing/pitch/projection 摘要随对应操作更新; +- ACTIVE frame counter 持续增长; +- STATIC 静止后停止周期增长,但地图手势仍正常; +- 无崩溃、黑屏、永久 continuous rendering 或普通地图破坏。 + +### FAIL/停止 + +若 layer 无法创建、无法进入 pass、transform 不是同帧、ACTIVE 无法持续、STATIC 无法停止,或必须改用 Overlay/Timer/大改 Map 主循环,则记录 FAIL 并停止后续 GPU/Mask/iOS 验证。 + +## 11. 当前结论 + +静态代码和 Linux 任务相关对象编译支持该路线具备可验证性,但缺少 Android OpenGL 实际编译与运行证据。 + +当前唯一合法结论:`WAITING_MANUAL_VALIDATION`。 + +不得进入下一项 GPU State A/B + Trail A/B 验证。 diff --git a/docs/报告/30_01_CoreRenderLayer接入验证_Codex完成报告_v1.md b/docs/报告/30_01_CoreRenderLayer接入验证_Codex完成报告_v1.md new file mode 100644 index 000000000..e793baa7d --- /dev/null +++ b/docs/报告/30_01_CoreRenderLayer接入验证_Codex完成报告_v1.md @@ -0,0 +1,141 @@ +# 30-01 Core RenderLayer 接入验证 Codex 完成报告 v1 + +日期:2026-08-29 + +任务:`docs/40_任务/30_01_CoreRenderLayer接入验证指令书_v1.md` + +执行阶段:A(验证代码准备) + +当前结论:`WAITING_MANUAL_VALIDATION` + +## 1. 前置文档读取 + +已读取根 `AGENTS.md`、`PARTICLE_BASELINE.md`、`docs/00_项目总则/` 全部当前有效文件、`docs/00_项目规范/` 全部当前有效文件、架构调查报告、总体架构设计、两份前置 Codex 报告、开发记录、当前 STEP-000 和本任务书。已按任务要求调查 Style 注册、RenderLayer/RenderTree/RenderOrchestrator、Background/Raster/Custom 示例、Android renderer/frontend、repaint 和 Transform/Paint 链。 + +## 2. Git 基线 + +- 分支:`particle/main`。 +- 任务开始 HEAD:`74be2a5052428717d7c9e133c333da8bd783b958`。 +- 开始时远端同步:`particle/main...origin/particle/main = 0 0`。 +- 开始时无已跟踪修改;有用户提供的未跟踪当前任务书。 +- submodule:已查询,无本任务修改。 +- 主要变更 commit:阶段 A 实质提交后回填。 +- commit message:`test: add core particle render layer validation`。 +- push:阶段 A 实质提交后回填。 +- 公开远端:`ssh://git@192.168.200.230:2222/tei/MapLibreParticleLab.git`。 +- 远端分支:`particle/main`。 + +## 3. 实际修改文件 + +### Core 验证代码 + +- 新增 `ParticleValidationLayer`、Impl/properties、factory、`RenderParticleValidationLayer`。 +- 修改 Core/default 与 Android LayerManager 注册。 +- 修改 `RenderLayer` 增加默认 false 的 `needsRepaint()`。 +- 修改 `RenderOrchestrator` 汇总 Layer repaint 请求。 +- 修改 CMake/Bazel source lists。 + +### Android Test App + +- 新增 `ParticleCoreLayerValidationActivity` 和 layout。 +- 注册 Manifest。 +- 新增页面标题、说明和 ACTIVE/STATIC 文案。 + +### 文档 + +- 纳入当前正式任务书。 +- 新增技术验证报告和本完成报告。 +- 追加 `粒子开发记录.md`。 +- 未创建或修改 Step。 + +## 4. Style Layer 接入位置 + +JSON type `particle-validation` 经 Android `LayerManagerAndroid` 的 core-only factory 正式解析为 `style::ParticleValidationLayer`。其 `LayerTypeInfo` 为 source-less、无 layout、无 tile kind。它不是 RasterLayer 分支,也不是 MapView 外部 Overlay。 + +## 5. RenderLayer 创建链 + +```text +Style JSON → LayerManagerAndroid → ParticleValidationLayerFactory +→ ParticleValidationLayer immutable Impl +→ RenderOrchestrator layer diff +→ ParticleValidationLayerFactory::createRenderLayer +→ RenderParticleValidationLayer +``` + +## 6. RenderTree / pass + +`RenderParticleValidationLayer` 进入 source-less `LayerRenderItem`,按 style index 创建 source-less LayerGroup,并注册一个无像素输出的 validation Drawable。Drawable 属于 `RenderPass::Translucent`,随正常 LayerGroup order 进入 main translucent pass。Test App 将它固定放在蓝色参考圆与黄色参考圆之间。 + +## 7. Transform 获取链 + +```text +UpdateParameters::TransformState +→ RenderTreeParameters::TransformParameters +→ 当前 frame PaintParameters +→ validation DrawableTweaker::execute +``` + +读取 viewport、zoom、bearing、pitch、projection matrix 摘要和 MapLibre frame count。没有独立 Camera 状态。 + +## 8. Repaint 链 + +ACTIVE 的 `RenderParticleValidationLayer::needsRepaint()` 返回 true,由 RenderOrchestrator 写入 RenderTree `needsRepaint`,再经 RendererObserver、Map::Impl::onDidFinishRenderingFrame/onUpdate 和 AndroidRendererFrontend.requestRender 请求下一 MapLibre frame。STATIC 返回 false。没有 Timer、Handler loop、JS/RN frame loop。 + +## 9. Android OpenGL 验证入口 + +Test App → `Custom Layer` 分类 → `Particle Core Layer Validation`。虽然位于现有 UI 分类中,但实现不是 CustomLayer/CustomLayerHost;分类只用于减少 Test App 导航改动。 + +## 10. 用户手工编译命令 + +```bash +cd /mnt/sda1/MapLibreParticleLab +source /root/.maplibre-particle-env +cd platform/android +RENDERER=opengl BUILDTYPE=Debug JOBS=3 make android-x86-64 +``` + +APK 预期路径:`platform/android/MapLibreAndroidTestApp/build/outputs/apk/opengl/debug/MapLibreAndroidTestApp-opengl-debug.apk`。 + +## 11. 用户手工运行步骤 + +详见技术验证报告第 9 节。核心操作是:打开验证页面;保存 `ParticleValidation` 日志;验证 pan/zoom/rotate/pitch/resize;ACTIVE 静置观察连续 frame;STATIC 静置观察停止;STATIC 下操作地图确认正常重绘。 + +## 12. 构建与检查记录 + +- Android/Gradle/npm/ADB:未执行,遵循任务书禁止项。 +- Linux OpenGL CMake configure:PASS。 +- Linux OpenGL 全量增量:在 `41/321` 无错误时主动停止,原因是公共头变化导致完整 Core 重编译;未宣称全量 PASS。 +- 本任务新增/直接修改的 5 个 Linux Core 对象精确编译:PASS。 +- C++ clang-format、`git diff --check`:PASS。 +- Android XML 标准库解析:PASS。 +- APK/AAR:本轮未生成新产物。 + +## 13. 当前状态 + +`WAITING_MANUAL_VALIDATION`。 + +用户尚未提供 Android OpenGL 编译、运行、手势、resize、ACTIVE/STATIC 和日志证据,不能写 PASS。 + +## 14. 是否修改生产代码 + +是,但只包含验证所需薄接入:新增隔离的 VALIDATION ONLY Core Layer/RenderLayer、注册/build list,以及通用默认 false repaint hook。没有粒子生产功能;没有改 RasterLayer、Map、MapView 主循环或 backend 算法。 + +## 15. 是否扩大架构范围 + +否。未实现 GPU particle、Field、RasterArraySource、Trail、Mask、Vulkan、iOS、RN/JS bridge 或真实数据。 + +## 16. 依赖状态 + +未安装、未升级、未修改任何依赖、lock、SDK、NDK、Gradle、Java、Node 或 MapLibre baseline。 + +## 17. 已知问题与未完成 + +- Android OpenGL 编译和运行待用户。 +- 五项地图变化和 ACTIVE/STATIC 行为待实际证据。 +- 全量 Linux OpenGL 增量未完成;任务相关对象已编译通过。 +- 验证 Drawable故意不输出像素;以 pass/order/transform/repaint 日志为技术证据,蓝/黄参考圆用于确认地图与 style layer context。 +- commit/push 元数据将在提交后回填一次,不循环 amend。 + +## 18. 是否可以进入下一验证 + +否。只有用户证据回填并将本任务最终结论更新为 PASS 后,才能进入 GPU State A/B + Trail A/B 验证。 diff --git a/include/mbgl/layermanager/particle_validation_layer_factory.hpp b/include/mbgl/layermanager/particle_validation_layer_factory.hpp new file mode 100644 index 000000000..9aacfd2a7 --- /dev/null +++ b/include/mbgl/layermanager/particle_validation_layer_factory.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace mbgl { + +// VALIDATION ONLY: factory for the 30-01 Core RenderLayer experiment. +class ParticleValidationLayerFactory final : public LayerFactory { +public: + const style::LayerTypeInfo* getTypeInfo() const noexcept override; + std::unique_ptr createLayer(const std::string&, + const style::conversion::Convertible&) noexcept override; + std::unique_ptr createRenderLayer(Immutable) noexcept override; +}; + +} // namespace mbgl diff --git a/include/mbgl/style/layers/particle_validation_layer.hpp b/include/mbgl/style/layers/particle_validation_layer.hpp new file mode 100644 index 000000000..255aacb70 --- /dev/null +++ b/include/mbgl/style/layers/particle_validation_layer.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +namespace mbgl { +namespace style { + +// VALIDATION ONLY: minimal source-less Core layer for 30-01 architecture validation. +class ParticleValidationLayer final : public Layer { +public: + explicit ParticleValidationLayer(const std::string& layerID); + ~ParticleValidationLayer() override; + + bool isActive() const; + void setActive(bool); + + class Impl; + const Impl& impl() const; + Mutable mutableImpl() const; + +private: + explicit ParticleValidationLayer(Immutable); + + std::optional setPropertyInternal(const std::string&, const conversion::Convertible&) override; + StyleProperty getProperty(const std::string&) const override; + Value serialize() const override; + std::unique_ptr cloneRef(const std::string& id) const override; + Mutable mutableBaseImpl() const override; +}; + +} // namespace style +} // namespace mbgl diff --git a/platform/android/MapLibreAndroid/src/cpp/style/layers/layer_manager.cpp b/platform/android/MapLibreAndroid/src/cpp/style/layers/layer_manager.cpp index 85f39dc11..adb974efd 100644 --- a/platform/android/MapLibreAndroid/src/cpp/style/layers/layer_manager.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/style/layers/layer_manager.cpp @@ -19,12 +19,15 @@ #include "symbol_layer.hpp" #include "fill_extrusion_layer.hpp" #include "location_indicator_layer.hpp" +#include namespace mbgl { namespace android { LayerManagerAndroid::LayerManagerAndroid() { + // VALIDATION ONLY: JSON style access; intentionally no Android product API/JNI peer. + addLayerTypeCoreOnly(std::make_unique()); #if defined(MBGL_LAYER_FILL_DISABLE_RUNTIME) addLayerTypeCoreOnly(std::make_unique()); #elif !defined(MBGL_LAYER_FILL_DISABLE_ALL) diff --git a/platform/android/MapLibreAndroidTestApp/src/main/AndroidManifest.xml b/platform/android/MapLibreAndroidTestApp/src/main/AndroidManifest.xml index 7cdedd553..679d63a6a 100644 --- a/platform/android/MapLibreAndroidTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapLibreAndroidTestApp/src/main/AndroidManifest.xml @@ -286,6 +286,18 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> + + + + + maplibreMap = map + map.cameraPosition = CameraPosition.Builder() + .target(LatLng(0.0, 0.0)) + .zoom(2.0) + .build() + loadValidationStyle(active = true) + } + + findViewById