Skip to content

Releases: WorldWindEarth/WorldWindKotlin

WorldWind Kotlin v2.0.6

Choose a tag to compare

@EMaksymenko EMaksymenko released this 12 Jul 19:10

WorldWind Kotlin 2.0.6

This release rebuilds the real-time visibility stack: cascaded sun shadows and sightline analysis are rewritten on depth-texture pipelines with PCF filtering — moment shadow maps are gone from the engine — with hardware depth-compare samplers on capable GPUs, off-screen shadow casters, alpha-cutout shadows, and hemispheric ambient shading. Alongside: a 3D Tiles texture-upload throttle, a batch of iOS stability fixes, and MVT vector layer-ordering and offline-cache fixes.

🌑 Shadow pipeline rewritten as depth-texture CSM

  • Depth-only cascade maps with tent PCF replace the previous moment-based cascades. Receiver shadow math is camera-relative and caster matrices compose in double precision — raw ECEF float32 quantizes to ~0.5 m and erased street-scale shadow structure. Cascades fit the accumulated scene bounds with sticky hysteresis and a texel-snapped light anchor, so the maps stay bit-stable under camera motion. Casters rasterize double-sided (photogrammetry winding is unreliable), and terrain casters skip 3D-Tile coverage regions so the coarse elevation surface can't blanket photogrammetry in false shadow. ShadowLayer.debugShadowMode adds cascade-band / footprint / map-depth debug views.
  • Off-screen casters keep casting — view-frustum-culled shapes, COLLADA/glTF models, and 3D tiles that intersect the street-scale cascade regions still rasterize into the shadow maps (previously their shadows popped in and out as the camera turned). 3D tiles refine against a coarser screen-space-error budget for shadow-only selection, and all keepalive content skips the color pass. Tunable via ShadowLayer.offscreenCasterCascades (default 2, 0 disables).
  • Alpha-masked casters cast their cutout silhouette — cutout-textured 3D-Tile submeshes (alphaMode MASK) discard transparent fragments in the depth pass instead of casting full-quad slab shadows.
  • Shadows fade across the terminator instead of vanishing in a single frame at sunset; sun elevation is judged against the shaded content's position, so an orbital camera keeps shadows on sunlit terrain viewed across the limb.
  • Casters sunward of a cascade's near plane are pancaked onto it, so a distant mountain toward a low sun still shadows street-scale cascades instead of being clipped out of the depth map.
  • Elevated casters gate per cascade — a single model at altitude no longer inflates every cascade's depth window (which cost depth precision and detached contact shadows scene-wide); only the cascades its light-space footprint overlaps are lifted.
  • Receiver depth bias is now in world metres, normalized per cascade at upload, so bias tuning means the same thing in every scene regardless of depth-window size.
  • Two receiver safeties: tap depths clamp to [0, 1] (fixes false dark speckle on far-cascade valley floors at grazing sun on the software path), and the shadow distance cap uploads the fitted coverage end so a hard cutoff line can never appear inside populated cascade coverage.

🔭 Sightline rewritten on a depth cube

  • One depth-only cube map serves all sightlines, resolved by tent PCF with receiver-plane depth prediction (cures grazing-pavement acne for street-level observers). All six faces render, so receivers above the observer — city-canyon facades — tint correctly. Terrain tiles inside 3D-Tile coverage are skipped as occluders, matching the shadow pass.
  • DirectionalSightline and OmnidirectionalSightline merge into RealtimeSightline (breaking) — the cube always covers the full sphere, so direction is just a receiver-side mask: fieldOfView now spans (0°, 360°], where 360° is the former omnidirectional and the old 90° limit is gone. Named against its static-analysis peer ViewshedSightline.
  • The depth-cube pass is range-culled — terrain tiles and occluders whose bounds miss the observer's range sphere skip all six faces. Previously a street-scale observer rasterized the whole visible terrain set six times; the cube also survives pans that used to invalidate it.
  • Multi-window safety: the sightline receiver scratch matrix moved onto the per-window draw context, and the depth-cube bind cache is invalidated whenever a benign cube is parked, so receiver order can never sample the wrong cube.

📐 Viewshed fixes

  • The GPU ray-walk's constant step cap silently painted every cell beyond it visible; a rectangular AOI with the observer near a corner reported false coverage across its far region. The cap is now exact per dispatch, and an exhausted walk reads occluded — the conservative default.
  • The draft → full-resolution refine could stall forever on event-driven platforms (JVM/Android) when a draft dispatch spanned more than one frame; the frame pump now keeps running while escalation work is pending.

⚡ Hardware depth-compare receivers

  • Shadow and sightline receivers compile as GLES 3 / WebGL 2 / GL 3.3 core with sampler2DShadow / samplerCubeShadow where the platform supports them: nine hardware 2×2-PCF taps replace the 16-fetch software cascade filter, and each cube tent tap becomes one hardware compare. GLSL ES 1.00 in-shader compares remain the WebGL1 fallback, and Adreno GPUs stay on the software path (hardware compare is driver-unpredictable there). Also fixes the depth-read quantization artifacts (zebra stripes/circles) on Mac "Designed for iPad" builds.

💡 Shading

  • Hemispheric ambient for lit shapes, meshes and 3D tiles: the flat 0.35 ambient becomes a sky/ground hemisphere term with the same average — up-facing surfaces read sky-lit, undersides ground-lit, vertical walls unchanged.

🚀 Performance

  • 3D Tiles: byte-budgeted texture uploads — city-scale loading eager-bound every freshly-installed texture in one frame (a single 2048² mipmapped texture is ~21 MB of glTexImage2D), producing 20–150 ms GL-thread stalls. Uploads now drain in per-frame batches capped by measured upload throughput, targeting a 3 ms bind slice.
  • Android: no more double draw — every discrete redraw and every pick used to cost a second full-scene draw of identical content; the follow-up GL pass is now requested only while the pick or frame queue still holds work.

