@itwin/core-frontend
Version:
iTwin.js frontend components
381 lines • 18.5 kB
JavaScript
"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