@itwin/core-frontend
Version:
iTwin.js frontend components
145 lines • 7.85 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module WebGL
*/
import { assert, dispose } from "@itwin/core-bentley";
import { Matrix4d, Plane3dByOriginAndUnitNormal, Point3d, Range3d, Vector3d } from "@itwin/core-geometry";
import { ColorDef, FrustumPlanes, RenderTexture, TextureTransparency } from "@itwin/core-common";
import { GraphicsCollectorDrawArgs } from "../../../tile/internal";
import { FeatureSymbology } from "../../../render/FeatureSymbology";
import { BatchState } from "./BatchState";
import { BranchStack } from "./BranchStack";
import { FrameBuffer } from "./FrameBuffer";
import { GL } from "./GL";
import { PlanarTextureProjection } from "./PlanarTextureProjection";
import { RenderCommands } from "./RenderCommands";
import { System } from "./System";
import { Texture, TextureHandle } from "./Texture";
import { TextureDrape } from "./TextureDrape";
/** @internal */
export class BackgroundMapDrape extends TextureDrape {
_fbo;
_graphics = [];
_frustum;
_width = 0;
_height = 0;
_mapTree;
_drapedTree;
static _postProjectionMatrix = Matrix4d.createRowValues(0, 1, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 1);
_debugFrustum;
_debugFrustumGraphic = undefined;
_symbologyOverrides = new FeatureSymbology.Overrides();
_bgColor = ColorDef.from(0, 0, 0, 255);
_plane = Plane3dByOriginAndUnitNormal.create(Point3d.createZero(), Vector3d.create(0, 0, 1));
constructor(drapedTree, mapTree) {
super();
this._drapedTree = drapedTree;
this._mapTree = mapTree;
}
get isDisposed() { return super.isDisposed && undefined === this._fbo; }
[Symbol.dispose]() {
super[Symbol.dispose]();
this._fbo = dispose(this._fbo);
}
addGraphic(graphic) {
this._graphics.push(graphic);
}
static create(draped, map) {
return new BackgroundMapDrape(draped, map);
}
collectGraphics(context) {
this._graphics.length = 0;
if (undefined === context.viewingSpace)
return;
const viewState = context.viewingSpace.view;
if (undefined === viewState)
return;
const tileTree = this._mapTree.treeOwner.load();
if (undefined === tileTree || !this._mapTree.layerRefHandler.initializeLayers(context))
return;
const requiredWidth = 2 * Math.max(context.target.viewRect.width, context.target.viewRect.height); // TBD - Size to textured area.
const requiredHeight = requiredWidth;
if (requiredWidth !== this._width || requiredHeight !== this._height)
this[Symbol.dispose]();
this._width = requiredWidth;
this._height = requiredHeight;
const targetTree = this._drapedTree.treeOwner.tileTree;
const args = this._drapedTree.createDrawArgs(context);
if (!targetTree || !args)
return;
const targetTiles = targetTree.selectTiles(args);
const projection = PlanarTextureProjection.computePlanarTextureProjection(this._plane, context, { tiles: targetTiles, location: args.location }, [this._mapTree], viewState, this._width, this._height, Range3d.createNull());
if (!projection.textureFrustum || !projection.projectionMatrix || !projection.worldToViewMap)
return;
this._frustum = projection.textureFrustum;
this._debugFrustum = projection.debugFrustum;
this._projectionMatrix = projection.projectionMatrix;
const drawArgs = GraphicsCollectorDrawArgs.create(context, this, this._mapTree, FrustumPlanes.fromFrustum(this._frustum), projection.worldToViewMap);
if (undefined !== drawArgs)
tileTree.draw(drawArgs);
if (context.target.debugControl && context.target.debugControl.displayDrapeFrustum) {
this._debugFrustumGraphic = dispose(this._debugFrustumGraphic);
const builder = context.createSceneGraphicBuilder();
builder.setSymbology(ColorDef.green, ColorDef.green, 1);
builder.addFrustum(context.viewingSpace.getFrustum());
builder.setSymbology(ColorDef.red, ColorDef.red, 1);
builder.addFrustum(this._debugFrustum);
builder.setSymbology(ColorDef.white, ColorDef.white, 1);
builder.addFrustum(this._frustum);
this._debugFrustumGraphic = builder.finish();
}
}
draw(target) {
if (undefined !== this._debugFrustumGraphic)
target.graphics.foreground.push(this._debugFrustumGraphic);
if (undefined === this._frustum || this._graphics.length === 0)
return;
if (undefined === this._fbo) {
const colorTextureHandle = TextureHandle.createForAttachment(this._width, this._height, GL.Texture.Format.Rgba, GL.Texture.DataType.UnsignedByte);
if (undefined === colorTextureHandle) {
assert(false, "Failed to create planar texture");
return;
}
this._texture = new Texture({ ownership: "external", type: RenderTexture.Type.TileSection, handle: colorTextureHandle, transparency: TextureTransparency.Opaque });
this._fbo = FrameBuffer.create([colorTextureHandle]);
}
if (undefined === this._fbo) {
assert(false, "unable to create frame buffer object");
return;
}
System.instance.glTimer.beginOperation("Terrain Projection");
const prevState = System.instance.currentRenderState.clone();
System.instance.context.viewport(0, 0, this._width, this._height);
const prevPlan = target.plan;
const drawingParams = PlanarTextureProjection.getTextureDrawingParams(target);
const stack = new BranchStack();
stack.changeRenderPlan(drawingParams.viewFlags, prevPlan.is3d, prevPlan.hline, prevPlan.contours);
stack.setSymbologyOverrides(this._symbologyOverrides);
const batchState = new BatchState(stack);
System.instance.applyRenderState(drawingParams.state);
target.uniforms.style.changeBackgroundColor(this._bgColor); // Avoid white on white reversal. Will be reset below in changeRenderPlan().
target.changeFrustum(this._frustum, this._frustum.getFraction(), true);
const prevProjMatrix = target.uniforms.frustum.projectionMatrix;
target.uniforms.frustum.changeProjectionMatrix(BackgroundMapDrape._postProjectionMatrix.multiplyMatrixMatrix(prevProjMatrix));
target.uniforms.branch.pushState(stack.top);
const renderCommands = new RenderCommands(target, stack, batchState);
renderCommands.addGraphics(this._graphics, 5 /* RenderPass.OpaqueGeneral */);
const system = System.instance;
const gl = system.context;
system.frameBufferStack.execute(this._fbo, true, false, () => {
gl.clearColor(0, 0, 0, 0);
gl.clear(GL.BufferBit.Color);
target.techniques.execute(target, renderCommands.getCommands(5 /* RenderPass.OpaqueGeneral */), 19 /* RenderPass.PlanarClassification */); // Draw these with RenderPass.PlanarClassification (rather than Opaque...) so that the pick ordering is avoided.
});
target.uniforms.branch.pop();
batchState.reset(); // Reset the batch Ids...
target.changeRenderPlan(prevPlan);
system.applyRenderState(prevState);
gl.viewport(0, 0, target.viewRect.width, target.viewRect.height); // Restore viewport
system.glTimer.endOperation();
}
}
//# sourceMappingURL=BackgroundMapDrape.js.map