UNPKG

@itwin/core-frontend

Version:
464 lines • 19.9 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 Rendering */ Object.defineProperty(exports, "__esModule", { value: true }); exports.VertexTableBuilder = void 0; exports.createMeshParams = createMeshParams; const core_bentley_1 = require("@itwin/core-bentley"); const core_geometry_1 = require("@itwin/core-geometry"); const core_common_1 = require("@itwin/core-common"); const AuxChannelTable_1 = require("./AuxChannelTable"); const VertexTable_1 = require("./VertexTable"); const SurfaceParams_1 = require("./SurfaceParams"); const VertexIndices_1 = require("./VertexIndices"); const EdgeParams_1 = require("./EdgeParams"); /** @internal */ function createMeshParams(args, maxDimension, enableIndexedEdges) { const builder = createMeshBuilder(args); const vertices = builder.build(args.colors, args.features, maxDimension); const surfaceIndices = VertexIndices_1.VertexIndices.fromArray(args.vertIndices); const surface = { type: builder.type, indices: surfaceIndices, fillFlags: args.fillFlags ?? core_common_1.FillFlags.ByView, hasBakedLighting: true === args.hasBakedLighting, textureMapping: undefined !== args.textureMapping ? { texture: args.textureMapping.texture, alwaysDisplayed: false } : undefined, material: (0, SurfaceParams_1.createSurfaceMaterial)(args.material), }; const channels = undefined !== args.auxChannels ? AuxChannelTable_1.AuxChannelTable.fromChannels(args.auxChannels, vertices.numVertices, maxDimension) : undefined; const edges = (0, EdgeParams_1.createEdgeParams)({ meshArgs: args, maxWidth: maxDimension, createIndexed: enableIndexedEdges }); return { vertices, surface, edges, isPlanar: !!args.isPlanar, auxChannels: channels, }; } /** Builds a VertexTable from some data type supplying the vertex data. * @internal */ class VertexTableBuilder { data; _curIndex = 0; get uvParams() { return undefined; } appendColorTable(colorIndex) { if (undefined !== colorIndex.nonUniform) { for (const color of colorIndex.nonUniform.colors) { this.appendColor(color); } } } advance(nBytes) { this._curIndex += nBytes; (0, core_bentley_1.assert)(undefined !== this.data); (0, core_bentley_1.assert)(this._curIndex <= this.data.length); } append8(val) { (0, core_bentley_1.assert)(0 <= val); (0, core_bentley_1.assert)(val <= 0xff); (0, core_bentley_1.assert)(val === Math.floor(val)); (0, core_bentley_1.expectDefined)(this.data)[this._curIndex] = val; this.advance(1); } append16(val) { this.append8(val & 0x00ff); this.append8(val >>> 8); } append32(val) { this.append16(val & 0x0000ffff); this.append16(val >>> 16); } appendColor(tbgr) { const colors = core_common_1.ColorDef.getColors(tbgr); // invert transparency => alpha colors.t = 255 - colors.t; // premultiply alpha... switch (colors.t) { case 0: colors.r = colors.g = colors.b = 0; break; case 255: break; default: { const f = colors.t / 255.0; colors.r = Math.floor(colors.r * f + 0.5); colors.g = Math.floor(colors.g * f + 0.5); colors.b = Math.floor(colors.b * f + 0.5); break; } } // Store 32-bit value in little-endian order (red first) this.append8(colors.r); this.append8(colors.g); this.append8(colors.b); this.append8(colors.t); } build(colorIndex, featureIndex, maxDimension) { const { numVertices, numRgbaPerVertex } = this; const numColors = colorIndex.isUniform ? 0 : colorIndex.numColors; const dimensions = (0, VertexTable_1.computeDimensions)(numVertices, numRgbaPerVertex, numColors, maxDimension); (0, core_bentley_1.assert)(0 === dimensions.width % numRgbaPerVertex || (0 < numColors && 1 === dimensions.height)); const data = new Uint8Array(dimensions.width * dimensions.height * 4); this.data = data; for (let i = 0; i < numVertices; i++) this.appendVertex(i); this.appendColorTable(colorIndex); this.data = undefined; return { data, qparams: this.qparams, usesUnquantizedPositions: this.usesUnquantizedPositions, width: dimensions.width, height: dimensions.height, hasTranslucency: colorIndex.hasAlpha, uniformColor: colorIndex.uniform, numVertices, numRgbaPerVertex, uvParams: this.uvParams, featureIndexType: featureIndex.type, uniformFeatureID: featureIndex.type === core_common_1.FeatureIndexType.Uniform ? featureIndex.featureID : undefined, }; } static buildFromPolylines(args, maxDimension) { const polylines = args.polylines; if (polylines.length === 0) return undefined; const builder = createPolylineBuilder(args); return builder.build(args.colors, args.features, maxDimension); } } exports.VertexTableBuilder = VertexTableBuilder; var Quantized; (function (Quantized) { /** * Supplies vertex data from a PolylineArgs or MeshArgs. Each vertex consists of 12 bytes: * pos.x 00 * pos.y 02 * pos.z 04 * colorIndex 06 * featureIndex 08 (24 bits) * materialIndex 0B (for meshes that use a material atlas; otherwise unused). NOTE: Currently front-end code does not produce material atlases. */ class SimpleBuilder extends VertexTableBuilder { args; _qpoints; constructor(args) { super(); this._qpoints = args.points; this.args = args; (0, core_bentley_1.assert)(undefined !== this.args.points); } get numVertices() { return this.args.points.length; } get numRgbaPerVertex() { return 3; } get usesUnquantizedPositions() { return false; } get qparams() { return this._qpoints.params; } appendVertex(vertIndex) { this.appendPosition(vertIndex); this.appendColorIndex(vertIndex); this.appendFeatureIndex(vertIndex); } appendPosition(vertIndex) { this.append16(this._qpoints.list[vertIndex].x); this.append16(this._qpoints.list[vertIndex].y); this.append16(this._qpoints.list[vertIndex].z); } appendColorIndex(vertIndex) { if (undefined !== this.args.colors.nonUniform) { this.append16(this.args.colors.nonUniform.indices[vertIndex]); } else { this.advance(2); } } appendFeatureIndex(vertIndex) { if (undefined !== this.args.features.featureIDs) { this.append32(this.args.features.featureIDs[vertIndex]); } else { this.advance(4); } } } Quantized.SimpleBuilder = SimpleBuilder; /** Supplies vertex data from a MeshArgs. */ class MeshBuilder extends SimpleBuilder { type; constructor(args, type) { super(args); this.type = type; } static create(args) { if (args.isVolumeClassifier) return new MeshBuilder(args, SurfaceParams_1.SurfaceType.VolumeClassifier); const isLit = undefined !== args.normals && 0 < args.normals.length; const isTextured = undefined !== args.textureMapping; let uvParams; if (args.textureMapping) { const uvRange = core_geometry_1.Range2d.createNull(); const fpts = args.textureMapping.uvParams; const pt2d = new core_geometry_1.Point2d(); if (undefined !== fpts && fpts.length > 0) for (let i = 0; i < args.points.length; i++) uvRange.extendPoint(core_geometry_1.Point2d.create(fpts[i].x, fpts[i].y, pt2d)); uvParams = core_common_1.QParams2d.fromRange(uvRange); } if (isLit) // If isTextured is true, uvParams will always be defined. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return isTextured ? new TexturedLitMeshBuilder(args, uvParams) : new LitMeshBuilder(args); else // If isTextured is true, uvParams will always be defined. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return isTextured ? new TexturedMeshBuilder(args, uvParams) : new MeshBuilder(args, SurfaceParams_1.SurfaceType.Unlit); } } Quantized.MeshBuilder = MeshBuilder; /** Supplies vertex data from a MeshArgs where each vertex consists of 16 bytes. * In addition to the SimpleBuilder data, the final 4 bytes hold the quantized UV params * The color index is left uninitialized as it is unused. */ class TexturedMeshBuilder extends MeshBuilder { _qparams; _qpoint = new core_common_1.QPoint2d(); constructor(args, qparams, type = SurfaceParams_1.SurfaceType.Textured) { super(args, type); this._qparams = qparams; (0, core_bentley_1.assert)(undefined !== args.textureMapping); } get numRgbaPerVertex() { return 4; } get uvParams() { return this._qparams; } appendVertex(vertIndex) { this.appendPosition(vertIndex); this.appendNormal(vertIndex); this.appendFeatureIndex(vertIndex); this.appendUVParams(vertIndex); } appendNormal(_vertIndex) { this.advance(2); } // no normal for unlit meshes appendUVParams(vertIndex) { this._qpoint.init((0, core_bentley_1.expectDefined)(this.args.textureMapping).uvParams[vertIndex], this._qparams); this.append16(this._qpoint.x); this.append16(this._qpoint.y); } } /** As with TexturedMeshBuilder, but the color index is replaced with the oct-encoded normal value. */ class TexturedLitMeshBuilder extends TexturedMeshBuilder { constructor(args, qparams) { super(args, qparams, SurfaceParams_1.SurfaceType.TexturedLit); (0, core_bentley_1.assert)(undefined !== args.normals); } appendNormal(vertIndex) { this.append16((0, core_bentley_1.expectDefined)(this.args.normals)[vertIndex].value); } } /** 16 bytes. The last 2 bytes are unused; the 2 immediately preceding it hold the oct-encoded normal value. */ class LitMeshBuilder extends MeshBuilder { constructor(args) { super(args, SurfaceParams_1.SurfaceType.Lit); (0, core_bentley_1.assert)(undefined !== args.normals); } get numRgbaPerVertex() { return 4; } appendVertex(vertIndex) { super.appendVertex(vertIndex); this.append16((0, core_bentley_1.expectDefined)(this.args.normals)[vertIndex].value); this.advance(2); // 2 unused bytes } } })(Quantized || (Quantized = {})); /** Builders in this namespace store vertex positions as 32-bit floats instead of quantizing to 16-bit unsigned integers. * This is preferred for decoration graphics, which might contain ranges of positions that exceed the limits for quantization; if quantized, * they could produce visual artifacts. * Each builder produces a VertexTable that starts with the following layout: * pos.x: 00 * pos.y: 04 * pos.z: 08 * featureIndex: 0C * materialIndex:0F (NOTE: frontend code currently doesn't produce material atlases, so this is always zero). * Followed (by default) by: * colorIndex: 10 * unused: 12 * Subclasses may add 4 more bytes and/or overwrite the final 4 bytes above. */ var Unquantized; (function (Unquantized) { const u32Array = new Uint32Array(1); const f32Array = new Float32Array(u32Array.buffer); // colorIndex: 10 // unused: 12 class SimpleBuilder extends VertexTableBuilder { args; _points; _qparams3d; constructor(args) { super(); (0, core_bentley_1.assert)(!(args.points instanceof core_common_1.QPoint3dList)); this._qparams3d = core_common_1.QParams3d.fromRange(args.points.range); this.args = args; this._points = args.points; } get numVertices() { return this._points.length; } get numRgbaPerVertex() { return 5; } get usesUnquantizedPositions() { return true; } get qparams() { return this._qparams3d; } appendVertex(vertIndex) { this.appendTransposePosAndFeatureNdx(vertIndex); this.appendColorIndex(vertIndex); } appendFloat32(val) { f32Array[0] = val; this.append32(u32Array[0]); } convertFloat32(val) { f32Array[0] = val; return u32Array[0]; } appendTransposePosAndFeatureNdx(vertIndex) { // transpose position xyz vals into [0].xyz - [3].xyz, and add feature index at .w // this is to order things to let shader code access much more efficiently const pt = this._points[vertIndex]; const x = this.convertFloat32(pt.x); const y = this.convertFloat32(pt.y); const z = this.convertFloat32(pt.z); const featID = (this.args.features.featureIDs) ? this.args.features.featureIDs[vertIndex] : 0; this.append8(x & 0x000000ff); this.append8(y & 0x000000ff); this.append8(z & 0x000000ff); this.append8(featID & 0x000000ff); this.append8((x >>> 8) & 0x000000ff); this.append8((y >>> 8) & 0x000000ff); this.append8((z >>> 8) & 0x000000ff); this.append8((featID >>> 8) & 0x000000ff); this.append8((x >>> 16) & 0x000000ff); this.append8((y >>> 16) & 0x000000ff); this.append8((z >>> 16) & 0x000000ff); this.append8((featID >>> 16) & 0x000000ff); this.append8(x >>> 24); this.append8(y >>> 24); this.append8(z >>> 24); this.append8(featID >>> 24); } appendPosition(vertIndex) { const pt = this._points[vertIndex]; this.appendFloat32(pt.x); this.appendFloat32(pt.y); this.appendFloat32(pt.z); } appendFeatureIndex(vertIndex) { if (this.args.features.featureIDs) this.append32(this.args.features.featureIDs[vertIndex]); else this.advance(4); } _appendColorIndex(vertIndex) { if (undefined !== this.args.colors.nonUniform) this.append16(this.args.colors.nonUniform.indices[vertIndex]); else this.advance(2); } appendColorIndex(vertIndex) { this._appendColorIndex(vertIndex); this.advance(2); } } Unquantized.SimpleBuilder = SimpleBuilder; class MeshBuilder extends SimpleBuilder { type; constructor(args, type) { super(args); this.type = type; } static create(args) { if (args.isVolumeClassifier) return new MeshBuilder(args, SurfaceParams_1.SurfaceType.VolumeClassifier); const isLit = undefined !== args.normals && 0 < args.normals.length; const isTextured = undefined !== args.textureMapping; let uvParams; if (args.textureMapping) { const uvRange = core_geometry_1.Range2d.createNull(); const fpts = args.textureMapping.uvParams; const pt2d = new core_geometry_1.Point2d(); if (undefined !== fpts && fpts.length > 0) for (let i = 0; i < args.points.length; i++) uvRange.extendPoint(core_geometry_1.Point2d.create(fpts[i].x, fpts[i].y, pt2d)); uvParams = core_common_1.QParams2d.fromRange(uvRange); } if (isLit) // If isTextured is true, uvParams will always be defined. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return isTextured ? new TexturedLitMeshBuilder(args, uvParams) : new LitMeshBuilder(args); else // If isTextured is true, uvParams will always be defined. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return isTextured ? new TexturedMeshBuilder(args, uvParams) : new MeshBuilder(args, SurfaceParams_1.SurfaceType.Unlit); } } Unquantized.MeshBuilder = MeshBuilder; // u: 10 // v: 12 class TexturedMeshBuilder extends MeshBuilder { _qparams; _qpoint = new core_common_1.QPoint2d(); constructor(args, qparams, type = SurfaceParams_1.SurfaceType.Textured) { super(args, type); this._qparams = qparams; (0, core_bentley_1.assert)(undefined !== args.textureMapping); } get uvParams() { return this._qparams; } appendVertex(vertIndex) { super.appendVertex(vertIndex); this._qpoint.init((0, core_bentley_1.expectDefined)(this.args.textureMapping).uvParams[vertIndex], this._qparams); this.append16(this._qpoint.x); this.append16(this._qpoint.y); } appendColorIndex() { } } // u: 10 // v: 12 // normal: 14 // unused: 16 class TexturedLitMeshBuilder extends TexturedMeshBuilder { constructor(args, qparams) { super(args, qparams, SurfaceParams_1.SurfaceType.TexturedLit); (0, core_bentley_1.assert)(undefined !== args.normals); } get numRgbaPerVertex() { return 6; } appendVertex(vertIndex) { super.appendVertex(vertIndex); this.append16((0, core_bentley_1.expectDefined)(this.args.normals)[vertIndex].value); this.advance(2); } } // color: 10 // normal: 12 class LitMeshBuilder extends MeshBuilder { constructor(args) { super(args, SurfaceParams_1.SurfaceType.Lit); (0, core_bentley_1.assert)(undefined !== args.normals); } appendColorIndex(vertIndex) { super._appendColorIndex(vertIndex); } appendVertex(vertIndex) { super.appendVertex(vertIndex); this.append16((0, core_bentley_1.expectDefined)(this.args.normals)[vertIndex].value); } } })(Unquantized || (Unquantized = {})); function createMeshBuilder(args) { if (args.points instanceof core_common_1.QPoint3dList) return Quantized.MeshBuilder.create(args); else return Unquantized.MeshBuilder.create(args); } function createPolylineBuilder(args) { if (args.points instanceof core_common_1.QPoint3dList) return new Quantized.SimpleBuilder(args); else return new Unquantized.SimpleBuilder(args); } //# sourceMappingURL=VertexTableBuilder.js.map