🍏 iOS fixes

  • SynchronizedPool was a plain unsynchronized pool despite the name; tile-decode workers and the render thread share the engine's pools, so concurrent access could corrupt them or hand the same instance to two consumers. Now locked, mirroring the JVM/Android contract.
  • 3D Tiles child-URI resolution collapses ../ dot segments — servers 403 raw dot segments sent verbatim by the Darwin HTTP stack, which spun tile fetching in an endless cancel/re-auth loop.
  • The render-resource cache sizes to physical memory like Android; the fixed 512 MB cap caused cyclic texture eviction on horizon views (whole-frame flicker and transient geometry corruption).
  • The native Draco decoder is enabled in the Xcode run script (the no-op stub decoded Draco tiles to empty geometry), and the Kotlin framework is declared as a script-phase output so the app relinks instead of shipping a stale build.
  • A cached feature source that yields zero rows refetches from origin, and an undecodable persisted feature file is deleted instead of leaving the layer blank forever.

🗺 Vector layers & MVT

  • Layer order now wins for draped shapes — MVT content rendered above imagery and user surface shapes regardless of layer order because it enqueued at elevated z bands; all MVT draped content now sits at the shared surface z, matching the insertion-order model of the reference engines.
  • Data-availability sector persistedVectorLayer.sector (mirroring ElevationCoverage.sector) gates tile assembly; bulk downloads union the region into it, it persists as the GeoPackage content bbox, and reopening a cache restores it.
  • Request headers persist with the cache — a reopened cached MVT layer keeps e.g. the User-Agent OSM's tile policy requires.
  • No-data tiles stay transparent instead of painting an opaque style-background sheet over underlying layers.
  • Default styles aligned with live reference tile schemas: road _link ramps, OMT path/track classes, rock/wetland landcover, OpenTopoMap cream background, and no more debug-gray fill on unmapped layers.

🐞 Fixes

  • SLPK: texture names are resolved from I3S metadata (textureSetDefinitions, or the legacy per-node href) instead of a hardcoded 0.jpg — fixes white untextured meshes on Metashape-produced packages.
  • GeoPackage: a cancelled reader can no longer leak the read-handle pool empty.

📚 Tutorials

  • The 3D Tiles Archive (.3tz / .3dtiles) tutorial now runs on Android too, sharing one implementation with JVM.

📦 Dependency updates

  • mil-sym 2.11.2 (Android) / 2.8.2 (Java) / 2.9.2 (TS), xmlutil 1.0.1.

Full changelog: v2.0.5...v2.0.6

WorldWind Kotlin v2.0.5

Choose a tag to compare

@EMaksymenko EMaksymenko released this 05 Jul 13:13

WorldWind Kotlin 2.0.5

This release adds three new local data formats (ArcGIS SLPK/I3S scene layers, Cesium 3D Tiles archives, and LAS/LAZ point clouds), extends offline bulk caching to vector layers, and delivers a round of performance and stability fixes for tiled vector rendering — alongside a large internal consolidation pass that removes ~1,900 lines of duplicated code with no behavior change.

✨ New format support

  • ArcGIS SLPK (I3S) scene layers — render an Esri Scene Layer Package (I3S 1.7+ integrated mesh) in place from a local .slpk, with no extraction or copy. Reuses the existing 3D Tiles streaming, traversal, cache, and GPU pipeline through a byte-source seam. Seam-free across tiles, textured, with altitudeOffset support. Validated on real Esri IntegratedMesh v1.8 datasets. (JVM + Android)
  • Cesium 3D Tiles archives (.3tz / .3dtiles) — open a local 3D Tiles archive directly on the globe with openArchived3dTilesLayer(file). Magic-byte sniffing picks the reader: .3tz (ZIP) or .3dtiles (SQLite media table). No decoder or layer subclass needed — the archive holds ordinary 3D Tiles content. (JVM + Android)
  • LAS/LAZ point clouds — new PointCloudLayer loads a standalone .las/.laz file onto the globe, reusing the .pnts GPU path. Pure-Kotlin LAS reader (point formats 0–3, 6–8) and LASzip decoder (chunked formats 0–3), verified byte-identical against the laz-rs reference. Auto-georeferences WGS84/NAD83/ETRS89 UTM and geographic CRS, geoid-aware altitude so orthometric LiDAR rests on terrain, live altitudeOffset, and progressive off-thread loading that keeps single-threaded targets (JS/wasm) interactive.

📦 Offline bulk caching for vector layers

  • Bulk region download for MVT and OSM Buildings — the "save a region for offline use" flow (previously WMS/WMTS raster and elevation only) now covers MVT vector tiles and OSM Buildings, writing through to the same GeoPackage / IndexedDB / file stores. A resolution range picks the same slippy zoom levels as the raster/elevation path.
  • tileCount() on MVT and OSM Buildings layers, mirroring LevelSet.tileCount, so a download can be sized before committing to it.
  • clone() promoted to the VectorLayer contract, implemented by all four vector layers — each builds a fresh instance from config only, never sharing live scopes, semaphores, or caches.

🚀 Performance & stability

  • Bounded GPU memory for tiled feature layers — the resident-tile LRU can now be bounded by real VBO/EBO bytes instead of a flat tile count, so a few dense full-res WFS tiles can no longer balloon GPU memory until the Adreno KGSL driver fails to mmap. TiledFeatureLayer defaults to a 96 MB budget.
  • Per-frame upload throttle — a pan's burst of freshly-fetched tiles is now admitted a few at a time instead of all in one frame, spreading their GPU buffer uploads across frames and eliminating an observed ~410 ms GL-thread hitch.
  • MVT assembly parallelism capped — the background assembly pool no longer sizes to every core; it now leaves cores free for the render/GC threads. Measured on an S23: worst-case frame 568 → 335 ms, GL.draw 492 → 201 ms.
  • WFS refresh efficiencyWfsLayer now caches the GetCapabilities document and reuses a single HTTP client across refreshes, so an auto-refreshing viewport no longer re-downloads capabilities or rebuilds an HTTP client on every pan. The fetch loop is also split from renderable decode, dropping a per-page renderable graph that was built and immediately discarded.

