pedalsim_engine (1.10.5)
Installation
dart pub add pedalsim_engine:1.10.5 --hosted-url=About this package
Dart.Package.PedalsimEngine
Pedalsim's native 3D map engine for Flutter, published as pedalsim_engine on the Platform pub feed. The engine
itself is Packages/Cpp.Package.Pedalsim.Engine; this package carries its prebuilt shared library and the little
platform code Flutter needs to show its frames. It runs on Windows (x64), Android (arm64-v8a, armeabi-v7a,
x86_64) and the web.
Using it
PedalsimEngineView(
packPath: pack.path,
tier: EngineTier.high,
onOpened: (engine) => engine
..camera(const EngineCamera(zoom: 16.6, pitchDegrees: 60))
..clock(DateTime.now()),
onReady: (engine) => print('route is ${engine.routeLength} m'),
onFailed: (reason) => print(reason),
)
The view opens the engine at its first layout, keeps the engine's size in step with its own, and closes it when it
is disposed. While it is open, send the ride as often as the app has it (ride(metres, speed); the engine extrapolates
between updates at 60 fps), the camera (camera: zoom and pitch as MapLibre means them, a compass bearing or null to
follow the road), the clock (clock, which places the sun), weather, atmosphere (fog, lightning and lying snow, each 0 to 1) and options (labels, street lines, traffic,
birds, animals). PedalsimEngine.open and the same calls work without the view for an app that lays out the
Texture itself.
photo() freezes the frame, re-renders it offscreen at up to 3840 px with the engine's still settings that can change
while it runs, and saves the JPEG to the device's photos; it resolves to false when nothing was saved. The view stays on
the last frame for the few seconds it takes (the engine settles streaming and 150 frames of temporal antialiasing).
orbit adds the rider's own camera offset (drag, wheel, pinch) on top of the app's camera with a quick follow, and
riders draws the rider's dot and other riders' dots over everything. direction(reverse: true) rides the route
backwards (lane, ribbon and camera flip). For dots, badges or anything else the app draws over the view, project maps
latitude and longitude to logical pixels in the view and riderScreen gives the rider's own point, both from the last
drawn frame (null before the first frame or behind the camera).
Without a pack, give the view stream: (latitude:, longitude:) and sources: a function that fetches the tile each
request names (terrarium elevation PNG, imagery JPEG, basemap vector tile) and returns its bytes, or null when there is
none. Send the route around the rider with route and ride in metres from its first point.
Only one engine renders at a time: the engine's GPU layer (sokol_gfx) is global to the process. A second open while
one is attached fails with start_failed.
How it works
The engine library owns its GPU device, its render thread and every texture it draws with. Dart calls it directly
over dart:ffi (lib/src/bindings.dart, mirroring native/include/pedalsim_engine/c_api.h). Flutter only receives
the finished frame, so it can draw the app's widgets on top:
- Windows: the plugin (
windows/pedalsim_engine_plugin.cpp) registers a GPU surface texture. The engine renders into one of three shared D3D11 textures and publishes it only after the GPU has finished; the texture callback hands Flutter the latest one's shared handle. No copy. - Web:
lib/src/engine_web.dartloadsnative/web/pedalsim_engine.jsand its wasm (bundled for web builds only), fetches the pack frompackPathas a URL, and gives the engine its own canvas in anHtmlElementView; the calls go to the module's exports over JS interop. The web module has no threads, so the app needs no cross-origin isolation headers. UseEngineTier.lowthere for now: High trips an ANGLE shader compile failure on Chrome and Edge on Windows. - Android: the plugin (
PedalsimEnginePlugin.kt) creates aSurfaceProducerand hands itsSurfaceto the engine over JNI; the engine renders into it with EGL and OpenGL ES 3. A resize that brings a new Surface moves the engine to it without reloading. When Android takes the Surface away, the engine releases its GPU state and reloads the pack once the Surface is back.
Updating the engine
The binaries in native/ are build output of the engine repository, never edited here:
py -3 ../Cpp.Package.Pedalsim.Engine/tool/build_binaries.py native
native/ENGINE_COMMIT records the engine commit they came from; commit the engine first so it carries no -dirty.
A change to c_api.h needs the matching change in lib/src/bindings.dart and the web module's export list: a new
minor version for added functions, a new major one for a changed or removed function.
A release is Version.txt plus a matching CHANGELOG.md entry, pushed to main: CI publishes the version in
Version.txt (not the changelog's, nor pubspec.yaml's 0.0.0) and skips it quietly when that version is already on
the feed, so a push that forgets Version.txt builds green and publishes nothing.