UNPKG

@itwin/core-frontend

Version:
260 lines • 15.8 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. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); exports.RealityMeshGeometry = exports.RealityMeshGeometryParams = void 0; /** @packageDocumentation * @module WebGL */ const core_bentley_1 = require("@itwin/core-bentley"); const core_common_1 = require("@itwin/core-common"); const core_geometry_1 = require("@itwin/core-geometry"); const GraphicBranch_1 = require("../../../render/GraphicBranch"); const AttributeBuffers_1 = require("./AttributeBuffers"); const AttributeMap_1 = require("./AttributeMap"); const CachedGeometry_1 = require("./CachedGeometry"); const GL_1 = require("./GL"); const Primitive_1 = require("./Primitive"); const System_1 = require("./System"); const RenderTerrain_1 = require("../RenderTerrain"); const internal_1 = require("../../../tile/internal"); const MapLayerParams_1 = require("./MapLayerParams"); const scratchOverlapRange = core_geometry_1.Range2d.createNull(); /** @internal */ class RealityMeshGeometryParams extends CachedGeometry_1.IndexedGeometryParams { uvParams; featureID; normals; numBytesPerIndex; constructor(positions, normals, uvParams, indices, numIndices, numBytesPerIndex, featureID) { super(positions, indices, numIndices); this.numBytesPerIndex = numBytesPerIndex; let attrParams = AttributeMap_1.AttributeMap.findAttribute("a_uvParam", 7 /* TechniqueId.RealityMesh */, false); (0, core_bentley_1.assert)(attrParams !== undefined); this.buffers.addBuffer(uvParams, [AttributeBuffers_1.BufferParameters.create(attrParams.location, 2, GL_1.GL.DataType.UnsignedShort, false, 0, 0, false)]); this.uvParams = uvParams; if (undefined !== normals) { attrParams = AttributeMap_1.AttributeMap.findAttribute("a_norm", 7 /* TechniqueId.RealityMesh */, false); (0, core_bentley_1.assert)(attrParams !== undefined); if (normals.bytesUsed > 0) this.buffers.addBuffer(normals, [AttributeBuffers_1.BufferParameters.create(attrParams.location, 2, GL_1.GL.DataType.UnsignedByte, false, 0, 0, false)]); this.normals = normals; } this.featureID = featureID; } static createFromBuffers(posBuf, uvParamBuf, indices, normBuf, featureID) { const indBuf = AttributeBuffers_1.BufferHandle.createBuffer(GL_1.GL.Buffer.Target.ElementArrayBuffer, indices); if (undefined === indBuf) return undefined; const bytesPerIndex = indices.BYTES_PER_ELEMENT; (0, core_bentley_1.assert)(1 === bytesPerIndex || 2 === bytesPerIndex || 4 === bytesPerIndex); return new RealityMeshGeometryParams(posBuf, normBuf, uvParamBuf, indBuf, indices.length, bytesPerIndex, featureID); } static fromRealityMesh(params) { const posBuf = AttributeBuffers_1.QBufferHandle3d.create(params.positions.params, params.positions.points); const uvParamBuf = AttributeBuffers_1.QBufferHandle2d.create(params.uvs.params, params.uvs.points); const normalBuf = params.normals ? AttributeBuffers_1.BufferHandle.createArrayBuffer(params.normals) : undefined; return (undefined === posBuf || undefined === uvParamBuf) ? undefined : this.createFromBuffers(posBuf, uvParamBuf, params.indices, normalBuf, params.featureID ?? 0); } get isDisposed() { return super.isDisposed && this.uvParams.isDisposed; } get bytesUsed() { return this.positions.bytesUsed + (undefined === this.normals ? 0 : this.normals.bytesUsed) + this.uvParams.bytesUsed + this.indices.bytesUsed; } [Symbol.dispose]() { super[Symbol.dispose](); (0, core_bentley_1.dispose)(this.uvParams); } } exports.RealityMeshGeometryParams = RealityMeshGeometryParams; /** @internal */ class RealityMeshGeometry extends CachedGeometry_1.IndexedGeometry { renderGeometryType = "reality-mesh"; isInstanceable = false; noDispose = false; hasTextures; get asRealityMesh() { return this; } get isDisposed() { return this._realityMeshParams.isDisposed; } get uvQParams() { return this._realityMeshParams.uvParams.params; } get hasFeatures() { return this._realityMeshParams.featureID !== undefined; } get supportsThematicDisplay() { return true; } get overrideColorMix() { return .5; } // This could be a setting from either the mesh or the override if required. get transform() { return this._transform; } _realityMeshParams; _indexType; textureParams; _transform; baseColor; _baseIsTransparent; _isTerrain; _disableTextureDisposal; constructor(props) { super(props.realityMeshParams); this._realityMeshParams = props.realityMeshParams; this.textureParams = props.textureParams; this._transform = props.transform; this.baseColor = props.baseColor; this._baseIsTransparent = props.baseIsTransparent; this._isTerrain = props.isTerrain; this._disableTextureDisposal = props.disableTextureDisposal; this.hasTextures = undefined !== this.textureParams && this.textureParams.params.some((x) => undefined !== x.texture); const bytesPerIndex = props.realityMeshParams.numBytesPerIndex; this._indexType = 1 === bytesPerIndex ? GL_1.GL.DataType.UnsignedByte : (2 === bytesPerIndex ? GL_1.GL.DataType.UnsignedShort : GL_1.GL.DataType.UnsignedInt); } [Symbol.dispose]() { if (this.noDispose) { return; } super[Symbol.dispose](); (0, core_bentley_1.dispose)(this._realityMeshParams); if (true !== this._disableTextureDisposal) (0, core_bentley_1.dispose)(this.textureParams); } static createForTerrain(mesh, transform, disableTextureDisposal = false) { const params = RealityMeshGeometryParams.fromRealityMesh(mesh); if (!params) return undefined; return new RealityMeshGeometry({ realityMeshParams: params, transform, baseIsTransparent: false, isTerrain: true, disableTextureDisposal, }); } static createFromRealityMesh(realityMesh, disableTextureDisposal = false) { const params = RealityMeshGeometryParams.fromRealityMesh(realityMesh); if (!params) return undefined; const { texture: meshTexture, featureID } = realityMesh; const tile = realityMesh.tileData; const layerClassifiers = tile?.layerClassifiers; const texture = meshTexture ? new RenderTerrain_1.TerrainTexture(meshTexture, featureID ?? 0, core_geometry_1.Vector2d.create(1.0, -1.0), core_geometry_1.Vector2d.create(0.0, 1.0), core_geometry_1.Range2d.createXYXY(0, 0, 1, 1), 0, 0) : undefined; if (!layerClassifiers?.size || !tile) return new RealityMeshGeometry({ realityMeshParams: params, textureParams: texture ? MapLayerParams_1.LayerTextureParams.create([texture]) : undefined, baseIsTransparent: false, isTerrain: false, disableTextureDisposal }); const transformECEF = tile.ecefTransform; const tileEcefRange = transformECEF.multiplyRange(tile.range); const cartographicRange = new core_common_1.CartographicRange(tileEcefRange, transformECEF); const boundingBox = cartographicRange.getLongitudeLatitudeBoundingBox(); const mapCartoRectangle = internal_1.MapCartoRectangle.fromRadians(boundingBox.low.x, boundingBox.low.y, boundingBox.high.x, boundingBox.high.y); const corners = tile.range.corners(); const normal = core_geometry_1.Vector3d.createCrossProductToPoints(corners[0], corners[1], corners[2])?.normalize(); if (!normal) { return new RealityMeshGeometry({ realityMeshParams: params, textureParams: texture ? MapLayerParams_1.LayerTextureParams.create([texture]) : undefined, baseIsTransparent: false, isTerrain: false, disableTextureDisposal }); } const chordHeight = corners[0].distance(corners[3]) / 2; const realityPlanarTilePatch = new internal_1.PlanarTilePatch(corners, normal, chordHeight); const realityProjection = new internal_1.PlanarProjection(realityPlanarTilePatch); const realityMeshParams = { projection: realityProjection, tileRectangle: mapCartoRectangle, tileId: undefined, baseColor: undefined, baseTransparent: false, layerClassifiers }; const layerTextures = texture ? [texture] : []; layerClassifiers?.forEach((layerClassifier, layerIndex) => layerTextures[layerIndex] = new MapLayerParams_1.ProjectedTexture(layerClassifier, realityMeshParams, realityMeshParams.tileRectangle)); return new RealityMeshGeometry({ realityMeshParams: params, textureParams: layerTextures.length > 0 ? MapLayerParams_1.LayerTextureParams.create(layerTextures) : undefined, baseIsTransparent: false, isTerrain: false, disableTextureDisposal }); } getRange() { return core_geometry_1.Range3d.createXYZXYZ(this.qOrigin[0], this.qOrigin[1], this.qOrigin[2], this.qOrigin[0] + core_common_1.Quantization.rangeScale16 * this.qScale[0], this.qOrigin[1] + core_common_1.Quantization.rangeScale16 * this.qScale[1], this.qOrigin[2] + core_common_1.Quantization.rangeScale16 * this.qScale[2]); } static createGraphic(system, params, disableTextureDisposal = false) { const meshes = []; const textures = params.textures ?? []; const realityMesh = params.realityMesh; const { baseColor, baseTransparent, featureTable, tileId, layerClassifiers } = params; const texturesPerMesh = System_1.System.instance.maxRealityImageryLayers; const layers = new Array(); // Collate the textures and classifiers layers into a single array. for (const texture of textures) { const layer = layers[texture.layerIndex]; if (layer) { layer.push(texture); } else { layers[texture.layerIndex] = [texture]; } } params.layerClassifiers?.forEach((layerClassifier, layerIndex) => layers[layerIndex] = [new MapLayerParams_1.ProjectedTexture(layerClassifier, params, params.tileRectangle)]); if (layers.length < 2 && !layerClassifiers?.size && textures.length < texturesPerMesh) { // If only there is not more than one layer then we can group all of the textures into a single draw call. meshes.push(new RealityMeshGeometry({ realityMeshParams: realityMesh._realityMeshParams, textureParams: MapLayerParams_1.LayerTextureParams.create(textures), transform: realityMesh._transform, baseColor, baseIsTransparent: baseTransparent, isTerrain: realityMesh._isTerrain, disableTextureDisposal })); } else { let primaryLayer; while (primaryLayer === undefined) primaryLayer = layers.shift(); if (!primaryLayer) return undefined; for (const primaryTexture of primaryLayer) { const targetRectangle = primaryTexture.targetRectangle; const overlapMinimum = 1.0E-5 * (targetRectangle.high.x - targetRectangle.low.x) * (targetRectangle.high.y - targetRectangle.low.y); let layerTextures = [primaryTexture]; for (const secondaryLayer of layers) { if (!secondaryLayer) continue; for (const secondaryTexture of secondaryLayer) { if (secondaryTexture instanceof MapLayerParams_1.ProjectedTexture) { layerTextures.push(secondaryTexture.clone(targetRectangle)); } else { const secondaryRectangle = secondaryTexture.targetRectangle; const overlap = targetRectangle.intersect(secondaryRectangle, scratchOverlapRange); if (!overlap.isNull && (overlap.high.x - overlap.low.x) * (overlap.high.y - overlap.low.y) > overlapMinimum) { const textureRange = core_geometry_1.Range2d.createXYXY(overlap.low.x, overlap.low.y, overlap.high.x, overlap.high.y); secondaryRectangle.worldToLocal(textureRange.low, textureRange.low); secondaryRectangle.worldToLocal(textureRange.high, textureRange.high); if (secondaryTexture.clipRectangle) textureRange.intersect(secondaryTexture.clipRectangle, textureRange); if (!textureRange.isNull && textureRange) { layerTextures.push(secondaryTexture.cloneWithClip(textureRange)); } } } } } while (layerTextures.length > texturesPerMesh) { meshes.push(new RealityMeshGeometry({ realityMeshParams: realityMesh._realityMeshParams, textureParams: MapLayerParams_1.LayerTextureParams.create(layerTextures.slice(0, texturesPerMesh)), transform: realityMesh._transform, baseColor, baseIsTransparent: baseTransparent, isTerrain: realityMesh._isTerrain, disableTextureDisposal })); layerTextures = layerTextures.slice(texturesPerMesh); } meshes.push(new RealityMeshGeometry({ realityMeshParams: realityMesh._realityMeshParams, textureParams: MapLayerParams_1.LayerTextureParams.create(layerTextures), transform: realityMesh._transform, baseColor, baseIsTransparent: baseTransparent, isTerrain: realityMesh._isTerrain, disableTextureDisposal })); } } if (meshes.length === 0) return undefined; const branch = new GraphicBranch_1.GraphicBranch(true); for (const mesh of meshes) { const primitive = Primitive_1.Primitive.create(mesh); if (featureTable) { branch.add(system.createBatch(primitive, featureTable, mesh.getRange(), { tileId })); } } return system.createBranch(branch, realityMesh._transform ? realityMesh._transform : core_geometry_1.Transform.createIdentity(), { disableClipStyle: params.disableClipStyle }); } collectStatistics(stats) { this._isTerrain ? stats.addTerrain(this._realityMeshParams.bytesUsed) : stats.addRealityMesh(this._realityMeshParams.bytesUsed); if (this.textureParams?.params) { for (const param of this.textureParams.params) { if (param.texture?.bytesUsed) stats.addTexture(param.texture.bytesUsed); } } } get techniqueId() { return 7 /* TechniqueId.RealityMesh */; } getPass(target) { if (this._baseIsTransparent || (target.wantThematicDisplay && target.uniforms.thematic.wantIsoLines)) return "translucent"; return "opaque"; } get renderOrder() { return 3 /* RenderOrder.UnlitSurface */; } draw() { this._params.buffers.bind(); System_1.System.instance.context.drawElements(GL_1.GL.PrimitiveType.Triangles, this._params.numIndices, this._indexType, 0); this._params.buffers.unbind(); } } exports.RealityMeshGeometry = RealityMeshGeometry; //# sourceMappingURL=RealityMesh.js.map