🐞 Fixes

  • Web: serviceTypeToDataType was missing "WCS 2.0.1", registering WCS coverages as tiles on JS/wasm.
  • iOS: FileSystemElevationBackend.writeTile never deleted the ancillary sidecar on default packing, mis-decoding a re-packed tile.
  • Web: ContentManager.findEntry hard-coded lastModified = null while listEntries populated it.
  • Non-casting 3D-tile meshes are now correctly excluded from the shadow cascade cull.
  • JVM: a fast click with incidental jitter no longer triggers an unwanted inertial fling — the gesture must now move beyond the same 5 dp slop the minimap uses, scaled by display density.

🧹 Internal / maintainability

A behavior-preserving consolidation pass across independent subsystems (verified compiling on JVM/JS/wasmJs/iOS, with jvmTest passing):

  • All eight 2D map projections now share their grid/border tessellation loops (−609 lines), backed by a new consistency test covering every projection.
  • Web-Mercator / slippy tile math consolidated into a single SlippyTiles source of truth (tile conversions, MercatorSector delegation, fractional unprojection).
  • Shared cores extracted for: tile-fetch exponential backoff, bulk-retrieval retry/backoff, iOS/Web elevation-backend delegation, shadow/sightline receiver uniform plumbing (−231 lines), the MSM shadow GLSL reconstruction, glTF accessor readers, moments blur, and the lazy HTTP client pattern.
  • Five latent bugs fixed while de-duplicating tile-key and slippy math (see Fixes above).

Tutorials

  • New tutorials wired across JVM / web / iOS / Android shells: Point Cloud (LAS/LAZ), ArcGIS SLPK (I3S), and 3D Tiles Archive.
  • Tutorial lists reordered into themed groups progressing from basics to complex format rendering, consistently across all platforms; the Android drawer gets a distinct icon per theme.

Full changelog: v2.0.4...v2.0.5

WorldWind Kotlin v2.0.4

Choose a tag to compare

@EMaksymenko EMaksymenko released this 30 Jun 22:38

Release 2.0.4

43 commits since 2.0.3.

3D Tiles

  • Render KTX2 (KHR_texture_basisu) textures instead of dropping them.
  • Enable glb-wrapped Gaussian splats out of the box.
  • Throttle Gaussian-splat parses inside the layer, and move the Gaussian view-Z sort to Dispatchers.Default to keep it off the render thread.
  • Depth-pick now lands on the Gaussian-splat surface.
  • Expose the root bounding-volume sector for fly-to.
  • Priority-ordered fetch queue with off-permit cache writes.
  • Evict cold .json-grafted subtrees to bound the Tile3d node count.
  • Combine vbo + ebo + batchIds into one BufferObject per primitive; cache hot-path render-resource-cache refs in MeshSubmesh; inline traversal distance on Tile3d and drop the sortDistances HashMap.
  • GL-thread feedback for the adaptive install throttle.
  • Stencil-mask terrain inside mesh / point-cloud coverage so terrain no longer pokes through.
  • Mesh tiles cast into the sightline moments cube, and always pick the sightline-spliced program variant.
  • Reset the altitude-bake cache when a tileset drops on auth-expired; create the blob-store table on NGA's handle and fix the per-class DAO cache; report cached blob-store size from sizeBytesOf.

WFS

  • Viewport auto-refresh with a GeoPackage cache (download-once & tiled).
  • Retry transient fetch failures with linear backoff.

MVT

  • Shared TiledVectorLayer base, earcut polygon fills, progressive cut, and configurable background + label density.

GeoPackage

  • Read-only handle pool for concurrent feature reads.
  • Add deleteFeatureTable and narrow the features bbox to the actual extent.

Sightline

  • Bind benign textures on the no-sightline receiver path.
  • Clamp the moments texture wrap to edge.
  • Identity-keyed receiver cache; drop frameStamp.

Rendering & Performance

  • WebGL: per-target buffers for 3D Tiles and DPI-correct curved labels.
  • Cache: stale-while-revalidate on the cached-tile fast path, with discard-on-cancel.
  • Elevation: keep cache decode and miss-retry off the render thread.
  • RenderResourceCache: per-frame eviction time budget, and the Web path is now implemented.
  • BasicTessellator: stable BufferObject keys with a version bump on re-prepare.
  • Shapes: one-primitive outlines and exact (non-MSAA) surface-shape picking.
  • Placemark/Label: claim near-plane depth and discard transparent fragments; adaptive Label depth offset.
  • Texture: caller opt-out for mipmap generation.
  • Drawables: reference-only resets.
  • OSM Buildings: persist render config in the cache and filter redundant outlines.

Fixes & Internals

  • WMS capabilities: treat Layer attributes (queryable, cascaded, opaque, noSubsets, fixedWidth, fixedHeight) as unqualified per the XML standard, fixing parsing under xmlutil 1.0.0.
  • HttpClient: install socketTimeoutMillis on all platforms.
  • Tutorials (JVM): export sun.awt to silence JOGL AppContextInfo spam.
  • Fix unresolvable Dokka KDoc links.

Build & Dependencies

  • compileSdk / targetSdk raised to 37 (required by lifecycle-compose 2.11.0).
  • lifecycle-compose 2.10.02.11.0
  • ktor 3.5.03.5.1
  • xmlutil 0.91.31.0.0
  • mil-sym (android 2.11.02.11.1, java 2.8.02.8.1, ts 2.9.02.9.1)
  • javafx 21.0.526.0.1
  • webp-imageio 0.10.20.11.0

WorldWind Kotlin v2.0.3

Choose a tag to compare

@EMaksymenko EMaksymenko released this 17 Jun 09:49

WorldWind Kotlin 2.0.3

