@itwin/core-frontend
Version:
iTwin.js frontend components
236 lines • 10.9 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 Rendering
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.GraphicDescriptionBuilderImpl = void 0;
exports.isGraphicDescription = isGraphicDescription;
exports.collectGraphicDescriptionTransferables = collectGraphicDescriptionTransferables;
const core_geometry_1 = require("@itwin/core-geometry");
const ImdlModel_1 = require("../../imdl/ImdlModel");
const GraphicType_1 = require("../../render/GraphicType");
const GraphicAssembler_1 = require("../../render/GraphicAssembler");
const core_common_1 = require("@itwin/core-common");
const core_bentley_1 = require("@itwin/core-bentley");
const PointStringParams_1 = require("./PointStringParams");
const PolylineParams_1 = require("./PolylineParams");
const VertexTableBuilder_1 = require("./VertexTableBuilder");
const ParseImdlDocument_1 = require("../../imdl/ParseImdlDocument");
const Symbols_1 = require("../Symbols");
const GraphicDescriptionContextImpl_1 = require("./GraphicDescriptionContextImpl");
class GraphicDescriptionBuilderImpl extends GraphicAssembler_1.GraphicAssembler {
[Symbols_1._implementationProhibited] = undefined;
_computeChordTolerance;
_context;
_viewIndependentOrigin;
constructor(options) {
const type = options.type;
const placement = options.placement ?? core_geometry_1.Transform.createIdentity();
const wantEdges = options.generateEdges ?? type === GraphicType_1.GraphicType.Scene;
const wantNormals = wantEdges || type === GraphicType_1.GraphicType.Scene;
const preserveOrder = type === GraphicType_1.GraphicType.ViewOverlay || type === GraphicType_1.GraphicType.WorldOverlay || type === GraphicType_1.GraphicType.ViewBackground;
super({
...options,
[Symbols_1._implementationProhibited]: undefined,
type,
placement,
wantEdges,
wantNormals,
preserveOrder,
});
this._computeChordTolerance = options.computeChordTolerance;
this._viewIndependentOrigin = options.viewIndependentOrigin?.clone();
this._context = options.context;
if (!(this._context.transientIds instanceof core_bentley_1.TransientIdSequence)) {
throw new Error("Invalid WorkerGraphicDescriptionContext");
}
}
finish() {
const description = {
[Symbols_1._implementationProhibited]: undefined,
type: this.type,
primitives: [],
};
if (this[Symbols_1._accumulator].isEmpty) {
return description;
}
const tolerance = this._computeChordTolerance({ builder: this, computeRange: () => this[Symbols_1._accumulator].geometries.computeRange() });
const meshes = this[Symbols_1._accumulator].toMeshes(this, tolerance, this.pickable);
if (meshes.length === 0) {
return description;
}
// If the meshes contain quantized positions, they are all quantized to the same range. If that range is small relative to the distance
// from the origin, quantization errors can produce display artifacts. Remove the translation from the quantization parameters and apply
// it in the transform instead.
// If the positions are not quantized, they have already been transformed to be relative to the center of the meshes' range.
// Apply the inverse translation to put them back into model space.
let transformOrigin;
let meshesRangeOffset = false;
for (const mesh of meshes) {
const verts = mesh.points;
if (!transformOrigin) {
// This is the first mesh we've processed.
if (verts instanceof core_common_1.QPoint3dList) {
transformOrigin = verts.params.origin.clone();
verts.params.origin.setZero();
}
else {
// In this case we need to modify the qOrigin of the graphic that will get created later since we have translated the origin.
// We can't modify it directly, but if we temporarily modify the range of the mesh used to create it the qOrigin will get created properly.
// Range is shared (not cloned) by all meshes and the mesh list itself, so modifying the range of the meshlist will modify it for all meshes.
// This will become the range in local coordinates of the batch, if we are creating a batch.
transformOrigin = verts.range.center;
if (!meshesRangeOffset) {
meshes.range?.low.subtractInPlace(transformOrigin);
meshes.range?.high.subtractInPlace(transformOrigin);
meshesRangeOffset = true;
}
}
}
else {
if (verts instanceof core_common_1.QPoint3dList) {
(0, core_bentley_1.assert)(transformOrigin.isAlmostEqual(verts.params.origin));
verts.params.origin.setZero();
}
else {
(0, core_bentley_1.assert)(verts.range.center.isAlmostZero);
}
}
const primitive = this.createPrimitive(mesh);
if (primitive) {
const origin = this._viewIndependentOrigin;
if (origin) {
primitive.modifier = {
type: "viewIndependentOrigin",
origin: { x: origin.x, y: origin.y, z: origin.z },
};
}
description.primitives.push(primitive);
}
}
this[Symbols_1._accumulator].clear();
if (transformOrigin) {
description.translation = { x: transformOrigin.x, y: transformOrigin.y, z: transformOrigin.z };
}
const featureTable = this.pickable && meshes.features?.anyDefined ? meshes.features : undefined;
if (featureTable) {
(0, core_bentley_1.assert)(undefined !== this.pickable);
const features = core_common_1.PackedFeatureTable.pack(featureTable);
const range = meshes.range ?? new core_geometry_1.Range3d();
description.batch = {
...this.pickable,
range: range.toJSON(),
modelId: this.pickable.modelId ?? this.pickable.id,
featureTable: {
multiModel: false,
data: features.data,
numFeatures: features.numFeatures,
animationNodeIds: features.animationNodeIds,
},
};
}
return description;
}
createPrimitive(mesh) {
const meshArgs = mesh.toMeshArgs();
if (meshArgs) {
return this.createMeshPrimitive(meshArgs);
}
const polylineArgs = mesh.toPolylineArgs();
if (!polylineArgs) {
return undefined;
}
return polylineArgs.flags.isDisjoint ? this.createPointStringPrimitive(polylineArgs) : this.createPolylinePrimitive(polylineArgs);
}
createMeshPrimitive(args) {
const params = (0, VertexTableBuilder_1.createMeshParams)(args, this._context.constraints.maxTextureSize, true);
let material;
const mat = params.surface.material;
if (mat) {
(0, core_bentley_1.assert)(mat.isAtlas === false && mat.material instanceof GraphicDescriptionContextImpl_1.WorkerMaterial);
material = mat.material.toImdl();
}
let textureMapping;
const tex = params.surface.textureMapping;
if (tex) {
(0, core_bentley_1.assert)(tex.texture instanceof GraphicDescriptionContextImpl_1.WorkerTexture);
textureMapping = { alwaysDisplayed: false, texture: tex.texture.index.toString(10) };
}
return {
type: "mesh",
params: {
...params,
vertices: convertVertexTable(params.vertices),
auxChannels: params.auxChannels?.toJSON(),
edges: params.edges ? (0, ParseImdlDocument_1.edgeParamsToImdl)(params.edges) : undefined,
surface: {
...params.surface,
indices: params.surface.indices.data,
material,
textureMapping,
},
},
};
}
createPolylinePrimitive(args) {
const params = (0, PolylineParams_1.createPolylineParams)(args, this._context.constraints.maxTextureSize);
if (!params) {
return undefined;
}
return {
type: "polyline",
params: {
...params,
vertices: convertVertexTable(params.vertices),
polyline: {
indices: params.polyline.indices.data,
prevIndices: params.polyline.prevIndices.data,
nextIndicesAndParams: params.polyline.nextIndicesAndParams,
},
},
};
}
createPointStringPrimitive(args) {
const params = (0, PointStringParams_1.createPointStringParams)(args, this._context.constraints.maxTextureSize);
if (!params) {
return undefined;
}
return {
type: "point",
params: {
indices: params.indices.data,
vertices: convertVertexTable(params.vertices),
weight: params.weight,
},
};
}
resolveGradient(gradient) {
return this._context.createGradientTexture(gradient);
}
}
exports.GraphicDescriptionBuilderImpl = GraphicDescriptionBuilderImpl;
function convertVertexTable(src) {
return {
...src,
qparams: src.qparams.toJSON(),
uvParams: src.uvParams?.toJSON(),
uniformColor: src.uniformColor?.toJSON(),
};
}
function isGraphicDescription(description) {
const descr = description;
return "object" === typeof descr && Array.isArray(descr.primitives) && "number" === typeof descr.type;
}
function collectGraphicDescriptionTransferables(xfers, description) {
if (!isGraphicDescription(description)) {
throw new Error("Invalid GraphicDescription");
}
for (const primitive of description.primitives) {
(0, ImdlModel_1.addPrimitiveTransferables)(xfers, primitive);
}
}
//# sourceMappingURL=GraphicDescriptionBuilderImpl.js.map