@tangram.gl/tangram-renderer 0.0.0-stage → 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -2
- package/dist/core.js +36923 -0
- package/dist/core.js.map +6 -0
- package/dist/index.js +32 -0
- package/dist/loaders-gl-worker.js +82 -0
- package/dist/loaders-gl-worker.js.map +6 -0
- package/dist/map-logic.js +2 -0
- package/dist/map-logic.js.map +6 -0
- package/dist/projected-basemaps-worker.js +3 -0
- package/dist/projected-basemaps-worker.js.map +6 -0
- package/dist/shader-modules.js +141 -0
- package/dist/shader-modules.js.map +6 -0
- package/dist/style-schema.js +126 -0
- package/dist/style-schema.js.map +6 -0
- package/dist/tangram-style.schema.json +882 -0
- package/dist/tangram.debug.mjs +37139 -0
- package/dist/tangram.debug.mjs.map +6 -0
- package/dist/tangram.min.mjs +4950 -0
- package/dist/types/builders/earcut.d.ts +15 -0
- package/dist/types/core.d.ts +29 -0
- package/dist/types/gl/constants.d.ts +2 -0
- package/dist/types/gl/globe_mesh.d.ts +48 -0
- package/dist/types/gl/glsl.d.ts +17 -0
- package/dist/types/gl/vertex-constants.d.ts +4 -0
- package/dist/types/gl/vertex-types.d.ts +34 -0
- package/dist/types/gl/vertex_data.d.ts +32 -0
- package/dist/types/gl/vertex_elements.d.ts +8 -0
- package/dist/types/gl/vertex_layout.d.ts +32 -0
- package/dist/types/glsl.d.ts +14 -0
- package/dist/types/gpu/luma_device_renderer.d.ts +66 -0
- package/dist/types/gpu/resource_lifecycle.d.ts +4 -0
- package/dist/types/gpu/tangram_gpu_backend.d.ts +151 -0
- package/dist/types/index.d.ts +155 -0
- package/dist/types/lights/light-definitions.d.ts +121 -0
- package/dist/types/map-logic/draped-terrain-bounds.d.ts +41 -0
- package/dist/types/map-logic/globe-terrain-preparation.d.ts +85 -0
- package/dist/types/map-logic/globe-terrain.d.ts +54 -0
- package/dist/types/map-logic/index.d.ts +33 -0
- package/dist/types/map-logic/label-identity.d.ts +22 -0
- package/dist/types/map-logic/label-placement.d.ts +32 -0
- package/dist/types/map-logic/screen-bounds.d.ts +15 -0
- package/dist/types/map-logic/terrain-data.d.ts +55 -0
- package/dist/types/map-logic/terrain-error.d.ts +51 -0
- package/dist/types/map-logic/terrain-ground-topology.d.ts +26 -0
- package/dist/types/map-logic/terrain-height-field.d.ts +59 -0
- package/dist/types/map-logic/terrain-navigation.d.ts +27 -0
- package/dist/types/map-logic/terrain-neighborhood.d.ts +5 -0
- package/dist/types/map-logic/terrain-query.d.ts +33 -0
- package/dist/types/map-logic/terrain-resource-budget.d.ts +51 -0
- package/dist/types/map-logic/terrain-transition-topology.d.ts +23 -0
- package/dist/types/map-logic/tile-build-queue.d.ts +51 -0
- package/dist/types/map-logic/tile-cache-policy.d.ts +46 -0
- package/dist/types/map-logic/tile-residency.d.ts +17 -0
- package/dist/types/map-logic/triangle-query-index.d.ts +87 -0
- package/dist/types/procedures/js-yaml.d.ts +15 -0
- package/dist/types/procedures/mesh-projector.d.ts +107 -0
- package/dist/types/procedures/mvt-dependencies.d.ts +20 -0
- package/dist/types/procedures/projected-coordinate-transform.d.ts +27 -0
- package/dist/types/procedures/projection-batch-executor.d.ts +53 -0
- package/dist/types/procedures/scene-yaml-legacy.d.ts +6 -0
- package/dist/types/procedures/terrain-draping.d.ts +165 -0
- package/dist/types/procedures/terrain-globe.d.ts +6 -0
- package/dist/types/procedures/terrain-styled-topology.d.ts +34 -0
- package/dist/types/procedures/web-mercator-legacy.d.ts +4 -0
- package/dist/types/procedures/web-mercator-math.d.ts +4 -0
- package/dist/types/scene/globals.d.ts +11 -0
- package/dist/types/scene/ground_footprint.d.ts +16 -0
- package/dist/types/scene/host_frame.d.ts +54 -0
- package/dist/types/scene/projection_math.d.ts +52 -0
- package/dist/types/scene/scene-resource-types.d.ts +177 -0
- package/dist/types/scene/scene_bundle.d.ts +69 -0
- package/dist/types/scene/visibility_adapter.d.ts +106 -0
- package/dist/types/selection/draped-terrain-surface.d.ts +78 -0
- package/dist/types/selection/terrain_surface.d.ts +149 -0
- package/dist/types/shader-modules/globe-horizon.d.ts +15 -0
- package/dist/types/shader-modules/height-decode.d.ts +13 -0
- package/dist/types/shader-modules/hillshade.d.ts +13 -0
- package/dist/types/shader-modules/index.d.ts +6 -0
- package/dist/types/shader-modules/planar.d.ts +12 -0
- package/dist/types/shader-modules/sphere-map.d.ts +13 -0
- package/dist/types/shader-modules/triplanar.d.ts +15 -0
- package/dist/types/sources/decoded_tile_store.d.ts +95 -0
- package/dist/types/sources/tile_source_metadata.d.ts +32 -0
- package/dist/types/styles/text/fontfaceobserver.d.ts +10 -0
- package/dist/types/tile/tile_id.d.ts +37 -0
- package/dist/types/tile/tile_traversal_adapter.d.ts +63 -0
- package/dist/types/types.d.ts +293 -0
- package/dist/types/utils/geo.d.ts +57 -0
- package/dist/types/utils/hash.d.ts +1 -0
- package/dist/types/utils/log.d.ts +27 -0
- package/dist/types/utils/props.d.ts +6 -0
- package/dist/types/utils/subscribe.d.ts +10 -0
- package/dist/types/utils/thread.d.ts +6 -0
- package/dist/types/utils/urls.d.ts +26 -0
- package/dist/types/utils/utils.d.ts +26 -0
- package/dist/types/utils/version.d.ts +2 -0
- package/dist/types/utils/worker-types.d.ts +68 -0
- package/dist/types/utils/worker_broker.d.ts +3 -0
- package/package.json +103 -3
- package/src/builders/common.ts +41 -0
- package/src/builders/earcut.d.ts +15 -0
- package/src/builders/geometry-types.ts +60 -0
- package/src/builders/points.ts +115 -0
- package/src/builders/polygons.ts +225 -0
- package/src/builders/polylines.ts +682 -0
- package/src/builders/wireframe.ts +31 -0
- package/src/core.d.ts +29 -0
- package/src/core.ts +33 -0
- package/src/experimental/loaders-gl-worker.ts +19 -0
- package/src/experimental/projected-basemaps-worker.ts +13 -0
- package/src/experimental/projected-mesh-cache.ts +137 -0
- package/src/experimental/projected-mesh-domain.ts +110 -0
- package/src/experimental/projected-mesh-refinement.ts +193 -0
- package/src/experimental/projected-mesh.ts +399 -0
- package/src/experimental/projected-normal.ts +26 -0
- package/src/experimental/projected-symbol-mesh.ts +74 -0
- package/src/gl/constants.ts +18 -0
- package/src/gl/context.ts +103 -0
- package/src/gl/extensions.ts +30 -0
- package/src/gl/globe_mesh.ts +285 -0
- package/src/gl/glsl.ts +257 -0
- package/src/gl/mesh-types.ts +56 -0
- package/src/gl/render_state.ts +111 -0
- package/src/gl/shader_program.ts +1310 -0
- package/src/gl/texture.ts +814 -0
- package/src/gl/uniform_buffer.ts +340 -0
- package/src/gl/vao.ts +154 -0
- package/src/gl/vbo_mesh.ts +349 -0
- package/src/gl/vertex-constants.ts +19 -0
- package/src/gl/vertex-types.ts +35 -0
- package/src/gl/vertex_data.ts +126 -0
- package/src/gl/vertex_elements.ts +54 -0
- package/src/gl/vertex_layout.ts +241 -0
- package/src/glsl.d.ts +14 -0
- package/src/gpu/luma_device_renderer.ts +579 -0
- package/src/gpu/pixel_readback.ts +51 -0
- package/src/gpu/resource_lifecycle.ts +32 -0
- package/src/gpu/tangram_gpu_backend.ts +195 -0
- package/src/index.d.ts +155 -0
- package/src/index.ts +105 -0
- package/src/labels/collision-types.ts +94 -0
- package/src/labels/collision.ts +273 -0
- package/src/labels/collision_grid.ts +61 -0
- package/src/labels/intersect.ts +30 -0
- package/src/labels/label-types.ts +91 -0
- package/src/labels/label.ts +207 -0
- package/src/labels/label_line.ts +801 -0
- package/src/labels/label_point.ts +131 -0
- package/src/labels/main-pass-types.ts +73 -0
- package/src/labels/main_pass.ts +221 -0
- package/src/labels/point_anchor.ts +100 -0
- package/src/labels/point_placement.ts +150 -0
- package/src/labels/projected-pass.ts +259 -0
- package/src/labels/repeat_group.ts +72 -0
- package/src/lights/ambient_light.glsl +18 -0
- package/src/lights/directional_light.glsl +39 -0
- package/src/lights/geographic-lights.ts +21 -0
- package/src/lights/light-definitions.ts +285 -0
- package/src/lights/light.ts +590 -0
- package/src/lights/lighting-uniforms.ts +80 -0
- package/src/lights/lighting-wgsl.ts +116 -0
- package/src/lights/material.glsl +237 -0
- package/src/lights/material.ts +145 -0
- package/src/lights/native-falloff.ts +37 -0
- package/src/lights/point_light.glsl +96 -0
- package/src/lights/spot_light.glsl +111 -0
- package/src/map-logic/draped-terrain-bounds.ts +71 -0
- package/src/map-logic/globe-terrain-preparation.ts +217 -0
- package/src/map-logic/globe-terrain.ts +296 -0
- package/src/map-logic/index.ts +37 -0
- package/src/map-logic/label-identity.ts +36 -0
- package/src/map-logic/label-placement.ts +117 -0
- package/src/map-logic/screen-bounds.ts +34 -0
- package/src/map-logic/terrain-data.ts +107 -0
- package/src/map-logic/terrain-error.ts +134 -0
- package/src/map-logic/terrain-ground-topology.ts +164 -0
- package/src/map-logic/terrain-height-field.ts +254 -0
- package/src/map-logic/terrain-navigation.ts +50 -0
- package/src/map-logic/terrain-neighborhood.ts +43 -0
- package/src/map-logic/terrain-query.ts +51 -0
- package/src/map-logic/terrain-resource-budget.ts +124 -0
- package/src/map-logic/terrain-transition-topology.ts +164 -0
- package/src/map-logic/tile-build-queue.ts +110 -0
- package/src/map-logic/tile-cache-policy.ts +89 -0
- package/src/map-logic/tile-residency.ts +50 -0
- package/src/map-logic/triangle-query-index.ts +265 -0
- package/src/procedures/js-yaml.d.ts +15 -0
- package/src/procedures/mesh-projector.ts +191 -0
- package/src/procedures/mlt-loaders.ts +55 -0
- package/src/procedures/mvt-dependencies.d.ts +20 -0
- package/src/procedures/mvt-legacy.ts +150 -0
- package/src/procedures/mvt-loaders.ts +53 -0
- package/src/procedures/mvt-parser.ts +48 -0
- package/src/procedures/mvt-properties.ts +36 -0
- package/src/procedures/mvt-tile-provider.ts +72 -0
- package/src/procedures/pmtiles-loader.ts +75 -0
- package/src/procedures/projected-coordinate-transform.ts +79 -0
- package/src/procedures/projection-batch-executor.ts +140 -0
- package/src/procedures/scene-yaml-legacy.ts +16 -0
- package/src/procedures/scene-yaml-loaders.ts +10 -0
- package/src/procedures/terrain-draping.ts +713 -0
- package/src/procedures/terrain-globe.ts +32 -0
- package/src/procedures/terrain-styled-topology.ts +184 -0
- package/src/procedures/web-mercator-legacy.ts +24 -0
- package/src/procedures/web-mercator-math.ts +50 -0
- package/src/scene/camera.ts +298 -0
- package/src/scene/camera_base.ts +116 -0
- package/src/scene/classic_scene.ts +20 -0
- package/src/scene/external_camera.ts +101 -0
- package/src/scene/globals.ts +120 -0
- package/src/scene/ground_footprint.ts +139 -0
- package/src/scene/host_frame.ts +326 -0
- package/src/scene/projected_tile_lod.ts +125 -0
- package/src/scene/projection_math.ts +142 -0
- package/src/scene/projection_shaders.ts +183 -0
- package/src/scene/renderer.ts +516 -0
- package/src/scene/scene-resource-types.ts +174 -0
- package/src/scene/scene.ts +2378 -0
- package/src/scene/scene_bundle.ts +304 -0
- package/src/scene/scene_debug.ts +129 -0
- package/src/scene/scene_loader.ts +402 -0
- package/src/scene/scene_worker.ts +528 -0
- package/src/scene/view.ts +683 -0
- package/src/scene/visibility_adapter.ts +319 -0
- package/src/scene/worker_url.ts +15 -0
- package/src/selection/draped-terrain-surface.ts +377 -0
- package/src/selection/selection-types.ts +79 -0
- package/src/selection/selection.ts +542 -0
- package/src/selection/selection_fragment.glsl +18 -0
- package/src/selection/selection_globals.glsl +9 -0
- package/src/selection/selection_pixels.ts +59 -0
- package/src/selection/selection_vertex.glsl +15 -0
- package/src/selection/terrain_surface.ts +298 -0
- package/src/shader-modules/globe-horizon.ts +52 -0
- package/src/shader-modules/height-decode.ts +41 -0
- package/src/shader-modules/hillshade.ts +70 -0
- package/src/shader-modules/index.ts +10 -0
- package/src/shader-modules/planar.ts +24 -0
- package/src/shader-modules/sphere-map.ts +38 -0
- package/src/shader-modules/triplanar.ts +45 -0
- package/src/sources/aligned_tile_source.ts +122 -0
- package/src/sources/data_source.ts +655 -0
- package/src/sources/decoded_tile_store.ts +245 -0
- package/src/sources/geojson.ts +300 -0
- package/src/sources/mvt.ts +247 -0
- package/src/sources/raster.ts +341 -0
- package/src/sources/shared_tile_source_adapter.ts +117 -0
- package/src/sources/sources.ts +10 -0
- package/src/sources/tile_source_adapter.ts +84 -0
- package/src/sources/tile_source_metadata.ts +65 -0
- package/src/sources/tile_source_state.ts +112 -0
- package/src/sources/topojson.ts +90 -0
- package/src/styles/feature_annotations.ts +16 -0
- package/src/styles/filter.ts +190 -0
- package/src/styles/geometry-style-types.ts +209 -0
- package/src/styles/globe_visibility_wgsl.ts +22 -0
- package/src/styles/layer-types.ts +45 -0
- package/src/styles/layer.ts +586 -0
- package/src/styles/lines/dasharray.ts +49 -0
- package/src/styles/lines/lines.ts +707 -0
- package/src/styles/lines/lines_wgsl.ts +224 -0
- package/src/styles/points/point-runtime-types.ts +125 -0
- package/src/styles/points/points.ts +1079 -0
- package/src/styles/points/points_fragment.glsl +126 -0
- package/src/styles/points/points_vertex.glsl +230 -0
- package/src/styles/points/points_wgsl.ts +189 -0
- package/src/styles/polygons/polygons.ts +268 -0
- package/src/styles/polygons/polygons_fragment.glsl +173 -0
- package/src/styles/polygons/polygons_vertex.glsl +213 -0
- package/src/styles/polygons/polygons_wgsl.ts +127 -0
- package/src/styles/property-types.ts +125 -0
- package/src/styles/raster/raster.ts +33 -0
- package/src/styles/raster/raster_globals.glsl +46 -0
- package/src/styles/style-mixing-types.ts +101 -0
- package/src/styles/style-runtime-types.ts +220 -0
- package/src/styles/style-schema.ts +133 -0
- package/src/styles/style.ts +1033 -0
- package/src/styles/style_globals.glsl +69 -0
- package/src/styles/style_manager.ts +464 -0
- package/src/styles/style_parser.ts +620 -0
- package/src/styles/text/font_manager.ts +180 -0
- package/src/styles/text/fontfaceobserver.d.ts +10 -0
- package/src/styles/text/text-types.ts +220 -0
- package/src/styles/text/text.ts +378 -0
- package/src/styles/text/text_canvas.ts +773 -0
- package/src/styles/text/text_labels.ts +436 -0
- package/src/styles/text/text_segments.ts +142 -0
- package/src/styles/text/text_settings.ts +228 -0
- package/src/styles/text/text_wgsl.ts +159 -0
- package/src/styles/text/text_wrap.ts +194 -0
- package/src/tile/globe_tile_preload.ts +40 -0
- package/src/tile/tangram_tileset_2d.ts +108 -0
- package/src/tile/tile-build-types.ts +155 -0
- package/src/tile/tile.ts +807 -0
- package/src/tile/tile_id.ts +172 -0
- package/src/tile/tile_manager.ts +889 -0
- package/src/tile/tile_pyramid.ts +119 -0
- package/src/tile/tile_resource_cache.ts +91 -0
- package/src/tile/tile_traversal_adapter.ts +132 -0
- package/src/types.ts +332 -0
- package/src/utils/debounce.ts +17 -0
- package/src/utils/debug_settings.ts +43 -0
- package/src/utils/errors.ts +12 -0
- package/src/utils/functions.ts +95 -0
- package/src/utils/geo.ts +364 -0
- package/src/utils/hash.ts +14 -0
- package/src/utils/log.ts +108 -0
- package/src/utils/media_capture.ts +193 -0
- package/src/utils/merge.ts +44 -0
- package/src/utils/obb.ts +134 -0
- package/src/utils/props.ts +43 -0
- package/src/utils/slice.ts +14 -0
- package/src/utils/subscribe.ts +58 -0
- package/src/utils/task.ts +154 -0
- package/src/utils/thread.ts +26 -0
- package/src/utils/urls.ts +223 -0
- package/src/utils/utils.ts +310 -0
- package/src/utils/vector.ts +197 -0
- package/src/utils/version.ts +8 -0
- package/src/utils/worker-types.ts +79 -0
- package/src/utils/worker_broker.ts +523 -0
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
// tangram-layers
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import Scene from './scene';
|
|
6
|
+
import HostFrame from './host_frame';
|
|
7
|
+
import LumaDeviceRenderer from '../gpu/luma_device_renderer';
|
|
8
|
+
import type View from './view';
|
|
9
|
+
import type {RendererOptions, RenderOptions, SceneDefinition, SceneListeners, SceneLoadOptions, TileResourceStatistics, TileSourceStatistics} from '../types';
|
|
10
|
+
import type {TangramLightMapping} from '../lights/light-definitions';
|
|
11
|
+
import type {TangramTileSourceMetadata} from '../sources/tile_source_metadata';
|
|
12
|
+
import {validateConcurrentTileLoads} from '../sources/decoded_tile_store';
|
|
13
|
+
import {normalizeProjectedBasemapOptions} from '../procedures/mesh-projector';
|
|
14
|
+
import {validateProjectionEngine} from '../procedures/projected-coordinate-transform';
|
|
15
|
+
import type {ProjectedBasemapOptions} from '../procedures/mesh-projector';
|
|
16
|
+
import {normalizeProjectionExecutionOptions} from '../procedures/projection-batch-executor';
|
|
17
|
+
import type {ProjectionExecutionStatistics} from '../procedures/projection-batch-executor';
|
|
18
|
+
import type {FeatureSelectionResult, FeatureSelectionOptions} from '../types';
|
|
19
|
+
import {Matrix4} from '@math.gl/core';
|
|
20
|
+
import {pickTerrainAt} from '../selection/terrain_surface';
|
|
21
|
+
import type {TerrainSurface, TerrainSurfaceHit} from '../selection/terrain_surface';
|
|
22
|
+
import {normalizeTerrainDraping, type TerrainDrapingOptions, type TerrainDrapingSnapshot} from '../procedures/terrain-draping';
|
|
23
|
+
import {PROJECTION_CONSTANTS} from './projection_math';
|
|
24
|
+
import {DrapedTerrainSurfaceSnapshot, type DrapedTerrainQueryEntry} from '../selection/draped-terrain-surface';
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
interface FrameOptions {renderViewId?: string}
|
|
28
|
+
|
|
29
|
+
/** Minimal scene surface needed by the host-driven renderer. */
|
|
30
|
+
interface RendererScene {
|
|
31
|
+
/** Immutable worker input, separate from vector source residency. */
|
|
32
|
+
terrain?: TerrainDrapingSnapshot;
|
|
33
|
+
/** GPU-only multiplier; source heights and worker data remain physical. */
|
|
34
|
+
terrainExaggeration: number;
|
|
35
|
+
/** One shared morph timestamp for all eyes and collision in this frame. */
|
|
36
|
+
terrainFrameTime?: number;
|
|
37
|
+
/** Last atomically admitted mesh generation, independent of pending worker configuration. */
|
|
38
|
+
terrainDisplayGeneration?: number;
|
|
39
|
+
/** Worker ribbon-width target; no DEM data is cloned when only this value changes. */
|
|
40
|
+
terrainRibbonZoom?: number;
|
|
41
|
+
/** Configured line draw groups, including roads currently suppressed by no-data. */
|
|
42
|
+
terrainRibbonStyles?: boolean;
|
|
43
|
+
/** Schedule a viewport-local feature query for a subsequent render. */
|
|
44
|
+
getFeatureAt(pixel: {x: number; y: number}, options: {radius?: number; renderViewId?: string; width?: number; height?: number}): Promise<FeatureSelectionResult | undefined>;
|
|
45
|
+
/** Switch only selection ownership; shared workers/features remain unchanged. */
|
|
46
|
+
setFeatureSelectionView?(id: string, retainedIds: readonly string[]): void;
|
|
47
|
+
/** Shared source/style tile ownership across every eye. */
|
|
48
|
+
tile_manager: {getResourceStatistics(): TileResourceStatistics; updateProjectedLabels(frame: HostFrame, clockwiseRotation: boolean, terrainSurface?: DrapedTerrainSurfaceSnapshot): void;
|
|
49
|
+
getTerrainDrapingStatistics(terrain?: TerrainDrapingSnapshot): import('../procedures/terrain-draping').TerrainDrapingStatistics;
|
|
50
|
+
getDrapedTerrainQueryEntries(time: number): DrapedTerrainQueryEntry[]} | null;
|
|
51
|
+
view: View;
|
|
52
|
+
config: {animated?: boolean; scene?: {cpu_projection?: unknown}} | null;
|
|
53
|
+
animated: boolean;
|
|
54
|
+
dirty: boolean;
|
|
55
|
+
start_time: number;
|
|
56
|
+
host_animation_time: number | null;
|
|
57
|
+
subscribe(listeners: SceneListeners): unknown;
|
|
58
|
+
load(config: SceneDefinition | null, options: SceneLoadOptions): unknown;
|
|
59
|
+
/** Rebuild styled meshes without replacing source procedures or worker ownership. */
|
|
60
|
+
rebuild(options: {preserveTileCache: boolean; preserveTime?: boolean; terrainRibbonZoom?: number | null}): Promise<unknown>;
|
|
61
|
+
/** Retrieves current source and TileJSON provider credits for the host UI. */
|
|
62
|
+
getAttributions(): Promise<string[]>;
|
|
63
|
+
/** Normalized source capabilities, including worker-owned archive metadata. */
|
|
64
|
+
getSourceMetadata(): Promise<Record<string, TangramTileSourceMetadata>>;
|
|
65
|
+
/** Shared built-in load queue diagnostics from each worker, independent of mesh builds. */
|
|
66
|
+
getTileSourceStatistics(): Promise<TileSourceStatistics[]>;
|
|
67
|
+
/** Host-side kernel work, absent for the worker-local implementation. */
|
|
68
|
+
getProjectionEngineStatistics(): ProjectionExecutionStatistics | undefined;
|
|
69
|
+
/** Returns detached lighting descriptors for the currently active eye. */
|
|
70
|
+
getLumaLightDefinitions(): TangramLightMapping[];
|
|
71
|
+
resizeMap(width: number, height: number): void;
|
|
72
|
+
setCameraMatrices(camera: import('../types').HostCamera): void;
|
|
73
|
+
updateScene(options: {renderPass?: import('@luma.gl/core').RenderPass | null}): boolean;
|
|
74
|
+
processTasks(): void;
|
|
75
|
+
requestRedraw(): void;
|
|
76
|
+
destroy(): unknown;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Embeddable Tangram renderer driven by a host-provided frame.
|
|
81
|
+
*
|
|
82
|
+
* Unlike the standalone Scene path, Renderer does not create an animation loop
|
|
83
|
+
* or derive camera matrices. The host owns frame scheduling and supplies an
|
|
84
|
+
* active render pass together with geographic view and camera state.
|
|
85
|
+
*/
|
|
86
|
+
export default class Renderer {
|
|
87
|
+
|
|
88
|
+
gpuBackend: LumaDeviceRenderer | null;
|
|
89
|
+
device_renderer: LumaDeviceRenderer | null;
|
|
90
|
+
scene: RendererScene;
|
|
91
|
+
/** A destroyed scene no longer owns a tile manager. */
|
|
92
|
+
private get activeTileManager(): NonNullable<RendererScene['tile_manager']> {
|
|
93
|
+
if (!this.scene.tile_manager) throw new Error('Renderer scene tile manager has been destroyed');
|
|
94
|
+
return this.scene.tile_manager;
|
|
95
|
+
}
|
|
96
|
+
host_frame: HostFrame | null;
|
|
97
|
+
active_render_view_id: string | null;
|
|
98
|
+
private animationFrame: unknown = null;
|
|
99
|
+
private readonly submittedViews = new Set<string>();
|
|
100
|
+
/** One cooperative hierarchy warm-up, shared across eyes and cancelled on surface replacement. */
|
|
101
|
+
private terrainQueryPreparation?: {snapshot: DrapedTerrainSurfaceSnapshot; steps: Generator<void, void, void>};
|
|
102
|
+
/** Internal settled surface identity keeps terrain visibility caches warm without changing public frame timestamps. */
|
|
103
|
+
private annotationTerrainSurface?: DrapedTerrainSurfaceSnapshot;
|
|
104
|
+
/** Serialize projection rebuilds so rapid selector changes cannot publish stale meshes last. */
|
|
105
|
+
private projectionUpdate: Promise<void> = Promise.resolve();
|
|
106
|
+
/** Failed worker geometry must be rebuilt even when restoring the prior options. */
|
|
107
|
+
private projectionNeedsRebuild = false;
|
|
108
|
+
/** Terrain updates serialize so worker geometry cannot commit obsolete heights last. */
|
|
109
|
+
private terrainUpdate: Promise<void> = Promise.resolve();
|
|
110
|
+
/** Only the latest queued snapshot is retained while an active worker rebuild drains. */
|
|
111
|
+
private pendingTerrain?: TerrainDrapingSnapshot;
|
|
112
|
+
/** Automatically morph from the last admitted field, not superseded host requests. */
|
|
113
|
+
private pendingTerrainUsesPrevious = false;
|
|
114
|
+
/** Monotonic request identity for superseded queued terrain updates. */
|
|
115
|
+
private terrainRevision = 0;
|
|
116
|
+
/** A failed recovery cannot expose a mixture of incompatible worker generations. */
|
|
117
|
+
private terrainFailed = false;
|
|
118
|
+
/** Old display feature IDs cannot be queried while workers replace their selection tables. */
|
|
119
|
+
private terrainUpdating = false;
|
|
120
|
+
/** At most one asynchronous width rebuild; every eye shares the latest logical view request. */
|
|
121
|
+
private terrainRibbonScheduled = false;
|
|
122
|
+
/** Latest view zoom, coalesced while worker geometry is in flight. */
|
|
123
|
+
private requestedTerrainRibbonZoom?: number;
|
|
124
|
+
/** Width target whose entire mesh generation has committed. */
|
|
125
|
+
private admittedTerrainRibbonZoom?: number;
|
|
126
|
+
/** Do not repeatedly retry an inadmissible width until navigation or explicit terrain retry changes it. */
|
|
127
|
+
private terrainRibbonFailure?: {zoom: number; message: string};
|
|
128
|
+
/** Query ownership follows the last submitted draw, not a worker commit before the next frame. */
|
|
129
|
+
private terrainSurfaceSnapshot: DrapedTerrainSurfaceSnapshot | null = null;
|
|
130
|
+
/** Old draw buffers remain live while the worker field is staged, even with explicit previousGrids: []. */
|
|
131
|
+
private terrainDisplayMinimumHeight = 0;
|
|
132
|
+
/** Prevent queued mesh updates from acting on a released scene. */
|
|
133
|
+
private destroyed = false;
|
|
134
|
+
|
|
135
|
+
constructor(config: SceneDefinition, options: RendererOptions = {}) {
|
|
136
|
+
validateConcurrentTileLoads(options.maxConcurrentTileLoadsPerWorker);
|
|
137
|
+
validateProjectionEngine(options.projectionEngine);
|
|
138
|
+
normalizeProjectionExecutionOptions(options.projectionEngineExecution);
|
|
139
|
+
this.gpuBackend = options.device ? new LumaDeviceRenderer(options.device) : null;
|
|
140
|
+
// Retain the historical field while integrations migrate to gpuBackend.
|
|
141
|
+
this.device_renderer = this.gpuBackend;
|
|
142
|
+
const device_options = this.gpuBackend ? this.gpuBackend.getSceneOptions() : {};
|
|
143
|
+
this.scene = Scene.create(config, Object.assign({}, options, device_options, {
|
|
144
|
+
device: this.gpuBackend ? this.gpuBackend.device : options.device,
|
|
145
|
+
disableRenderLoop: true,
|
|
146
|
+
cameraMode: 'external' as const
|
|
147
|
+
}));
|
|
148
|
+
this.terrainDisplayMinimumHeight = this.scene.terrain?.minimumHeight ?? 0;
|
|
149
|
+
this.host_frame = null;
|
|
150
|
+
this.active_render_view_id = null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static create(config: SceneDefinition, options: RendererOptions = {}): Renderer {
|
|
154
|
+
return new Renderer(config, options);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
subscribe(listeners: SceneListeners): unknown {
|
|
158
|
+
return this.scene.subscribe(listeners);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
load(config: SceneDefinition | null = null, options: SceneLoadOptions = {}): unknown {
|
|
162
|
+
this.terrainSurfaceSnapshot = null;
|
|
163
|
+
this.annotationTerrainSurface = undefined;
|
|
164
|
+
this.terrainQueryPreparation?.steps.return(); this.terrainQueryPreparation = undefined;
|
|
165
|
+
return this.scene.load(config, options);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Rebuild displaced meshes on existing workers without refetching vector source data. */
|
|
169
|
+
setTerrain(options: TerrainDrapingOptions): Promise<void> {
|
|
170
|
+
if (this.destroyed || !this.scene.terrain) return Promise.reject(new Error('Terrain requires a live enabled renderer'));
|
|
171
|
+
this.pendingTerrain = normalizeTerrainDraping(options);
|
|
172
|
+
this.terrainRibbonFailure = undefined;
|
|
173
|
+
this.pendingTerrainUsesPrevious = options.previousGrids === undefined;
|
|
174
|
+
const revision = ++this.terrainRevision;
|
|
175
|
+
const update = this.terrainUpdate.then(async () => {
|
|
176
|
+
if (this.destroyed) throw new Error('Cannot update a destroyed renderer');
|
|
177
|
+
if (revision !== this.terrainRevision) return;
|
|
178
|
+
if (!this.scene.terrain) throw new Error('Terrain must be enabled at renderer creation');
|
|
179
|
+
let terrain = this.pendingTerrain;
|
|
180
|
+
if (!terrain) return;
|
|
181
|
+
this.pendingTerrain = undefined;
|
|
182
|
+
const previous = this.scene.terrain;
|
|
183
|
+
terrain = {...terrain, transitionGeneration: previous.transitionGeneration + 1};
|
|
184
|
+
if (this.pendingTerrainUsesPrevious && terrain.grids.length && previous.grids.length) {
|
|
185
|
+
const byteLength = terrain.byteLength + previous.grids.reduce((bytes, grid) => bytes + grid.heights.byteLength + grid.valid.byteLength, 0);
|
|
186
|
+
if (byteLength > terrain.maxGridBytes) throw new Error('Terrain draping current/previous grid-byte budget exceeded');
|
|
187
|
+
if (previous.grids[0].verticalDatum !== terrain.grids[0].verticalDatum) throw new Error('Terrain draping previous datum must match');
|
|
188
|
+
// Only the previous current grids survive this update. Its own older
|
|
189
|
+
// morph field must not permanently constrain future exaggeration.
|
|
190
|
+
const minimumPreviousHeight = previous.grids.reduce((minimum, grid) => {
|
|
191
|
+
for (let index = 0; index < grid.heights.length; index++) if (grid.valid[index]) minimum = Math.min(minimum, grid.heights[index]);
|
|
192
|
+
return minimum;
|
|
193
|
+
}, 0);
|
|
194
|
+
terrain = {...terrain, previousGrids: previous.grids, previousGroundMeshResolution: previous.groundMeshResolution,
|
|
195
|
+
byteLength, minimumHeight: Math.min(terrain.minimumHeight, minimumPreviousHeight)};
|
|
196
|
+
}
|
|
197
|
+
if (terrain.minimumHeight * this.scene.terrainExaggeration <= -PROJECTION_CONSTANTS.earthRadius) throw new Error('Terrain exaggeration would invert the globe radius');
|
|
198
|
+
this.scene.terrain = terrain;
|
|
199
|
+
this.terrainUpdating = true;
|
|
200
|
+
try {
|
|
201
|
+
await this.scene.rebuild({preserveTileCache: true, preserveTime: true});
|
|
202
|
+
this.terrainDisplayMinimumHeight = terrain.minimumHeight;
|
|
203
|
+
this.terrainFailed = false;
|
|
204
|
+
if (!this.destroyed) this.scene.requestRedraw();
|
|
205
|
+
} catch (error) {
|
|
206
|
+
this.scene.terrain = previous;
|
|
207
|
+
this.terrainFailed = true;
|
|
208
|
+
if (!this.destroyed) {
|
|
209
|
+
try {
|
|
210
|
+
// Restore worker configuration and partially replaced meshes, not only the host field.
|
|
211
|
+
await this.scene.rebuild({preserveTileCache: true, preserveTime: true});
|
|
212
|
+
this.terrainFailed = false;
|
|
213
|
+
if (!this.destroyed) this.scene.requestRedraw();
|
|
214
|
+
} catch (recoveryError) {
|
|
215
|
+
throw new AggregateError([error, recoveryError], 'Terrain update and recovery failed');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
throw error;
|
|
219
|
+
} finally {
|
|
220
|
+
this.terrainUpdating = false;
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
this.terrainUpdate = update.catch(() => {});
|
|
224
|
+
return update;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Re-intersect built-in ribbons at the latest host zoom on the existing serialized worker pipeline. */
|
|
228
|
+
private requestTerrainRibbonRefinement(zoom: number): void {
|
|
229
|
+
this.requestedTerrainRibbonZoom = zoom;
|
|
230
|
+
if (this.terrainRibbonScheduled || this.admittedTerrainRibbonZoom === zoom || this.terrainRibbonFailure?.zoom === zoom) return;
|
|
231
|
+
if (!this.scene.terrain?.groundMeshResolution || !this.scene.terrainRibbonStyles && !this.activeTileManager.getTerrainDrapingStatistics(this.scene.terrain).ribbonMeshes) return;
|
|
232
|
+
this.terrainRibbonScheduled = true;
|
|
233
|
+
const update = this.terrainUpdate.then(async () => {
|
|
234
|
+
if (this.destroyed || !this.scene.terrain?.groundMeshResolution) return;
|
|
235
|
+
const target = this.requestedTerrainRibbonZoom;
|
|
236
|
+
if (target === undefined || target === this.admittedTerrainRibbonZoom) return;
|
|
237
|
+
const previous = this.scene.terrainRibbonZoom;
|
|
238
|
+
this.terrainUpdating = true;
|
|
239
|
+
try {
|
|
240
|
+
const completed = await this.scene.rebuild({preserveTileCache: true, preserveTime: true, terrainRibbonZoom: target});
|
|
241
|
+
if (completed === false) return; // A newer scene request superseded this queued width; retry after that build.
|
|
242
|
+
this.admittedTerrainRibbonZoom = target;
|
|
243
|
+
this.terrainRibbonFailure = undefined;
|
|
244
|
+
this.terrainFailed = false;
|
|
245
|
+
} catch (error) {
|
|
246
|
+
this.terrainRibbonFailure = {zoom: target, message: error instanceof Error ? error.message : String(error)};
|
|
247
|
+
this.scene.terrainRibbonZoom = previous;
|
|
248
|
+
if (!this.destroyed) {
|
|
249
|
+
try {
|
|
250
|
+
const recovered = await this.scene.rebuild({preserveTileCache: true, preserveTime: true, terrainRibbonZoom: previous ?? null});
|
|
251
|
+
if (recovered === false) throw new Error('Terrain ribbon recovery was superseded');
|
|
252
|
+
}
|
|
253
|
+
catch (recoveryError) {this.terrainFailed = true; throw new AggregateError([error, recoveryError], 'Terrain ribbon update and recovery failed');}
|
|
254
|
+
}
|
|
255
|
+
} finally {this.terrainUpdating = false;}
|
|
256
|
+
}).finally(() => {
|
|
257
|
+
this.terrainRibbonScheduled = false;
|
|
258
|
+
if (!this.destroyed) this.scene.requestRedraw();
|
|
259
|
+
});
|
|
260
|
+
this.terrainUpdate = update.catch(() => {});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** Change visual relief without new source loads, mesh builds or height samples. */
|
|
264
|
+
setTerrainExaggeration(value: number): void {
|
|
265
|
+
if (this.destroyed || !this.scene.terrain) throw new Error('Terrain requires a live enabled renderer');
|
|
266
|
+
if (!Number.isFinite(value) || value < 0 || value > 1000) throw new Error('Terrain exaggeration must be in [0, 1000]');
|
|
267
|
+
if (Math.min(this.scene.terrain.minimumHeight, this.terrainDisplayMinimumHeight) * value <= -PROJECTION_CONSTANTS.earthRadius) throw new Error('Terrain exaggeration would invert the globe radius');
|
|
268
|
+
if (this.scene.terrainExaggeration !== value) {this.scene.terrainExaggeration = value; this.scene.requestRedraw();}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Inspect resident worker preparation cost without conflating source/GPU/scratch ownership. */
|
|
272
|
+
getTerrainDrapingStatistics(): import('../procedures/terrain-draping').TerrainDrapingStatistics {
|
|
273
|
+
return {...this.activeTileManager.getTerrainDrapingStatistics(this.scene.terrain),
|
|
274
|
+
...(this.scene.terrain?.groundMeshResolution ? {ribbonRefinement: {requestedZoom: this.requestedTerrainRibbonZoom,
|
|
275
|
+
admittedZoom: this.admittedTerrainRibbonZoom, pending: this.terrainRibbonScheduled, error: this.terrainRibbonFailure?.message}} : {}),
|
|
276
|
+
annotationQueries: this.annotationTerrainSurface?.getStatistics()};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** Reproject loaded ground meshes while retaining the workers, decoded tiles and source definitions. */
|
|
280
|
+
setProjectedBasemapProjection(value: ProjectedBasemapOptions): Promise<void> {
|
|
281
|
+
const projection = normalizeProjectedBasemapOptions(value);
|
|
282
|
+
const update = this.projectionUpdate.then(async () => {
|
|
283
|
+
if (this.destroyed) throw new Error('Cannot update a destroyed renderer');
|
|
284
|
+
const settings = this.scene.config?.scene;
|
|
285
|
+
if (!settings?.cpu_projection) throw new Error('Projection updates require a loaded CPU-projected scene');
|
|
286
|
+
const previous = normalizeProjectedBasemapOptions(settings.cpu_projection);
|
|
287
|
+
if (!this.projectionNeedsRebuild && JSON.stringify(previous) === JSON.stringify(projection)) return;
|
|
288
|
+
settings.cpu_projection = projection;
|
|
289
|
+
try {
|
|
290
|
+
await this.scene.rebuild({preserveTileCache: true});
|
|
291
|
+
this.projectionNeedsRebuild = false;
|
|
292
|
+
if (!this.destroyed) this.scene.requestRedraw();
|
|
293
|
+
} catch (error) {
|
|
294
|
+
this.projectionNeedsRebuild = true;
|
|
295
|
+
settings.cpu_projection = previous;
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
// A failed update must not poison later corrections.
|
|
300
|
+
this.projectionUpdate = update.catch(() => {});
|
|
301
|
+
return update;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Returns source credits without coupling the renderer to DOM, deck.gl or Leaflet controls. */
|
|
305
|
+
getAttributions(): Promise<string[]> {
|
|
306
|
+
return this.scene.getAttributions();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Query interactive draws in top-origin CSS pixels, optionally routed to a named
|
|
311
|
+
* render view or resolved from full-canvas coordinates in the current HostFrame.
|
|
312
|
+
* The host must continue rendering while this asynchronous GPU/worker query is
|
|
313
|
+
* pending. This does not implement deck.gl picking or terrain intersections.
|
|
314
|
+
*/
|
|
315
|
+
getFeatureAt(pixel: {x: number; y: number}, options: FeatureSelectionOptions = {}): Promise<FeatureSelectionResult | undefined> {
|
|
316
|
+
if (this.destroyed) return Promise.reject(new Error('Cannot query a destroyed renderer'));
|
|
317
|
+
if (this.terrainUpdating) return this.terrainUpdate.then(() => this.getFeatureAt(pixel, options));
|
|
318
|
+
if (this.terrainFailed) return Promise.reject(new Error('Terrain generation requires a successful correction'));
|
|
319
|
+
if (![pixel.x, pixel.y, options.radius ?? 0].every(Number.isFinite) || (options.radius ?? 0) < 0) {
|
|
320
|
+
return Promise.reject(new Error('Selection coordinates and non-negative radius must be finite'));
|
|
321
|
+
}
|
|
322
|
+
let resolved;
|
|
323
|
+
try {
|
|
324
|
+
if (!this.host_frame && (options.renderViewId !== undefined || options.coordinateSpace === 'canvas')) {
|
|
325
|
+
throw new Error('View-aware selection requires a HostFrame');
|
|
326
|
+
}
|
|
327
|
+
resolved = this.host_frame?.resolveSelectionPoint(pixel, options, this.active_render_view_id ?? undefined);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
return Promise.reject(error);
|
|
330
|
+
}
|
|
331
|
+
if (resolved === null) return Promise.resolve({feature: null, changed: false, pixel: {...pixel}});
|
|
332
|
+
const pending = this.scene.getFeatureAt(resolved?.pixel ?? {...pixel}, {radius: options.radius,
|
|
333
|
+
...(resolved ? {renderViewId: resolved.view.id, width: resolved.view.viewport.width, height: resolved.view.viewport.height} : {})});
|
|
334
|
+
this.scene.requestRedraw();
|
|
335
|
+
return resolved ? pending.then(result => result && {...result, pixel: {...pixel}, renderViewId: resolved.view.id}) : pending;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** Capture exact admitted ground triangles at the last submitted stereo frame time. */
|
|
339
|
+
getDrapedTerrainSurface(): DrapedTerrainSurfaceSnapshot | null {
|
|
340
|
+
return this.destroyed || this.terrainFailed ? null : this.terrainSurfaceSnapshot;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/** Query supplied terrain, or the exact admitted draped ground; never substitute a flat surface. */
|
|
344
|
+
getTerrainAt(pixel: {x: number; y: number}, surface?: TerrainSurface, options: FeatureSelectionOptions = {}): TerrainSurfaceHit | null {
|
|
345
|
+
if (this.destroyed) throw new Error('Cannot query a destroyed renderer');
|
|
346
|
+
if (!this.host_frame) throw new Error('Terrain selection requires a HostFrame');
|
|
347
|
+
const resolved = surface ?? this.getDrapedTerrainSurface();
|
|
348
|
+
return resolved ? pickTerrainAt(this.host_frame, pixel, resolved, options, this.active_render_view_id ?? undefined) : null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** Resolve source capabilities without publishing archive handles or changing source policy. */
|
|
352
|
+
getSourceMetadata(): Promise<Record<string, TangramTileSourceMetadata>> {
|
|
353
|
+
return this.scene.getSourceMetadata();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/** Inspect source procedures without confusing their slots with renderer mesh-build slots. */
|
|
357
|
+
getTileSourceStatistics(): Promise<TileSourceStatistics[]> {
|
|
358
|
+
return this.scene.getTileSourceStatistics();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/** Inspect cooperative host projection work without conflating it with source/GPU residency. */
|
|
362
|
+
getProjectionEngineStatistics(): ProjectionExecutionStatistics | undefined {
|
|
363
|
+
return this.scene.getProjectionEngineStatistics();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/** Resolve Tangram lights into luma.gl definitions, retaining non-equivalent Tangram extensions. */
|
|
367
|
+
getLumaLightDefinitions(): TangramLightMapping[] {
|
|
368
|
+
return this.scene.getLumaLightDefinitions();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/** Current build queue and completed-cache mesh residency; does not include textures or driver memory. */
|
|
372
|
+
getTileResourceStatistics(): TileResourceStatistics {
|
|
373
|
+
return this.activeTileManager.getResourceStatistics();
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Applies host-owned viewport, geographic, and camera state.
|
|
378
|
+
*/
|
|
379
|
+
setFrame(frame: unknown, {renderViewId}: FrameOptions = {}): HostFrame {
|
|
380
|
+
const host_frame = HostFrame.from(frame);
|
|
381
|
+
if (this.scene.config && Boolean(this.scene.config.scene?.cpu_projection) !== (host_frame.projection.type === 'projected')) {
|
|
382
|
+
throw new Error('CPU-projected scene meshes and HostFrame projection must match');
|
|
383
|
+
}
|
|
384
|
+
const render_view = host_frame.getRenderView(renderViewId);
|
|
385
|
+
const viewport = render_view.viewport;
|
|
386
|
+
const render_view_changed = this.active_render_view_id !== render_view.id;
|
|
387
|
+
|
|
388
|
+
this.scene.view.applyHostFrame(host_frame, () => {
|
|
389
|
+
if (this.scene.view.size.css.width !== viewport.width || this.scene.view.size.css.height !== viewport.height) {
|
|
390
|
+
this.scene.resizeMap(viewport.width, viewport.height);
|
|
391
|
+
}
|
|
392
|
+
}, () => {
|
|
393
|
+
// CPU-projected shaders bypass the tile model-view transform. Compose the
|
|
394
|
+
// host view here so rendering, collision and selection use the same camera.
|
|
395
|
+
this.scene.setCameraMatrices(host_frame.projection.type === 'projected' ? {
|
|
396
|
+
...render_view.camera, view: new Float64Array(new Matrix4()),
|
|
397
|
+
projection: new Float64Array(new Matrix4(Array.from(render_view.camera.projection))
|
|
398
|
+
.multiplyRight(Array.from(render_view.camera.view)))
|
|
399
|
+
} : render_view.camera);
|
|
400
|
+
this.host_frame = host_frame;
|
|
401
|
+
this.active_render_view_id = render_view.id;
|
|
402
|
+
});
|
|
403
|
+
if (host_frame !== this.animationFrame) {
|
|
404
|
+
this.animationFrame = host_frame;
|
|
405
|
+
this.submittedViews.clear();
|
|
406
|
+
this.scene.host_animation_time = host_frame.animationTime ?? Math.max(0, (Date.now() - this.scene.start_time) / 1000);
|
|
407
|
+
}
|
|
408
|
+
if (render_view_changed) {
|
|
409
|
+
this.scene.dirty = true;
|
|
410
|
+
}
|
|
411
|
+
this.scene.setFeatureSelectionView?.(render_view.id, host_frame.renderViews.map(view => view.id));
|
|
412
|
+
return host_frame;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Updates and draws Tangram into a host-owned render pass.
|
|
417
|
+
*/
|
|
418
|
+
render({frame, renderPass = null, renderViewId, force = false}: Omit<RenderOptions, 'frame'> & {frame?: HostFrame | RenderOptions['frame']} = {}): boolean {
|
|
419
|
+
if (this.destroyed || this.terrainFailed) return false;
|
|
420
|
+
if (frame) {
|
|
421
|
+
this.setFrame(frame, { renderViewId });
|
|
422
|
+
}
|
|
423
|
+
else if (renderViewId) {
|
|
424
|
+
if (!this.host_frame) {
|
|
425
|
+
throw new Error('Renderer requires a HostFrame before selecting a render view');
|
|
426
|
+
}
|
|
427
|
+
this.setFrame(this.host_frame, { renderViewId });
|
|
428
|
+
}
|
|
429
|
+
if (this.host_frame && this.active_render_view_id) {
|
|
430
|
+
// Loading/reloading clears scene selection ownership, not the retained host frame.
|
|
431
|
+
this.scene.setFeatureSelectionView?.(this.active_render_view_id,
|
|
432
|
+
this.host_frame.renderViews.map(view => view.id));
|
|
433
|
+
}
|
|
434
|
+
if (force) {
|
|
435
|
+
this.scene.dirty = true;
|
|
436
|
+
}
|
|
437
|
+
// Submitting an eye again starts the next logical frame, even when its previous draw was skipped.
|
|
438
|
+
if (this.active_render_view_id && this.submittedViews.has(this.active_render_view_id)) {
|
|
439
|
+
this.submittedViews.clear();
|
|
440
|
+
if (this.host_frame) {
|
|
441
|
+
this.scene.host_animation_time = this.host_frame.animationTime ?? Math.max(0, (Date.now() - this.scene.start_time) / 1000);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
if (this.host_frame) {
|
|
445
|
+
if (!this.submittedViews.size) {
|
|
446
|
+
this.requestTerrainRibbonRefinement(this.host_frame.geographicAnchor.zoom);
|
|
447
|
+
this.scene.terrainFrameTime = performance.now();
|
|
448
|
+
this.advanceTerrainQueryPreparation();
|
|
449
|
+
}
|
|
450
|
+
let surface: DrapedTerrainSurfaceSnapshot | undefined;
|
|
451
|
+
if (this.scene.terrain?.occludeAnnotations && this.host_frame.projection.type !== 'projected') {
|
|
452
|
+
const entries = this.activeTileManager.getDrapedTerrainQueryEntries(this.scene.terrainFrameTime ?? performance.now());
|
|
453
|
+
const candidate = new DrapedTerrainSurfaceSnapshot(this.host_frame.projection.type, entries, this.scene.terrainDisplayGeneration ?? 0,
|
|
454
|
+
this.scene.terrainFrameTime ?? performance.now(), this.scene.terrainExaggeration, this.scene.terrain.maxQueryIndexBytes, this.scene.terrain.maxProjectedQueryBytes);
|
|
455
|
+
if (this.annotationTerrainSurface?.displayKey !== candidate.displayKey) this.annotationTerrainSurface = candidate;
|
|
456
|
+
surface = this.annotationTerrainSurface;
|
|
457
|
+
}
|
|
458
|
+
else this.annotationTerrainSurface = undefined;
|
|
459
|
+
this.activeTileManager.updateProjectedLabels(this.host_frame, this.gpuBackend?.device.type !== 'webgpu', surface);
|
|
460
|
+
}
|
|
461
|
+
const rendered = this.scene.updateScene({ renderPass });
|
|
462
|
+
if (rendered && this.scene.terrain && this.host_frame && this.host_frame.projection.type !== 'projected') {
|
|
463
|
+
const time = this.scene.terrainFrameTime ?? performance.now();
|
|
464
|
+
const entries = this.activeTileManager.getDrapedTerrainQueryEntries(time);
|
|
465
|
+
this.terrainSurfaceSnapshot = new DrapedTerrainSurfaceSnapshot(this.host_frame.projection.type, entries, this.scene.terrainDisplayGeneration ?? 0, time, this.scene.terrainExaggeration, this.scene.terrain.maxQueryIndexBytes, this.scene.terrain.maxProjectedQueryBytes);
|
|
466
|
+
}
|
|
467
|
+
if (this.submittedViews.size === 0) {
|
|
468
|
+
this.scene.processTasks();
|
|
469
|
+
}
|
|
470
|
+
if (this.active_render_view_id) {
|
|
471
|
+
this.submittedViews.add(this.active_render_view_id);
|
|
472
|
+
}
|
|
473
|
+
if (rendered && this.scene.config && this.scene.animated) {
|
|
474
|
+
this.scene.requestRedraw();
|
|
475
|
+
}
|
|
476
|
+
return rendered;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/** Progress exact settled-query acceleration without charging a second stereo eye another slice. */
|
|
480
|
+
private advanceTerrainQueryPreparation(): void {
|
|
481
|
+
const snapshot = this.annotationTerrainSurface ?? this.terrainSurfaceSnapshot;
|
|
482
|
+
const budget = this.scene.terrain?.queryPreparationBudgetMs ?? 0;
|
|
483
|
+
if (!snapshot || !budget) {
|
|
484
|
+
this.terrainQueryPreparation?.steps.return(); this.terrainQueryPreparation = undefined;
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
if (this.terrainQueryPreparation?.snapshot.displayKey !== snapshot.displayKey) {
|
|
488
|
+
this.terrainQueryPreparation?.steps.return();
|
|
489
|
+
this.terrainQueryPreparation = {snapshot, steps: snapshot.prepareQueryIndexSteps()};
|
|
490
|
+
}
|
|
491
|
+
const preparation = this.terrainQueryPreparation;
|
|
492
|
+
const started = performance.now();
|
|
493
|
+
do {
|
|
494
|
+
if (preparation.steps.next().done) {this.terrainQueryPreparation = undefined; return;}
|
|
495
|
+
} while (performance.now() - started < budget);
|
|
496
|
+
this.scene.requestRedraw();
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
destroy() {
|
|
500
|
+
this.annotationTerrainSurface = undefined;
|
|
501
|
+
this.terrainQueryPreparation?.steps.return(); this.terrainQueryPreparation = undefined;
|
|
502
|
+
this.destroyed = true;
|
|
503
|
+
this.pendingTerrain = undefined;
|
|
504
|
+
this.terrainSurfaceSnapshot = null;
|
|
505
|
+
this.terrainRevision++;
|
|
506
|
+
try {
|
|
507
|
+
return this.scene.destroy();
|
|
508
|
+
}
|
|
509
|
+
finally {
|
|
510
|
+
if (this.gpuBackend) {
|
|
511
|
+
this.gpuBackend.destroy();
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
}
|