11 commits since 2.0.2.

3D Tiles (new)

OGC / Cesium 3D Tiles 1.0 / 1.1 streaming layer. Supports b3dm / i3dm / cmpt / pnts / glTF binary / Gaussian-splat payloads, served via Cesium Ion + Google Photorealistic + Bearer / custom-headers auth providers, with per-feature picking through batch tables. Vertical-datum correction via altitudeOffset + altitudeMode (ABSOLUTE / RELATIVE_TO_GROUND / CLAMP_TO_GROUND). Stencil-masked skip-LoD keeps fallback tiles visible under refining children without inter-LoD flicker.

Niantic SPZ Gaussian-splat codec wired in via the gaussianLoader hook on Ogc3dTilesLayer.

Tutorials: OGC Container (Utrecht), Google Photorealistic, Cesium Ion (defaults to asset 96188 OSM Buildings; swappable to any Ion asset).

Codec modules — new, independent Maven coordinates at 1.0.0

Three optional native-backed glTF extension modules. Each ships per-platform binaries (JVM JARs for macos-aarch64 / macos-x86_64 / linux-x86_64 / windows-x86_64; Android AARs for all four ABIs; iOS klibs via cinterop) and registers itself with the engine at startup via the corresponding installXxxDecoder() call.

Module glTF extension(s) covered
earth.worldwind:worldwind-formats-gltf-draco:1.0.0 KHR_draco_mesh_compression + 3DTILES_draco_point_compression
earth.worldwind:worldwind-formats-gltf-ktx2:1.0.0 KHR_texture_basisu (Basis Universal)
earth.worldwind:worldwind-formats-gltf-meshopt:1.0.0 EXT_meshopt_compression

The engine has no compile-time dependency on these — add them to your build only if your tilesets use the matching extension.

Fixes

  • Web — EGM96 geoid byte-order. The Kotlin/JS actual was viewing the fetched binary as a platform-native Int16Array (little-endian on x86/ARM) while the NGA file is big-endian per spec, returning byte-swapped offsets. Terrain mesh drifted by the local geoid separation: Utrecht tilesets levitated ~44 m above terrain, Manhattan OSM Buildings sat ~34 m below it. Fixed in webMain/EGM96Geoid.kt.

Other changes

  • JVM rendering: WorldWindow swapped from GLJPanel to heavyweight GLCanvas. Fewer blit copies, no PBO contention with Swing's repaint, far better per-frame stability under continuous redraws.
  • GeoPackage caches: per-put LRU eviction across all stores; long-running sessions can no longer out-grow their byte budget.
  • CachePolicy: removed the maxBytes capacity cap. LRU eviction pressure makes the hard ceiling redundant; callers size caches by working-set instead.
  • Internal: project version externalised to gradle.properties (worldwind.version, worldwind.codecsVersion) for CI-driven auto-release on master pushes when either advances past Maven Central.

Web tutorial host (GitHub Pages)

The Pages tutorial bundle now reads CESIUM_ION_TOKEN and GOOGLE_MAPS_API_KEY from repository Secrets at build time. Keys ship inside the public JS bundle, so they must be locked at the provider — HTTP-referrer restriction on the Google Maps Platform key (Map Tiles API only), asset-scoped + referrer-allowlisted Cesium Ion token (assets:read only). Placeholders fall back at build time for local dev without secrets configured.


WorldWind Kotlin v2.0.2

Choose a tag to compare

@EMaksymenko EMaksymenko released this 10 Jun 21:58

WorldWind Kotlin 2.0.2

A maintenance release focused on local elevation coverages, terrain-cache correctness, and a few rendering fixes. 10 commits since 2.0.1.

dependencies {
    implementation("earth.worldwind:worldwind:2.0.2")
}

Highlights

Elevation

  • Local DTED elevation coverage. New DtedElevationCoverage serves a local .dt0/.dt1/.dt2 directory as a single tiled coverage: one pyramid and one cache that resolve the finest level present per 1° cell (dt2 > dt1 > dt0, no duplicated data). Coarse cells upsample smoothly via windowed bilinear reads on the IO dispatcher, zoomed-out grids sparse-sample a cached per-cell overview, and height limits come from the base per-tile min/max — no synchronous reads on the render thread.
  • Cheaper height limits. Per-tile elevation min/max is cached, skipping the render-thread texel rescan and the associated per-frame work.
  • Terrain now reacts to coverage changes. ElevationModel advances its timestamp on every structural change (add / remove / clear / invalidate), not just on data updates. Disabling or removing a coverage now reliably re-tessellates the terrain instead of leaving stale, terraced heights behind.

Rendering & shapes

  • Fixed placemark leader lines turning to noise when drawn over lit shapes.
  • The Label depth offset is now configurable (default -0.003).
  • SelectDragDetector now drags relative-to-ground and above-sea-level shapes consistently with absolute-altitude shapes.

GeoPackage

  • GpkgContentManager defers cache eviction off the store-open path, so opening a store no longer blocks on eviction.

Web / MIL-STD-2525

  • MIL-STD-2525 modifiers/attributes are optional again on the web (js / wasmJs) targets.

Internals

  • Angle.fromDMS precompiles its DMS regexes into constants.
  • Silenced Dokka unresolved-link and tutorial compiler warnings.

Full changelog

  • ee3d8c92 ElevationModel: invalidate terrain on coverage add/remove/clear
  • 00e63f0d GpkgContentManager: defer cache eviction off the store-open path
  • 00e7b07a DtedElevationCoverage: single best-level local DTED elevation coverage
  • 10438b2e Angle.fromDMS: precompile DMS regexes into constants
  • ebe1e0eb Fix placemark leader lines turning to noise over lit shapes
  • 35bbfafa Cache per-tile elevation min/max; skip texel rescan for height limits
  • 72d74e9d SelectDragDetector: drag relative-to-ground and above-sea-level like absolute
  • 36189a0d Make Label depth offset configurable, default -0.003
  • 8b3e3510 Make MIL-STD-2525 modifiers/attributes optional again on web targets
  • b80b734e Silence Dokka unresolved-link and tutorial compiler warnings

