UNPKG

@itwin/core-frontend

Version:
183 lines (181 loc) • 8.91 kB
/*--------------------------------------------------------------------------------------------- * 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 { Range2d } from "@itwin/core-geometry"; import { TerrainTexture } from "../RenderTerrain"; import { Matrix4 } from "./Matrix"; import { ModelMapLayerDrapeTarget, ModelMapLayerSettings } from "@itwin/core-common"; import { assert, dispose, disposeArray, expectDefined } from "@itwin/core-bentley"; import { System } from "./System"; export class ProjectedTexture { meshParams; targetRectangle; classifier; constructor(classifier, meshParams, targetRectangle) { this.meshParams = meshParams; this.targetRectangle = targetRectangle; this.classifier = classifier; } clone(targetRectangle) { return new ProjectedTexture(this.classifier, this.meshParams, targetRectangle.clone()); } } const scratchBytes = new Uint8Array(4); const scratchBatchBaseId = new Uint32Array(scratchBytes.buffer); const scratchRange2d = Range2d.createNull(); class LayerTextureParam { texture; _projectedTextureOrMatrix; constructor(texture, _projectedTextureOrMatrix) { this.texture = texture; this._projectedTextureOrMatrix = _projectedTextureOrMatrix; } get isProjected() { return this._projectedTextureOrMatrix instanceof ProjectedTexture; } [Symbol.dispose]() { this.texture = dispose(this.texture); } /* There are two methods of applying a texture to a reality mesh. the first member of "params" denotes which method is to be used. A value of zero indicates a standard texture and one represents a classified texture. A standard (nonprojected) texture is generated by multiplying v_textCoord by the scaling and translation packed into the first row of "matrix". A clip rectangle is packed into second row of "matrix". A "classified" reality mesh texture is used for map layers. It does not uses v_texCoord, the texture coordinates are instead generated by a projection of the model position onto the X-Y plane. We only have eye position, not model position so the matrix in this case is a real transform matrix that contains a mapping from eye to model position followed by the model to texture projection. */ getProjectionMatrix() { return this._projectedTextureOrMatrix instanceof ProjectedTexture ? this._projectedTextureOrMatrix.classifier.projectionMatrix : undefined; } getTerrainMatrix() { return this._projectedTextureOrMatrix instanceof Matrix4 ? this._projectedTextureOrMatrix : undefined; } getParams(result) { /** Entry 0 is 0 for */ if (this._projectedTextureOrMatrix instanceof ProjectedTexture) { const projectedTexture = this._projectedTextureOrMatrix; result.data[0] = 1; result.data[1] = projectedTexture.classifier.textureImageCount; result.data[2] = projectedTexture.classifier.sourceTransparency === undefined ? 1.0 : (1.0 - projectedTexture.classifier.sourceTransparency); scratchBatchBaseId[0] = projectedTexture.classifier.baseBatchId; result.data[4] = scratchBytes[0]; result.data[5] = scratchBytes[1]; result.data[6] = scratchBytes[2]; result.data[7] = scratchBytes[3]; const points = []; const meshParams = projectedTexture.meshParams; // Calculate range in the tiles local coordinates. const low = expectDefined(meshParams.tileRectangle.worldToLocal(projectedTexture.targetRectangle.low, scratchRange2d.low)); const high = expectDefined(meshParams.tileRectangle.worldToLocal(projectedTexture.targetRectangle.high, scratchRange2d.high)); points.push(meshParams.projection.getGlobalPoint(low.x, low.y, 0)); points.push(meshParams.projection.getGlobalPoint(high.x, low.y, 0)); points.push(meshParams.projection.getGlobalPoint(high.x, high.y, 0)); points.push(meshParams.projection.getGlobalPoint(low.x, high.y, 0)); for (let i = 0, j = 8; i < 4; i++) { const projectedPoint = projectedTexture.classifier.projectionMatrix.multiplyPoint3dQuietNormalize(points[i]); result.data[j++] = projectedPoint.x; result.data[j++] = projectedPoint.y; } const x0 = result.data[10] - result.data[8], y0 = result.data[11] - result.data[9]; const x1 = result.data[12] - result.data[8], y1 = result.data[13] - result.data[9]; if (x0 * y1 - x1 * y0 < 0) { const swap = ((i, j) => { const temp = result.data[i]; result.data[i] = result.data[j]; result.data[j] = temp; }); for (let i = 8, j = 14; i <= 10; i += 2, j -= 2) { swap(i, j); swap(i + 1, j + 1); } } } else { result.data[0] = 0; } return result; } } /** @internal */ export class LayerTextureParams { params; constructor(params) { this.params = params; } static create(textures) { const maxTexturesPerMesh = System.instance.maxRealityImageryLayers; assert(textures.length <= maxTexturesPerMesh); const textureParams = new Array(); for (const texture of textures) { if (texture instanceof TerrainTexture) { const terrainTexture = texture; const matrix = new Matrix4(); // Published as Mat4. assert(terrainTexture.texture !== undefined, "Texture not defined in TerrainTextureParams constructor"); matrix.data[0] = terrainTexture.translate.x; matrix.data[1] = terrainTexture.translate.y; matrix.data[2] = terrainTexture.scale.x; matrix.data[3] = terrainTexture.scale.y; if (terrainTexture.clipRectangle) { matrix.data[4] = terrainTexture.clipRectangle.low.x; matrix.data[5] = terrainTexture.clipRectangle.low.y; matrix.data[6] = terrainTexture.clipRectangle.high.x; matrix.data[7] = terrainTexture.clipRectangle.high.y; } else { matrix.data[4] = matrix.data[5] = 0; matrix.data[6] = matrix.data[7] = 1; } matrix.data[8] = (1.0 - terrainTexture.transparency); matrix.data[9] = terrainTexture.featureId; textureParams.push(new LayerTextureParam(terrainTexture.texture, matrix)); } else { const classifier = texture.classifier; textureParams.push(new LayerTextureParam(classifier.getOrCreateClassifierTexture(), texture)); } } for (let i = textures.length; i < maxTexturesPerMesh; i++) { const matrix = new Matrix4(); matrix.data[0] = matrix.data[1] = 0.0; matrix.data[2] = matrix.data[3] = 1.0; matrix.data[4] = matrix.data[5] = 1; matrix.data[6] = matrix.data[7] = -1; matrix.data[15] = 0; // Denotes a terrain texture. textureParams.push(new LayerTextureParam(undefined, matrix)); } return new LayerTextureParams(textureParams); } [Symbol.dispose]() { disposeArray(this.params); } } /** * Compares the map layers of two view states, ensuring both the number of layers * and their order remain unchanged. * Returns true if the map layers differ in count, order, or model IDs; otherwise, returns false. * * @param prevView The previous view state. * @param newView The new view state. * @returns {boolean} True if there is any difference in the model layer configuration; false otherwise. */ export function compareMapLayer(prevView, newView) { const getDrapedModelIds = (view) => view.displayStyle .getMapLayers(false) .filter((layer) => layer instanceof ModelMapLayerSettings && (layer.drapeTarget === ModelMapLayerDrapeTarget.RealityData || layer.drapeTarget === ModelMapLayerDrapeTarget.IModel)) .map(layer => layer.modelId); const prev = getDrapedModelIds(prevView); const next = getDrapedModelIds(newView); if (prev.length !== next.length) return true; for (let i = 0; i < prev.length; i++) { if (prev[i] !== next[i]) return true; } return false; } //# sourceMappingURL=MapLayerParams.js.map