UNPKG

@itwin/core-frontend

Version:
381 lines • 18.5 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 WebGL */ Object.defineProperty(exports, "__esModule", { value: true }); exports.InstancedGeometry = exports.PatternBuffers = exports.InstanceBuffers = exports.RenderInstancesImpl = exports.InstanceBuffersData = void 0; exports.isInstancedGraphicParams = isInstancedGraphicParams; const core_bentley_1 = require("@itwin/core-bentley"); const core_geometry_1 = require("@itwin/core-geometry"); const AttributeMap_1 = require("./AttributeMap"); const CachedGeometry_1 = require("./CachedGeometry"); const GL_1 = require("./GL"); const AttributeBuffers_1 = require("./AttributeBuffers"); const Matrix_1 = require("./Matrix"); const Symbols_1 = require("../../../common/internal/Symbols"); const core_common_1 = require("@itwin/core-common"); /** @internal */ function isInstancedGraphicParams(params) { return typeof params === "object" && typeof params.count === "number" && params.transforms instanceof Float32Array && params.transformCenter instanceof core_geometry_1.Point3d; } class InstanceData { numInstances; // A transform including only rtcCenter. _rtcOnlyTransform; // A transform from _rtcCenter including model matrix _rtcModelTransform; // The model matrix from which _rtcModelTransform was previously computed. If it changes, _rtcModelTransform must be recomputed. _modelMatrix = core_geometry_1.Transform.createIdentity(); constructor(numInstances, rtcCenter) { this.numInstances = numInstances; this._rtcOnlyTransform = core_geometry_1.Transform.createTranslation(rtcCenter); this._rtcModelTransform = this._rtcOnlyTransform.clone(); } getRtcModelTransform(modelMatrix) { if (!this._modelMatrix.isAlmostEqual(modelMatrix)) { modelMatrix.clone(this._modelMatrix); modelMatrix.multiplyTransformTransform(this._rtcOnlyTransform, this._rtcModelTransform); } return this._rtcModelTransform; } getRtcOnlyTransform() { return this._rtcOnlyTransform; } static _noFeatureId = new Float32Array([0, 0, 0]); get patternFeatureId() { return InstanceData._noFeatureId; } } /** @internal */ class InstanceBuffersData extends InstanceData { transforms; featureIds; symbology; _noDispose = false; constructor(count, transforms, rtcCenter, symbology, featureIds, disableDisposal = false) { super(count, rtcCenter); this.transforms = transforms; this.featureIds = featureIds; this.symbology = symbology; this._noDispose = disableDisposal; } static create(params, disableDisposal = false) { const { count, featureIds, symbologyOverrides, transforms } = params; (0, core_bentley_1.assert)(count > 0 && Math.floor(count) === count); (0, core_bentley_1.assert)(count === transforms.length / 12); (0, core_bentley_1.assert)(undefined === featureIds || count === featureIds.length / 3); (0, core_bentley_1.assert)(undefined === symbologyOverrides || count * 8 === symbologyOverrides.length); let idBuf; if (undefined !== featureIds && undefined === (idBuf = AttributeBuffers_1.BufferHandle.createArrayBuffer(featureIds))) return undefined; let symBuf; if (undefined !== symbologyOverrides && undefined === (symBuf = AttributeBuffers_1.BufferHandle.createArrayBuffer(symbologyOverrides))) return undefined; const tfBuf = AttributeBuffers_1.BufferHandle.createArrayBuffer(transforms); const transformCenter = params.transformCenter instanceof core_geometry_1.Point3d ? params.transformCenter : core_geometry_1.Point3d.fromJSON(params.transformCenter); if (!tfBuf) { return undefined; } return new InstanceBuffersData(count, tfBuf, transformCenter, symBuf, idBuf, disableDisposal); } [Symbol.dispose]() { if (!this._noDispose) { (0, core_bentley_1.dispose)(this.transforms); (0, core_bentley_1.dispose)(this.featureIds); (0, core_bentley_1.dispose)(this.symbology); } } get isDisposed() { return this.transforms.isDisposed && (!this.featureIds || this.featureIds.isDisposed) && (!this.symbology || this.symbology.isDisposed); } } exports.InstanceBuffersData = InstanceBuffersData; /** @internal */ var RenderInstancesImpl; (function (RenderInstancesImpl) { function create(params) { const buffers = InstanceBuffersData.create(params.instances, true); if (!buffers) { return undefined; } let featureTable; if (params.features) { // ###TODO permit user to specify batch type and other batch options... featureTable = new core_common_1.PackedFeatureTable(params.features.data, params.features.modelId, params.features.count, core_common_1.BatchType.Primary); } return { [Symbols_1._implementationProhibited]: "renderInstances", buffers, [Symbols_1._transforms]: params.instances.transforms, [Symbols_1._transformCenter]: params.instances.transformCenter, [Symbols_1._featureTable]: featureTable, }; } RenderInstancesImpl.create = create; })(RenderInstancesImpl || (exports.RenderInstancesImpl = RenderInstancesImpl = {})); /** @internal */ class InstanceBuffers { static _patternParams = new Float32Array([0, 0, 0, 0]); _data; patternParams = InstanceBuffers._patternParams; patternTransforms = undefined; viewIndependentOrigin = undefined; range; get numInstances() { return this._data.numInstances; } get transforms() { return this._data.transforms; } get featureIds() { return this._data.featureIds; } get symbology() { return this._data.symbology; } get hasFeatures() { return undefined !== this.featureIds; } get patternFeatureId() { return this._data.patternFeatureId; } getRtcModelTransform(modelMatrix) { return this._data.getRtcModelTransform(modelMatrix); } getRtcOnlyTransform() { return this._data.getRtcOnlyTransform(); } constructor(data, range) { this._data = data; this.range = range; } static createTransformBufferParameters(techniqueId) { const params = []; const numRows = 3; let row = 0; while (row < numRows) { // 3 rows per instance; 4 floats per row; 4 bytes per float. const floatsPerRow = 4; const bytesPerVertex = floatsPerRow * 4; const offset = row * bytesPerVertex; const stride = 3 * bytesPerVertex; const name = `a_instanceMatrixRow${row}`; const details = AttributeMap_1.AttributeMap.findAttribute(name, techniqueId, true); (0, core_bentley_1.assert)(details !== undefined); const bParams = { glAttribLoc: details.location, glSize: floatsPerRow, glType: GL_1.GL.DataType.Float, glNormalized: false, glStride: stride, glOffset: offset, glInstanced: true, }; params.push(bParams); row++; } return params; } static fromParams(params, computeReprRange) { const data = InstanceBuffersData.create(params); if (!data) { return undefined; } const range = params.range ?? this.computeRange(computeReprRange(), params.transforms, params.transformCenter); return new InstanceBuffers(data, range); } static fromRenderInstances(arg, reprRange) { const instances = arg; const range = this.computeRange(reprRange, instances[Symbols_1._transforms], instances[Symbols_1._transformCenter]); return new InstanceBuffers(instances.buffers, range); } [Symbol.dispose]() { (0, core_bentley_1.dispose)(this._data); } get isDisposed() { return this._data.isDisposed; } collectStatistics(stats) { const featureBytes = undefined !== this.featureIds ? this.featureIds.bytesUsed : 0; const symBytes = undefined !== this.symbology ? this.symbology.bytesUsed : 0; const bytesUsed = this.transforms.bytesUsed + symBytes + featureBytes; stats.addInstances(bytesUsed); } static extendTransformedRange(tfs, i, range, x, y, z) { range.extendXYZ(tfs[i + 3] + tfs[i + 0] * x + tfs[i + 1] * y + tfs[i + 2] * z, tfs[i + 7] + tfs[i + 4] * x + tfs[i + 5] * y + tfs[i + 6] * z, tfs[i + 11] + tfs[i + 8] * x + tfs[i + 9] * y + tfs[i + 10] * z); } static computeRange(reprRange, tfs, rtcCenter, out) { const range = out ?? new core_geometry_1.Range3d(); const numFloatsPerTransform = 3 * 4; (0, core_bentley_1.assert)(0 === tfs.length % (3 * 4)); for (let i = 0; i < tfs.length; i += numFloatsPerTransform) { this.extendTransformedRange(tfs, i, range, reprRange.low.x, reprRange.low.y, reprRange.low.z); this.extendTransformedRange(tfs, i, range, reprRange.low.x, reprRange.low.y, reprRange.high.z); this.extendTransformedRange(tfs, i, range, reprRange.low.x, reprRange.high.y, reprRange.low.z); this.extendTransformedRange(tfs, i, range, reprRange.low.x, reprRange.high.y, reprRange.high.z); this.extendTransformedRange(tfs, i, range, reprRange.high.x, reprRange.low.y, reprRange.low.z); this.extendTransformedRange(tfs, i, range, reprRange.high.x, reprRange.low.y, reprRange.high.z); this.extendTransformedRange(tfs, i, range, reprRange.high.x, reprRange.high.y, reprRange.low.z); this.extendTransformedRange(tfs, i, range, reprRange.high.x, reprRange.high.y, reprRange.high.z); } range.low.addInPlace(rtcCenter); range.high.addInPlace(rtcCenter); return range.clone(out); } } exports.InstanceBuffers = InstanceBuffers; /** @internal */ class PatternBuffers extends InstanceData { range; patternParams; origin; orgTransform; localToModel; symbolToLocal; offsets; viewIndependentOrigin; _featureId; [Symbols_1._implementationProhibited] = "renderAreaPattern"; constructor(count, rtcCenter, range, patternParams, // [ isAreaPattern, spacingX, spacingY, scale ] origin, // [ x, y ] orgTransform, localToModel, symbolToLocal, offsets, featureId, viewIndependentOrigin) { super(count, rtcCenter); this.range = range; this.patternParams = patternParams; this.origin = origin; this.orgTransform = orgTransform; this.localToModel = localToModel; this.symbolToLocal = symbolToLocal; this.offsets = offsets; this.viewIndependentOrigin = viewIndependentOrigin; this.patternTransforms = this; if (undefined !== featureId) { this._featureId = new Float32Array([ (featureId & 0x0000ff) >>> 0, (featureId & 0x00ff00) >>> 8, (featureId & 0xff0000) >>> 16, ]); } } static create(params) { const count = params.xyOffsets.byteLength / 2; (0, core_bentley_1.assert)(Math.floor(count) === count); const offsets = AttributeBuffers_1.BufferHandle.createArrayBuffer(params.xyOffsets); if (!offsets) return undefined; return new PatternBuffers(count, new core_geometry_1.Point3d(), params.range, new Float32Array([1, params.spacing.x, params.spacing.y, params.scale]), new Float32Array([params.origin.x, params.origin.y]), Matrix_1.Matrix4.fromTransform(params.orgTransform), Matrix_1.Matrix4.fromTransform(params.patternToModel), Matrix_1.Matrix4.fromTransform(core_geometry_1.Transform.createTranslation(params.symbolTranslation)), offsets, params.featureId, params.viewIndependentOrigin); } patternTransforms; get hasFeatures() { return undefined !== this._featureId; } get patternFeatureId() { return this._featureId ?? super.patternFeatureId; } get isDisposed() { return this.offsets.isDisposed; } [Symbol.dispose]() { (0, core_bentley_1.dispose)(this.offsets); } collectStatistics(stats) { stats.addInstances(this.offsets.bytesUsed); } } exports.PatternBuffers = PatternBuffers; /** @internal */ class InstancedGeometry extends CachedGeometry_1.CachedGeometry { _buffersContainer; _buffers; _repr; _ownsBuffers; getRtcModelTransform(modelMatrix) { return this._buffers.getRtcModelTransform(modelMatrix); } getRtcOnlyTransform() { return this._buffers.getRtcOnlyTransform(); } get viewIndependentOrigin() { return this._buffers.viewIndependentOrigin; } get asInstanced() { return this; } get asLUT() { return this._repr.asLUT; } get asMesh() { return this._repr.asMesh; } get asSurface() { return this._repr.asSurface; } get asEdge() { return this._repr.asEdge; } get asSilhouette() { return this._repr.asSilhouette; } get asIndexedEdge() { return this._repr.asIndexedEdge; } get renderOrder() { return this._repr.renderOrder; } get isLitSurface() { return this._repr.isLitSurface; } get hasBakedLighting() { return this._repr.hasBakedLighting; } get hasAnimation() { return this._repr.hasAnimation; } get usesQuantizedPositions() { return this._repr.usesQuantizedPositions; } get qOrigin() { return this._repr.qOrigin; } get qScale() { return this._repr.qScale; } get materialInfo() { return this._repr.materialInfo; } get polylineBuffers() { return this._repr.polylineBuffers; } get isEdge() { return this._repr.isEdge; } get hasFeatures() { return this._buffers.hasFeatures; } get techniqueId() { return this._repr.techniqueId; } get supportsThematicDisplay() { return this._repr.supportsThematicDisplay; } getPass(target) { return this._repr.getPass(target); } wantWoWReversal(params) { return this._repr.wantWoWReversal(params); } getLineCode(params) { return this._repr.getLineCode(params); } getLineWeight(params) { return this._repr.getLineWeight(params); } wantMonochrome(target) { return this._repr.wantMonochrome(target); } wantMixMonochromeColor(target) { return this._repr.wantMixMonochromeColor(target); } static create(repr, ownsBuffers, buffers) { const techId = repr.techniqueId; const container = AttributeBuffers_1.BuffersContainer.create(); container.appendLinkages(repr.lutBuffers.linkages); container.addBuffer(buffers.transforms, InstanceBuffers.createTransformBufferParameters(repr.techniqueId)); if (buffers.symbology) { const attrInstanceOverrides = AttributeMap_1.AttributeMap.findAttribute("a_instanceOverrides", techId, true); const attrInstanceRgba = AttributeMap_1.AttributeMap.findAttribute("a_instanceRgba", techId, true); (0, core_bentley_1.assert)(attrInstanceOverrides !== undefined); (0, core_bentley_1.assert)(attrInstanceRgba !== undefined); container.addBuffer(buffers.symbology, [ AttributeBuffers_1.BufferParameters.create(attrInstanceOverrides.location, 4, GL_1.GL.DataType.UnsignedByte, false, 8, 0, true), AttributeBuffers_1.BufferParameters.create(attrInstanceRgba.location, 4, GL_1.GL.DataType.UnsignedByte, false, 8, 4, true), ]); } if (buffers.featureIds) { const attrFeatureId = AttributeMap_1.AttributeMap.findAttribute("a_featureId", techId, true); (0, core_bentley_1.assert)(attrFeatureId !== undefined); container.addBuffer(buffers.featureIds, [AttributeBuffers_1.BufferParameters.create(attrFeatureId.location, 3, GL_1.GL.DataType.UnsignedByte, false, 0, 0, true)]); } return new this(repr, ownsBuffers, buffers, container); } static createPattern(repr, ownsBuffers, buffers) { const techId = repr.techniqueId; const container = AttributeBuffers_1.BuffersContainer.create(); container.appendLinkages(repr.lutBuffers.linkages); const attrX = AttributeMap_1.AttributeMap.findAttribute("a_patternX", techId, true); const attrY = AttributeMap_1.AttributeMap.findAttribute("a_patternY", techId, true); (0, core_bentley_1.assert)(undefined !== attrX && undefined !== attrY); container.addBuffer(buffers.offsets, [ AttributeBuffers_1.BufferParameters.create(attrX.location, 1, GL_1.GL.DataType.Float, false, 8, 0, true), AttributeBuffers_1.BufferParameters.create(attrY.location, 1, GL_1.GL.DataType.Float, false, 8, 4, true), ]); return new this(repr, ownsBuffers, buffers, container); } constructor(repr, ownsBuffers, buffers, container) { super(); this._repr = repr; this._ownsBuffers = ownsBuffers; this._buffers = buffers; this._buffersContainer = container; } get isDisposed() { if (!this._repr.isDisposed) return false; return !this._ownsBuffers || this._buffers.isDisposed; } [Symbol.dispose]() { this._repr[Symbol.dispose](); if (this._ownsBuffers) (0, core_bentley_1.dispose)(this._buffers); } _wantWoWReversal(_target) { (0, core_bentley_1.assert)(false, "Should never be called"); return false; } draw() { this._repr.drawInstanced(this._buffers.numInstances, this._buffersContainer); } computeRange(output) { return this._buffers.range.clone(output); } collectStatistics(stats) { this._repr.collectStatistics(stats); if (this._ownsBuffers) this._buffers.collectStatistics(stats); } get patternParams() { return this._buffers.patternParams; } get patternTransforms() { return this._buffers.patternTransforms; } get patternFeatureId() { return this._buffers.patternFeatureId; } } exports.InstancedGeometry = InstancedGeometry; //# sourceMappingURL=InstancedGeometry.js.map