Full Changelog: 2.0.1...2.0.2

WorldWind Kotlin v2.0.1

Choose a tag to compare

@EMaksymenko EMaksymenko released this 07 Jun 12:24

WorldWind Kotlin 2.0.1

23 commits since 2.0.0.

Maintenance and platform release. Headline items: a new Kotlin/Wasm (wasmJs) browser target across every module, a reworked stale-while-revalidate caching layer with capacity eviction on all platforms, a flat, interoperable GeoPackage feature cache, and low-memory streaming COLLADA/KMZ loading for large photogrammetry.

implementation 'earth.worldwind:worldwind:2.0.1'

🌐 Kotlin/Wasm (wasmJs) browser target

  • New wasmJs target across all modules (library, Compose, tutorials, samples). Browser code is shared between js and wasmJs in a webMain source set (~53 files) behind expect/actual seams: WebKgl / createWebKgl for the WebGL backend and MilStd2525Renderer for the mil-sym-ts / canvg bindings; only the generated externs, the per-target renderer adapter, and WeakRef stay per-target.
  • kotlinx-browser replaces the kotlin-wrappers BOM; GeoJSON swapped to the wasm-capable spatialk library; pngj moved to jvmCommon.
  • Source sets modernized via applyDefaultHierarchyTemplate (nonIosweb {js, wasmJs} + jvmCommon {jvm, android}).
  • Web tutorials / compose-samples dev-server ports pinned (js + wasmJs) so the browser origin — and the origin-scoped IndexedDB cache — stays stable across runs.

💾 Cache: stale-while-revalidate + capacity eviction

  • Tile freshness moved to a side table; effective SWR for image, elevation, and vector tiles.
  • Conditional-GET (ETag / Last-Modified) revalidation for the elevation cache on all platforms.
  • SWR for feature tiles with age-safe eviction; JS/iOS feature-store SWR freshness.
  • Capacity eviction (maxBytes) for the JS/iOS tile stores and the GeoPackage tile store.
  • Strict local/remote separation for image + elevation retrieval.
  • CacheEvictionPolicy renamed to CachePolicy (type + attributes). (API change)

🗺️ GeoPackage / features

  • Flat, two-way-interoperable GeoPackage feature cache.
  • gpkg_web_service renamed to ww_web_service with automatic migration. (schema change)
  • Drop upstream-vanished features on re-fetch; render a boundary-straddling feature in exactly one tile.

🧊 COLLADA / KMZ (large photogrammetry)

  • Low-memory streaming .dae parse (custom pull tokenizer — never materializes the document or numeric bodies as strings), a configurable texture-size cap (default 2048; an 8192² atlas → 16 MB instead of 256 MB decoded), and zip-direct KMZ loading (no extraction to disk; textures decoded lazily and LRU-evicted).
  • KMZ models are anchored from the doc.kml <Model> placement — position, scale, orientation, and <altitudeMode> (including the gx: sea-floor extensions).
  • Terrain-relative altitude modes (CLAMP_TO_GROUND / RELATIVE_TO_GROUND) place the model on the resolved terrain and follow it as elevation streams in (rebuild keyed on vertical exaggeration / elevation timestamp / globe state).
  • Y_UP models follow the KML model-facing convention (heading 0 → North-aligned) so geo-referenced KMZ tiles (e.g. OpenDroneMap) align out of the box; the COLLADA up-axis alone gives no geographic facing. Cosmetic for bare, manually-placed .dae (override with zRotation).

🛠️ Fixes & internals

  • Reuse a single HTTP client per feature source (+ per-client tutorial SSL).
  • WCS tutorial loads terrain once across all platforms.
  • Gesture: skip pan frames with a non-finite meters-per-pixel.
  • WGS coordinate parsing fix.
  • e2e reopen tests for tile/coverage caches + NGA reference-validator pass.
  • Remove dead getFeatureList code and the dormant JS WebTileCache; extract inlined FQN type references to imports.

Commits

  • Add Kotlin/Wasm (wasmJs) browser target across all modules
  • Deps: swap GeoJSON to wasm-capable spatialk; move pngj to jvmCommon
  • Cleanup: extract inlined FQN type references to imports
  • COLLADA: streaming parse, texture cap, and zip-direct KMZ loading
  • Networking: reuse one HTTP client per feature source; per-client tutorial SSL
  • WCS tutorial: load terrain once across all platforms
  • Gesture: skip pan frames with a non-finite meters-per-pixel
  • Cache: strict local/remote separation for image + elevation retrieval
  • Cache: capacity eviction for the JS/iOS tile stores
  • Coverage: conditional-GET revalidation for the elevation cache (all platforms)
  • Cache: JS/iOS feature-store SWR freshness + capacity eviction
  • Cache: rename CacheEvictionPolicy -> CachePolicy (type + attributes)
  • Tests: e2e reopen for tile/coverage caches + NGA reference-validator pass
  • GeoPackage: rename gpkg_web_service -> ww_web_service with migration
  • Features: drop upstream-vanished features on re-fetch (GeoPackage)
  • Features: render a boundary-straddling feature in exactly one tile
  • JS: remove the dormant WebTileCache
  • Cache: implement maxBytes for the GPKG tile store
  • Features: flat, two-way-interoperable GeoPackage feature cache
  • Cache: move tile freshness to side table + effective SWR for image/elevation/vector
  • Fix WGS coordinates parsing
  • Remove dead getFeatureList code
  • Cache: stale-while-revalidate for feature tiles + age-safe eviction

Full changelog: v2.0.0...v2.0.1

WorldWind Kotlin v2.0.0

Choose a tag to compare

@EMaksymenko EMaksymenko released this 31 May 21:47

WorldWind Kotlin 2.0.0

