UNPKG

@itwin/core-frontend

Version:
416 lines • 19 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Rendering */ Object.defineProperty(exports, "__esModule", { value: true }); exports.SceneContext = exports.DecorateContext = exports.DynamicsContext = exports.RenderContext = void 0; const core_bentley_1 = require("@itwin/core-bentley"); const core_common_1 = require("@itwin/core-common"); const DecorationsCache_1 = require("./DecorationsCache"); const IModelApp_1 = require("./IModelApp"); const Scene_1 = require("./render/Scene"); const internal_1 = require("./tile/internal"); const Viewport_1 = require("./Viewport"); const GraphicType_1 = require("./common/render/GraphicType"); /** Provides context for producing [[RenderGraphic]]s for drawing within a [[Viewport]]. * @public * @extensions */ class RenderContext { /** ViewFlags extracted from the context's [[Viewport]]. */ viewFlags; _viewport; /** Frustum extracted from the context's [[Viewport]]. */ frustum; /** Frustum planes extracted from the context's [[Viewport]]. */ frustumPlanes; constructor(vp, frustum) { this._viewport = vp; this.viewFlags = vp.viewFlags; this.frustum = frustum ? frustum : vp.getFrustum(); this.frustumPlanes = core_common_1.FrustumPlanes.fromFrustum(this.frustum); } /** Given a point in world coordinates, determine approximately how many pixels it occupies on screen based on this context's frustum. */ getPixelSizeAtPoint(inPoint) { return this.viewport.viewingSpace.getPixelSizeAtPoint(inPoint); } /** The [[Viewport]] associated with this context. */ get viewport() { return this._viewport; } /** The [[RenderSystem]] being used to produce graphics for this context. */ get renderSystem() { return this.target.renderSystem; } /** @internal */ get target() { return this.viewport.target; } /** @internal */ _createGraphicBuilder(options) { return this.target.createGraphicBuilder({ ...options, viewport: this.viewport }); } /** Create a builder for creating a [[GraphicType.Scene]] [[RenderGraphic]] for rendering within this context's [[Viewport]]. * @param transform the local-to-world transform in which the builder's geometry is to be defined. * @returns A builder for creating a [[GraphicType.Scene]] [[RenderGraphic]] for rendering within this context's [[Viewport]]. */ createSceneGraphicBuilder(transform) { return this._createGraphicBuilder({ type: GraphicType_1.GraphicType.Scene, placement: transform }); } /** Create a graphic from a [[GraphicBranch]]. */ createGraphicBranch(branch, location, opts) { return this.target.renderSystem.createGraphicBranch(branch, location, opts); } /** Create a [[RenderGraphic]] which groups a set of graphics into a node in a scene graph, applying to each a transform and optional clip volume and symbology overrides. * @param branch Contains the group of graphics and the symbology overrides. * @param location the local-to-world transform applied to the grouped graphics. * @returns A RenderGraphic suitable for drawing the scene graph node within this context's [[Viewport]]. * @see [[RenderSystem.createBranch]] */ createBranch(branch, location) { return this.createGraphicBranch(branch, location); } /** Given the size of a logical pixel in meters, convert it to the size of a physical pixel in meters, if [[RenderSystem.dpiAwareLOD]] is `true`. * Used when computing LOD for graphics. * @internal */ adjustPixelSizeForLOD(cssPixelSize) { return this.viewport.target.adjustPixelSizeForLOD(cssPixelSize); } } exports.RenderContext = RenderContext; /** Provides context for an [[InteractiveTool]] to display decorations representing its current state. * @see [[InteractiveTool.onDynamicFrame]] * @public */ class DynamicsContext extends RenderContext { _foreground; _overlay; /** Add a graphic to the list of dynamic graphics to be drawn in this context's [[Viewport]]. * These graphics are drawn as [[GraphicType.Scene]]. * @see [[addOverlay]] to add a graphic to be drawn as an overlay instead. */ addGraphic(graphic) { this.add(graphic, false); } /** Add a graphic to the list of dynamic graphics to be drawn in this context's [[Viewport]]. * These graphics are drawn as part of the viewport's scene as described by [[GraphicType.Scene]], except * that they always draw on top of other graphics as with [[GraphicType.WorldOverlay]]. * @see [[addGraphic]] to add an ordinary scene graphic instead. */ addOverlay(graphic) { this.add(graphic, true); } /** @internal */ add(graphic, isOverlay) { const key = isOverlay ? "_overlay" : "_foreground"; const list = this[key] ?? (this[key] = []); list.push(graphic); } /** @internal */ changeDynamics() { this.viewport.changeDynamics(this._foreground, this._overlay); } /** Create a builder for producing a [[RenderGraphic]] appropriate for rendering within this context's [[Viewport]]. * @param options Options describing how to create the builder. * @returns A builder that produces a [[RenderGraphic]]. */ createGraphic(options) { return this._createGraphicBuilder(options); } } exports.DynamicsContext = DynamicsContext; /** Provides context for a [[ViewportDecorator]] to add [[Decorations]] to be rendered within a [[Viewport]]. * @public * @extensions */ class DecorateContext extends RenderContext { _decorations; _cache; _curCacheableDecorator; /** The [[ScreenViewport]] in which this context's [[Decorations]] will be drawn. */ get viewport() { return super.viewport; } /** @internal */ constructor(vp, decorations, cache) { super(vp); this._decorations = decorations; this._cache = cache; } /** Create a new DecorateContext. * @param args Describes the inputs to the context. * @note Typically the [[ScreenViewport]] takes care of creating the context for you. * @public */ static create(args) { return new DecorateContext(args.viewport, args.output, args.cache ?? new DecorationsCache_1.DecorationsCache()); } /** Create a builder for creating a [[RenderGraphic]] of the specified type appropriate for rendering within this context's [[Viewport]]. * @param type The type of builder to create. * @param transform the local-to-world transform in which the builder's geometry is to be defined. * @param id If the decoration is to be pickable, a unique identifier to associate with the resultant [[RenderGraphic]]. * @returns A builder for creating a [[RenderGraphic]] of the specified type appropriate for rendering within this context's [[Viewport]]. * @see [[IModelConnection.transientIds]] for obtaining an ID for a pickable decoration. * @see [[createGraphic]] for more options. */ createGraphicBuilder(type, transform, id) { return this.createGraphic({ type, placement: transform, pickable: undefined !== id ? { id } : undefined }); } /** Create a builder for producing a [[RenderGraphic]] appropriate for rendering within this context's [[Viewport]]. * @param options Options describing how to create the builder. * @returns A builder that produces a [[RenderGraphic]]. */ createGraphic(options) { return this._createGraphicBuilder(options); } /** @internal */ addFromDecorator(decorator) { (0, core_bentley_1.assert)(undefined === this._curCacheableDecorator); try { if (decorator.useCachedDecorations) { const cached = this._cache.get(decorator); if (cached) { this.restoreCache(cached); return; } this._curCacheableDecorator = decorator; } decorator.decorate(this); } finally { this._curCacheableDecorator = undefined; } } /** Restores decorations onto this context from the specified array of cached decorations. */ restoreCache(cachedDecorations) { cachedDecorations.forEach((cachedDecoration) => { switch (cachedDecoration.type) { case "graphic": this.addDecoration(cachedDecoration.graphicType, cachedDecoration.graphicOwner); break; case "canvas": this.addCanvasDecoration(cachedDecoration.canvasDecoration, cachedDecoration.atFront); break; case "html": this.addHtmlDecoration(cachedDecoration.htmlElement); break; } }); } _appendToCache(decoration) { (0, core_bentley_1.assert)(undefined !== this._curCacheableDecorator); this._cache.add(this._curCacheableDecorator, decoration); } /** Calls [[GraphicBuilder.finish]] on the supplied builder to obtain a [[RenderGraphic]], then adds the graphic to the appropriate list of * [[Decorations]]. * @param builder The builder from which to extract the graphic. * @note The builder should not be used after calling this method. */ addDecorationFromBuilder(builder) { this.addDecoration(builder.type, builder.finish()); } /** Adds a graphic to the set of [[Decorations]] to be drawn in this context's [[ScreenViewport]]. * @param The type of the graphic, which determines to which list of decorations it is added. * @param decoration The decoration graphic to add. * @note The type must match the type with which the [[RenderGraphic]]'s [[GraphicBuilder]] was constructed. * @see [[DecorateContext.addDecorationFromBuilder]] for a more convenient API. */ addDecoration(type, decoration) { if (this._curCacheableDecorator) { const graphicOwner = this.target.renderSystem.createGraphicOwner(decoration); this._appendToCache({ type: "graphic", graphicOwner, graphicType: type }); decoration = graphicOwner; } switch (type) { case GraphicType_1.GraphicType.Scene: if (undefined === this._decorations.normal) this._decorations.normal = []; this._decorations.normal.push(decoration); break; case GraphicType_1.GraphicType.WorldDecoration: if (!this._decorations.world) this._decorations.world = []; this._decorations.world.push(decoration); break; case GraphicType_1.GraphicType.WorldOverlay: if (!this._decorations.worldOverlay) this._decorations.worldOverlay = []; this._decorations.worldOverlay.push(decoration); break; case GraphicType_1.GraphicType.ViewOverlay: if (!this._decorations.viewOverlay) this._decorations.viewOverlay = []; this._decorations.viewOverlay.push(decoration); break; case GraphicType_1.GraphicType.ViewBackground: this.setViewBackground(decoration); break; } } /** Add a [[CanvasDecoration]] to be drawn in this context's [[ScreenViewport]]. */ addCanvasDecoration(decoration, atFront = false) { if (this._curCacheableDecorator) this._appendToCache({ type: "canvas", canvasDecoration: decoration, atFront }); if (undefined === this._decorations.canvasDecorations) this._decorations.canvasDecorations = []; const list = this._decorations.canvasDecorations; if (0 === list.length || true === atFront) list.push(decoration); else list.unshift(decoration); } /** Add an HTMLElement to be drawn as a decoration in this context's [[ScreenViewport]]. */ addHtmlDecoration(decoration) { if (this._curCacheableDecorator) this._appendToCache({ type: "html", htmlElement: decoration }); // an element decoration being added might already be on the decorationDiv, just marked for removal if (decoration[Viewport_1.ELEMENT_MARKED_FOR_REMOVAL]) { decoration[Viewport_1.ELEMENT_MARKED_FOR_REMOVAL] = false; } else if (decoration.parentElement !== this.viewport.decorationDiv) { this.viewport.decorationDiv.appendChild(decoration); } } /** @internal */ drawStandardGrid(gridOrigin, rMatrix, spacing, gridsPerRef, _isoGrid = false, _fixedRepetitions) { const vp = this.viewport; if (vp.viewingGlobe) return; const color = vp.getContrastToBackgroundColor(); const planarGrid = this.viewport.target.renderSystem.createPlanarGrid(vp.getFrustum(), { origin: gridOrigin, rMatrix, spacing, gridsPerRef, color }); if (planarGrid) { this.addDecoration(GraphicType_1.GraphicType.WorldDecoration, planarGrid); } } /** Display skyBox graphic that encompasses entire scene and rotates with camera. * @see [[RenderSystem.createSkyBox]]. */ setSkyBox(graphic) { this._decorations.skyBox = graphic; } /** Set the graphic to be displayed behind all other geometry as the background of this context's [[ScreenViewport]]. */ setViewBackground(graphic) { this._decorations.viewBackground = graphic; } } exports.DecorateContext = DecorateContext; /** Context used to create the scene to be drawn in a [[Viewport]]. The scene consists of a set of [[RenderGraphic]]s produced by the * [[TileTree]]s visible within the viewport. Creating the scene may result in the enqueueing of requests for [[Tile]] content which * should be displayed in the viewport but are not yet loaded. * @public */ class SceneContext extends RenderContext { _missingChildTiles = false; /** The graphics comprising the scene. */ scene = new Scene_1.Scene(); /** @internal */ missingTiles = new Set(); /** @internal */ markChildrenLoading() { this._missingChildTiles = true; } /** @internal */ get hasMissingTiles() { return this._missingChildTiles || this.missingTiles.size > 0; } _viewingSpace; _graphicType = internal_1.TileGraphicType.Scene; constructor(vp, frustum) { super(vp, frustum); } /** The viewed volume containing the scene. */ get viewingSpace() { return undefined !== this._viewingSpace ? this._viewingSpace : this.viewport.viewingSpace; } /** @internal */ get graphicType() { return this._graphicType; } /** Add the specified graphic to the scene. */ outputGraphic(graphic) { switch (this._graphicType) { case internal_1.TileGraphicType.BackgroundMap: this.backgroundGraphics.push(graphic); break; case internal_1.TileGraphicType.Overlay: this.overlayGraphics.push(graphic); break; default: this.graphics.push(graphic); break; } } /** Indicate that the specified tile is desired for the scene but is not yet ready. A request to load its contents will later be enqueued. */ insertMissingTile(tile) { switch (tile.loadStatus) { case internal_1.TileLoadStatus.NotLoaded: case internal_1.TileLoadStatus.Queued: case internal_1.TileLoadStatus.Loading: this.missingTiles.add(tile); break; } } /** @internal */ requestMissingTiles() { IModelApp_1.IModelApp.tileAdmin.requestTiles(this.viewport, this.missingTiles); } /** @internal */ addPlanarClassifier(classifiedModelId, classifierTree, planarClipMask) { // Target may have the classifier from a previous frame; if not we must create one. let classifier = this.viewport.target.getPlanarClassifier(classifiedModelId); if (undefined === classifier) classifier = this.viewport.target.createPlanarClassifier(classifierTree?.activeClassifier); // Either way, we need to collect the graphics to draw for this frame, and record that we did so. if (undefined !== classifier) { this.planarClassifiers.set(classifiedModelId, classifier); classifier.setSource(classifierTree, planarClipMask); } return classifier; } /** @internal */ getPlanarClassifierForModel(modelId) { return this.planarClassifiers.get(modelId); } /** @internal */ addBackgroundDrapedModel(drapedTreeRef, _heightRange) { const drapedTree = drapedTreeRef.treeOwner.tileTree; if (undefined === drapedTree) return undefined; const id = drapedTree.modelId; let drape = this.getTextureDrapeForModel(id); if (undefined !== drape) return drape; drape = this.viewport.target.getTextureDrape(id); if (undefined === drape && this.viewport.backgroundDrapeMap) drape = this.viewport.target.renderSystem.createBackgroundMapDrape(drapedTreeRef, this.viewport.backgroundDrapeMap); if (undefined !== drape) this.textureDrapes.set(id, drape); return drape; } /** @internal */ getTextureDrapeForModel(modelId) { return this.textureDrapes.get(modelId); } /** @internal */ withGraphicType(type, func) { const prevType = this._graphicType; this._graphicType = type; func(); this._graphicType = prevType; } /** The graphics in the scene that will be drawn with depth. */ get graphics() { return this.scene.foreground; } /** The graphics that will be drawn behind everything else in the scene. */ get backgroundGraphics() { return this.scene.background; } /** The graphics that will be drawn in front of everything else in the scene. */ get overlayGraphics() { return this.scene.overlay; } /** @internal */ get planarClassifiers() { return this.scene.planarClassifiers; } /** @internal */ get textureDrapes() { return this.scene.textureDrapes; } /** @internal */ setVolumeClassifier(classifier, modelId) { this.scene.volumeClassifier = { classifier, modelId }; } } exports.SceneContext = SceneContext; //# sourceMappingURL=ViewContext.js.map