Major release — 91 commits since 1.14.2. New vector/feature/imagery layers, a
ground-up cache redesign, and broad rendering and API improvements.

Warning

This is a major release with breaking API and package changes. See
Breaking changes before upgrading.


Breaking changes

  • Cache API replaced (source-decorator design). The layer-typed CacheableXxx
    interfaces (configureCache / disableCache / cacheTileFactory /
    isCacheConfigured) are gone. Caching is now external: attachCache(layer, contentKey)
    wraps the layer's source in a CachedTileSource / CachedBulkFeatureSource /
    CachedTiledFeatureSource decorator, and listEntries() + openLayer<T>(contentKey) /
    openElevationCoverage<T> drive cross-launch reopen.
  • GeoPackage moved packages: earth.worldwind.ogc.gpkg / earth.worldwind.ogc.Gpkg*
    earth.worldwind.formats.gpkg. GPKG is a file format, not a network service, so
    ogc/ now contains only network protocols. Update imports accordingly.
  • GeoJsonLayerFactory is now a thin facade over GeoJsonBulkFeatureSource +
    BulkFeatureLayer; the old expect/actual extractGeoJsonProperties API was removed.
  • SelectDragCallback now takes Any instead of Renderable.
  • Compose Multiplatform 1.11.0 drops the iosX64 target in the -compose /
    -compose-samples modules.

New layers

  • MVT (Mapbox Vector Tile) layer with full Mapbox-GL parity: expression DSL
    (case / match / step / interpolate / bezier / feature-state / rgb /
    rgba / geometry-type / line-progress), per-feature picking, sprite atlases,
    per-glyph curved-baseline text, line-gradient, fill-extrusion-height (3D buildings),
    line-dasharray + casings, icon-text-fit highway shields, text-max-width word wrap,
    schema auto-detection (OpenMapTiles vs Shortbread), and a perf-HUD overlay.
  • OsmBuildingsLayer for schematic 3D cities — building / building:part / roof
    tags with colour / material styling, exponential backoff, and a batched
    one-VBO-per-tile mesh.
  • WFS feature serviceCQL_FILTER, paging, POST fallback, auth hook, GeoJSON / GML
    output negotiation, OGC API – Features compatibility, and a viewport-driven WfsLayer
    wrapper.
  • Shapefile loader.shp + .dbf + .prj + .cpg / language-driver codepages,
    ZIP-archive ingest, MultiPatch (shape type 31) → TriangleMesh, UTM reprojection,
    surface-drape with depth-offset, lazy recordsSequence.
  • NITF 2.1 / NSIF 1.0 imagery — uncompressed grayscale + 3-band RGB.
  • DTED elevation tiles (MIL-PRF-89020B) with local-library coverage.

Cache architecture v3 (source-decorator redesign)

  • External, source-decorator API. attachCache(layer, contentKey) wraps the layer's
    source in a cache decorator and registers a service-identity row;
    listEntries() + openLayer<T>(contentKey) / openElevationCoverage<T> reopen entries
    across launches. CacheCategory<T> (typed sealed-class witness) lets
    cm.open(CacheCategory.X) bulk-rebuild every entry of one data type with the right
    return shape.
  • Unified entry metadata. CacheEntry / ContentEntry are the single read/write
    surface for an entry's contentKey, lastModified, contentSize, displayName.
    File-format factories (MBTiles, RMaps, ATAK) and self-contained package layers
    (Kropyva-style .kme) implement ContentEntry directly; GPKG / IndexedDB / filesystem
    caches route through a ContentManagerEntry adapter. Apps dispatch generically against
    layer.contentEntry(cm) with no per-format type checks.
  • BulkFeatureLayer + BulkFeatureSource — one streaming pipeline for every
    vector-feature source (WFS, Shapefile, and now GeoJSON via GeoJsonBulkFeatureSource),
    with simplestyle keys applied automatically and density /
    labelVisibilityThreshold / defaultAltitudeMode / autoApplyStyle as layer-level
    params. GeoJSON cache opt-in (attachCache + openLayer<BulkFeatureLayer>) replays
    rows from the feature store on later launches with no source text required.
  • CachedGeometry gains MultiPolygon — GeoJSON / GPKG MULTIPOLYGON features no
    longer flatten to their first sub-polygon; they fan out to N Polygon renderables
    sharing one properties map.

Other cache infrastructure

  • Pure-web IndexedDB cachingCachedBulkFeatureSource + IndexedDbTileStore for
    image, vector-tile, feature, and elevation data on JS. iOS uses an NSBundle-anchored
    FileSystemTileStore + FileSystemFeatureStore.
  • CacheEvictionPolicy (maxEntries / maxAge / maxBytes) across every cache
    backend, with sweep-on-bind + explicit evict().
  • MVT persistent tile cache — GeoPackage on JVM/Android (OGC Image Matters
    im_vector_tiles_mapbox extension, readable by QGIS / ogr2ogr / NGA geopackage-java)
    and IndexedDB on JS, with HTTP ETag / Last-Modified revalidation.
  • Bulk-download overrideCache flagTiledImageLayer.launchBulkRetrieval and
    TiledElevationCoverage.launchBulkRetrieval can re-fetch every tile ignoring the cache.

Rendering

  • Mapbox style loader — full operator parity, fill-extrusion layer type,
    text-max-width 10em default.
  • ShadowLayer — tighter default cap, lookAt-range scaling, Lambert-modulated
    attenuation, soft-fade far cascade edge.
  • Moments textures gate GL_LINEAR on OES_texture_float_linear (Adreno fix).
  • JS WebGL2 translates legacy GLSL to ES 3.00 for dFdx-based lighting.
  • RenderResourceCache uses page-aligned BufferObject footprint for LRU accounting.
  • Lambertian shading on triangle-shaded shapes.
  • Depth-offset clamp-to-ground vector shapes (no more sinking into terrain).

API & package layout

  • KML format API made public.
  • GeoPackage moved to earth.worldwind.formats.gpkg (see Breaking changes); ogc/
    now contains only network protocols.
  • GeoJsonLayerFactory reduced to a ~30-line facade over GeoJsonBulkFeatureSource
    • BulkFeatureLayer.
  • New cross-platform GeoJSON and KML tutorials (commonMain) replace the Android-only
    KmlDemoActivity / GeoJsonDemoActivity. Sample documents ship as moko-resources
    assets, read per-platform via classpath / AssetManager / NSBundle / fetch.

Dependency bumps

  • Compose Multiplatform 1.10.3 → 1.11.0 (drops iosX64 in -compose /
    -compose-samples).
  • Ktor 3.4.3 → 3.5.0.
  • Kotlin 2.3.21, kotlinx-coroutines 1.11.0, kotlinx-serialization 1.11.0,
    geopackage-android 6.7.5.

Android versionCode 24 → 25.

WorldWind Kotlin v1.14.0

Choose a tag to compare

@EMaksymenko EMaksymenko released this 09 May 21:59

WorldWindKotlin 1.14.0 — Release Notes

Highlights

  • iOS support — New Kotlin/Native target (iosX64, iosArm64, iosSimulatorArm64) across :worldwind, :worldwind-compose, :worldwind-compose-samples, and :worldwind-tutorials. SwiftUI tutorial shell included.
  • Toolchain bump — Migrated to AGP 9 / Gradle 9 / Kotlin 2.3.21.
  • Unified Compose API — Single @Composable WorldWindow that works across Android, JVM (Desktop), JS, and iOS.
  • 3D Ellipsoid shape — New tri-axial ellipsoid renderable with rotation and lighting.

New Features

  • Compose: @Composable WorldWindow unified across Android, JVM, and JS (b29cdc7)
  • Shapes: 3D rotation / tri-axial Ellipsoid with lighting (caeaa3f)
  • Sightline: embedded-receiver path for in-shader self-shadow (f584eaf)
  • Navigation: fling + zoom-anchor gestures for 2D projections (2bd48a0)
  • GeoTiff: unified reader/writer in commonMain, dropping the JVM-only mil.nga.tiff dependency (2815097)

Fixes

  • Sightline/Shadow: restore caller's framebuffer instead of unbinding to NONE (12ab237)
  • DrawableSightline: directional regression — re-run depth per face (faf7366)
  • Path: emit second trailing miter dummy so WebGL accepts surface lines (0a95ae0)
  • Shape: invalidate geometry cache on vertical-exaggeration change (938f30e)
  • Shapes: keep BoundingData across reset() to stop fall-through blinking (961a40d)
  • Placemark/Label: recompute placePoint each frame (drop stale cartesian cache) (b9c8fd1)
  • SelectDragDetector: placemark select/drag on macOS Safari (6aa7cb5)
  • SelectDragDetector: route depth-tested point into pick/context/double-tap (4117c83)
  • PickedObject: opt out of depth unprojection for surface shapes (696f18d)
  • WorldWind: 2D pan stuck when subclasses override gestureDidBegin (7c7426d)
  • WorldWind: skip COLLISION_THRESHOLD on globe-state reclamp (8b5c7ea)
  • RequestRedraw: don't block sequential calls from background threads (050602d)
  • Tutorials: request redraw after async COLLADA/glTF parse completes (4ed2c48)

Rendering / Performance

  • ViewshedSightline: multi-WorldWindow correctness + RRC-managed output texture (db3f54f)
  • Programs: per-WorldWindow shader-program storage (ccff546)
  • Programs: zero-overhead no-shadow variants for shadow receivers (2c2f4c8)
  • Shadows: per-platform MSM moment bias (66dcf51)
  • Atmosphere: drop shadow modulation from GroundProgram SECONDARY pass (ea3675d)
  • Shadow: route surface-shape rasterize-pass disable through helper (95f32a2)
  • DrawableSightline: dispatch SightlineReceiver in occlusion passes (7be1f70)
  • RenderContext: reified getShaderProgram overload; drop KEY companions (9bcb7c6)

Build / Tooling

  • JVM/macOS: tutorials run on Apple Silicon JBR (eaa1ef3)
  • Build: strip moko-resources iOS pack on non-Mac hosts (Windows/Linux CI) (79abeec)
  • JVM: bump vlcj to 4.12.1 + assorted dependency bumps (3e7e111)
  • GeoTiffReader: drop ignored-key/tag log spam to DEBUG (2c87ad9)
  • Skip signing for local MavenLocal publishes (56c2033)
  • Examples: drop day-night terminator from basic Android activities (e2d9a0e)

Full Changelog: v1.13.1...v1.14.0 (38 commits)

WorldWind Kotlin v1.13.1

Choose a tag to compare

@EMaksymenko EMaksymenko released this 01 May 23:21

Highlights

Directional sun shadows. New ShadowLayer adds cascaded shadow maps with Hamburger 4-moment Moment Shadow Mapping. Shapes (3D meshes, polygons, COLLADA, glTF) cast shadows onto terrain and onto each other from the same sun direction that drives lighting and atmosphere. Opt-in: add ShadowLayer() to the layer list after AtmosphereLayer.

Atmosphere realism. Standard scattering coefficients plus a Black Marble city-lights night side.

WebGL stability. Two pre-existing GL_INVALID_OPERATION feedback-loop sources (one only fired during pick drag) eliminated.

What's New

Shadows

  • ShadowLayer with PSSM cascades (default 3) blended uniform/log via splitBlend.
  • Hamburger 4-moment MSM and 9-tap rotated PCF receiver paths, selectable via ShadowLayer.algorithm.
  • Per-platform defaults: JS → MSM (1-tap analytic Cholesky is fast on WebGL2/ANGLE), JVM/Android → PCF (Adreno can't do MSM cleanly).
  • ShapeAttributes.shadowMode, ColladaScene.shadowMode, GltfScene.shadowMode — per-shape cast/receive control, decoupled from isLightingEnabled.
  • Auto-scaling cascade reach (maxCascadeDistance and casterPullback track camera altitude) so the same defaults work from city view to globe view.
  • Per-cascade caster + terrain-tile culling, half-resolution far cascade, sun-below-horizon early-exit.
  • Stable cascade footprint via bounding-sphere texel snap (no shimmering on camera move).
  • Smooth blend across cascade boundaries.

Atmosphere & sky

  • AtmosphereLayer: standard scattering coefficients (Kr/Km/eSun) plus night-side Black Marble texture sampling.
  • StarFieldLayer: Gaussian star profile, larger sprites, density-aware sun rendering.

Input

  • Cursor-perfect drag for clamp-to-ground shapes in SelectDragDetector.
  • Fling gesture cancels reliably on every press regardless of which consumer claimed the pointer.

Bug Fixes

  • ViewshedSightline pick now returns the sightline itself rather than its internal SurfaceImage.
  • Pick depth texture left bound to GL_TEXTURE0 after the depth-to-color blit caused GL_INVALID_OPERATION feedback errors during back-to-back picks (drag).
  • Cascade textures left bound from the previous frame's receiver pass formed a feedback loop on the next frame's depth pass under Chromium's sampler-aware WebGL check.

API Additions

// Add directional sun shadows to a scene
engine.layers.addLayer(ShadowLayer())

// Per-shape opt-out
attributes.shadowMode = ShadowMode.RECEIVE_ONLY    // building doesn't cast onto itself
attributes.shadowMode = ShadowMode.CAST_ONLY       // marker that shouldn't get darkened
attributes.shadowMode = ShadowMode.NONE            // skip the pipeline entirely

// Algorithm override (per-platform default applies otherwise)
ShadowLayer().apply { algorithm = ShadowAlgorithm.MSM }

Migration Notes

  • ShadowLayer is opt-in and off by default; existing scenes are unaffected.
  • ShapeAttributes.shadowMode defaults to CAST_AND_RECEIVE. Without ShadowLayer in the layer list, the field is inert.
  • Place ShadowLayer after AtmosphereLayer so the layer sees the sun direction.

Full Changelog: v1.13.0...v1.13.1

WorldWind Kotlin v1.13.0

Choose a tag to compare

@EMaksymenko EMaksymenko released this 29 Apr 22:09

New features

  • 3D model formats — COLLADA and glTF 2.0 loaders with cross-platform tutorials.
  • Projected media surface — drape drone video / photos on terrain via 4-corner homography, plus a 3D camera-frustum projection path driven from KLV pose. (Documented JS/WebGL incompatibility on the 3D path.)
  • Sightline / viewshed overhaul
    • DEM-based GPU viewshed independent of terrain LoD
    • Cast shadows from off-frustum shapes inside sightline range
    • Variance Shadow Mapping with separable Gaussian on moments
    • Omnidirectional Moment Shadow Mapping with cube-map storage
    • SightlineOccluder hook so 3D shapes occlude as well
  • UI overlay layers — density-aware sizing and cross-platform interaction.
  • Improved atmosphere layer and more realistic star field.
  • Additional geographic projections.
  • Ellipse arc / pie-slice via startAzimuth + sweepAngle.
  • Pan fling and cursor / pinch-anchored zoom.
  • JVM KeyboardControls — multi-key hold and per-key acceleration.
  • Tutorial-selection UI in JVM entry point mirroring JS Main.
  • DefaultHttpClient expect/actual with platform engine customization hook (e.g. permissive SSL).
  • Picking returns Cartesian point reconstructed from pick-pass depth buffer.
  • Location.fromString — strict, format-autodetecting parser.

Rendering / globe robustness

  • Antimeridian + pole rendering for surface Polygon / Path / Ellipse, plus surface shapes that cross the antimeridian.
  • 3D Polygon Cartesian tessellation for pole-encircling polygons; top-plane lat/lon GLU input with antimeridian unwrap.
  • MSAA antialiasing for surface shapes.
  • Skip depth-write on translucent fragments.
  • 2D globe: hide tilt and exaggeration controls.
  • Camera clamps to terrain on globe-state change.
  • GoToAnimator animates tilt to 0 so the final lookAt matches the target.

Interaction & input

  • Drag picks point in parallel with cursor (no snap of ref to cursor).
  • View controls: live cursor tracking and orphan-repeat fix.
  • JS controller: touch events for minimap and view controls; finger-drag fix and removed dead zone; click events from drags are now swallowed.
  • JVM HiDPI mouse-coordinate offset fix.

Performance & internals

  • Smarter per-frame shape-assembly budget with graceful fall-through.
  • Pre-allocated arrays in index-buffer assembly (replacing List<Short> / List<Int>).
  • Long → Int buffer / data version counters.
  • GpkgContentManager dispatches SQLite work to Dispatchers.IO.
  • Cached Cartesian position in Placemark and Label (with correctness fix).
  • Reduced maximum star size.
  • Carry-overs from 1.11.x: LongLruMemoryCache (no Long boxing), elevation-decoder optimizations, async JVM frame rendering, throttled shape geometry assembly, drawable-queue sort optimizations, GLU tessellator cleanup, removal of per-frame NumericArray wrappers, eye-distance threshold cached on instances.

Bug fixes

  • DrawableQueue sort-key encoding for negative order values.
  • Deprecated onLowMemory / TRIM_MEMORY callbacks replaced.
  • ExtractKlv anchors JSON timeline at the video's first PTS.
  • Raw path variable shadowing addressed.
  • Several MilStd2525 generation fixes; mil-sym-2525 deps bumped.
  • Documentation and test warnings cleaned up.

Tutorials

  • Depth-pick visualization, Android Movable drag, JVM SSL hook.
  • Refreshed Android HTML help to match current Kotlin sources.

Full changelog: v1.11.0...v1.13.0